minimodem: use simpleaudio

This commit is contained in:
Kamal Mostafa 2011-05-29 22:22:20 -07:00
parent fe4b47af20
commit 0a47a37a06
1 changed files with 56 additions and 62 deletions

View File

@ -11,14 +11,20 @@
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/gccmacro.h>
#include <fftw3.h> #include <fftw3.h>
#include "simpleaudio.h"
#include "tscope_print.h" #include "tscope_print.h"
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
static inline static inline
float float
band_mag( fftwf_complex * const cplx, unsigned int band, float scalar ) band_mag( fftwf_complex * const cplx, unsigned int band, float scalar )
@ -30,22 +36,11 @@ band_mag( fftwf_complex * const cplx, unsigned int band, float scalar )
} }
int main(int argc, char*argv[]) { int main(int argc, char*argv[]) {
/* The sample type to use */
static const pa_sample_spec ss = {
.format = PA_SAMPLE_FLOAT32,
.rate = 48000, // pulseaudio will resample its configured audio rate
// .channels = 2 // 2 channel stereo
.channels = 1 // pulseaudio will downmix (additively) to 1 channel
// .channels = 3 // 2 channel stereo + 1 mixed channel
};
int ret = 1; int ret = 1;
int error;
if ( argc < 2 ) { if ( argc < 2 ) {
fprintf(stderr, "usage: minimodem baud_rate [ mark_hz space_hz ]\n"); fprintf(stderr, "usage: minimodem [filename] baud_rate [ mark_hz space_hz ]\n");
return 1; return 1;
} }
@ -56,7 +51,27 @@ int main(int argc, char*argv[]) {
argi++; argi++;
} }
unsigned int decode_rate = atoi(argv[argi++]); simpleaudio *sa;
char *p;
for ( p=argv[argi]; *p; p++ )
if ( !isdigit(*p) )
break;
if ( *p ) {
sa = simpleaudio_open_source_sndfile(argv[argi]);
argi++;
} else {
sa = simpleaudio_open_source_pulseaudio(argv[0], "bfsk demodulator");
}
if ( !sa )
return 1;
unsigned int sample_rate = simpleaudio_get_rate(sa);
unsigned int nchannels = simpleaudio_get_channels(sa);
unsigned int decode_rate;
decode_rate = atoi(argv[argi++]);
unsigned int band_width; unsigned int band_width;
band_width = decode_rate; band_width = decode_rate;
@ -85,8 +100,6 @@ int main(int argc, char*argv[]) {
bfsk_space_f = atoi(argv[argi++]); bfsk_space_f = atoi(argv[argi++]);
} }
unsigned int sample_rate = ss.rate;
unsigned int bfsk_mark_band = (bfsk_mark_f +(float)band_width/2) / band_width; unsigned int bfsk_mark_band = (bfsk_mark_f +(float)band_width/2) / band_width;
unsigned int bfsk_space_band = (bfsk_space_f +(float)band_width/2) / band_width; unsigned int bfsk_space_band = (bfsk_space_f +(float)band_width/2) / band_width;
@ -101,20 +114,6 @@ int main(int argc, char*argv[]) {
} }
/* Create the recording stream */
pa_simple *s;
s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error);
if ( !s ) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
return 1;
}
int pa_samplesize = pa_sample_size(&ss);
int pa_framesize = pa_frame_size(&ss);
int pa_nchannels = ss.channels;
assert( pa_framesize == pa_samplesize * pa_nchannels );
/* Create the FFT plan */ /* Create the FFT plan */
fftwf_plan fftplan; fftwf_plan fftplan;
@ -126,9 +125,9 @@ int main(int argc, char*argv[]) {
unsigned int nbands = fftsize / 2 + 1; unsigned int nbands = fftsize / 2 + 1;
float *fftin = fftwf_malloc(fftsize * sizeof(float) * pa_nchannels); float *fftin = fftwf_malloc(fftsize * sizeof(float) * nchannels);
fftwf_complex *fftout = fftwf_malloc(nbands * sizeof(fftwf_complex) * pa_nchannels); fftwf_complex *fftout = fftwf_malloc(nbands * sizeof(fftwf_complex) * nchannels);
/* /*
* works only for 1 channel: * works only for 1 channel:
@ -138,8 +137,8 @@ int main(int argc, char*argv[]) {
* works for N channels: * works for N channels:
*/ */
fftplan = fftwf_plan_many_dft_r2c( fftplan = fftwf_plan_many_dft_r2c(
/*rank*/1, &fftsize, /*howmany*/pa_nchannels, /*rank*/1, &fftsize, /*howmany*/nchannels,
fftin, NULL, /*istride*/pa_nchannels, /*idist*/1, fftin, NULL, /*istride*/nchannels, /*idist*/1,
fftout, NULL, /*ostride*/1, /*odist*/nbands, fftout, NULL, /*ostride*/1, /*odist*/nbands,
FFTW_ESTIMATE | FFTW_PRESERVE_INPUT ); FFTW_ESTIMATE | FFTW_PRESERVE_INPUT );
/* Nb. FFTW_PRESERVE_INPUT is needed for the "shift the input window" trick */ /* Nb. FFTW_PRESERVE_INPUT is needed for the "shift the input window" trick */
@ -150,10 +149,6 @@ int main(int argc, char*argv[]) {
} }
void *pa_samples_in = fftin; // read samples directly into fftin
assert( pa_samplesize == sizeof(float) );
/* /*
* Prepare the input sample chunk rate * Prepare the input sample chunk rate
*/ */
@ -179,8 +174,9 @@ int main(int argc, char*argv[]) {
/* pulseaudio *adds* when downmixing 2 channels to 1; if we're using /* pulseaudio *adds* when downmixing 2 channels to 1; if we're using
* only one channel here, we blindly assume that pulseaudio downmixed * only one channel here, we blindly assume that pulseaudio downmixed
* from 2, and rescale magnitudes accordingly. */ * from 2, and rescale magnitudes accordingly. */
if ( pa_nchannels == 1 ) // but sndfile does not do that.
magscalar /= 2.0; // if ( nchannels == 1 )
// magscalar /= 2.0;
float actual_decode_rate = (float)sample_rate / nsamples; float actual_decode_rate = (float)sample_rate / nsamples;
fprintf(stderr, "### nsamples=%u ", nsamples); fprintf(stderr, "### nsamples=%u ", nsamples);
@ -196,7 +192,7 @@ int main(int argc, char*argv[]) {
// sadly, COLUMNS is not exported by default (?) // sadly, COLUMNS is not exported by default (?)
char *columns_env = getenv("COLUMNS"); char *columns_env = getenv("COLUMNS");
int columns = columns_env ? atoi(columns_env) : 80; int columns = columns_env ? atoi(columns_env) : 80;
int show_nbands = ( (columns - 2 - 10) / pa_nchannels ) - 1 - 10; int show_nbands = ( (columns - 2 - 10) / nchannels ) - 1 - 10;
if ( show_nbands > nbands ) if ( show_nbands > nbands )
show_nbands = nbands; show_nbands = nbands;
@ -215,16 +211,12 @@ int main(int argc, char*argv[]) {
while ( 1 ) { while ( 1 ) {
size_t nframes = nsamples; bzero(fftin, (fftsize * sizeof(float) * nchannels));
size_t nbytes = nframes * pa_framesize;
bzero(fftin, (fftsize * sizeof(float) * pa_nchannels)); size_t nframes = nsamples;
if (pa_simple_read(s, pa_samples_in, nbytes, &error) < 0) { /* read samples directly into fftin */
fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", if ((ret=simpleaudio_read(sa, fftin, nframes)) <= 0)
pa_strerror(error));
ret = 1;
break; break;
}
carrier_nsamples += nframes; carrier_nsamples += nframes;
#define TRICK #define TRICK
@ -299,16 +291,15 @@ reprocess_audio:
skipped_frames += nframes; skipped_frames += nframes;
if ( nframes ) { if ( nframes ) {
size_t nbytes = nframes * pa_framesize; size_t framesize = nchannels * sizeof(float);
size_t reuse_bytes = nsamples*pa_framesize - nbytes; size_t nbytes = nframes * framesize;
memmove(pa_samples_in, pa_samples_in+nbytes, reuse_bytes); size_t reuse_bytes = nsamples*framesize - nbytes;
void *in = pa_samples_in + reuse_bytes; memmove(fftin, fftin+nbytes, reuse_bytes);
if (pa_simple_read(s, in, nbytes, &error) < 0) { void *in = fftin + reuse_bytes;
fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n",
pa_strerror(error)); if ((ret=simpleaudio_read(sa, in, nframes)) <= 0)
ret = 1;
break; break;
}
carrier_nsamples += nframes; carrier_nsamples += nframes;
goto reprocess_audio; goto reprocess_audio;
} }
@ -433,7 +424,10 @@ reprocess_audio:
} }
pa_simple_free(s); if ( ret != 0 )
fprintf(stderr, "simpleaudio_read: error\n");
simpleaudio_close(sa);
fftwf_free(fftin); fftwf_free(fftin);
fftwf_free(fftout); fftwf_free(fftout);