diff --git a/src/fm_mpx.c b/src/fm_mpx.c index 7fa869c..0a67440 100644 --- a/src/fm_mpx.c +++ b/src/fm_mpx.c @@ -19,10 +19,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . + + fm_mpx.c: generates an FM multiplex signal containing RDS plus possibly + monaural or stereo audio. */ #include #include +#include #include #include "rds.h" @@ -34,8 +38,8 @@ #define FIR_HALF_SIZE 30 #define FIR_SIZE (2*FIR_HALF_SIZE-1) -#define LENGTH 114000 -// TODO: remove constant + +size_t length; // coefficients of the low-pass FIR filter float low_pass_fir[FIR_HALF_SIZE]; @@ -52,81 +56,112 @@ int phase_19 = 0; float downsample_factor; -float rds_buffer[LENGTH] = {0}; -float audio_buffer[LENGTH] = {0}; +float *audio_buffer; int audio_index = 0; int audio_len = 0; float audio_pos; -float out = 0; -float alpha = .03; -float fir_buffer[FIR_SIZE] = {0}; +float fir_buffer_mono[FIR_SIZE] = {0}; +float fir_buffer_stereo[FIR_SIZE] = {0}; int fir_index = 0; +int channels; SNDFILE *inf; + + +float *alloc_empty_buffer(size_t length) { + float *p = malloc(length * sizeof(float)); + if(p == NULL) return NULL; + bzero(p, length * sizeof(float)); + + return p; +} -int fm_mpx_open(char *filename) { - // Open the input file - SF_INFO sfinfo; - if(! (inf = sf_open(filename, SFM_READ, &sfinfo))) { - fprintf(stderr, "Error: could not open input file %s.\n", filename) ; - return EXIT_FAILURE; // TODO better error code - } - - int in_samplerate = sfinfo.samplerate; - downsample_factor = 228000. / in_samplerate; - - printf("Input: %d Hz, upsampling factor: %.2f\n", in_samplerate, downsample_factor); - - - // Create the low-pass FIR filter - float cutoff_freq = 15000 * .8; - if(in_samplerate/2 < cutoff_freq) cutoff_freq = in_samplerate/2 * .8; - - - - low_pass_fir[FIR_HALF_SIZE-1] = 2 * cutoff_freq / 228000 /2; - // Here we divide this coefficient by two because it will be counted twice - // when applying the filter +int fm_mpx_open(char *filename, size_t len) { + length = len; - // Only store half of the filter since it is symmetric - for(int i=1; i 1) { + printf("%d channels, generating stereo multiplex.\n", channels); + } else { + printf("1 channel, monophonic operation.\n"); + } + + + // Create the low-pass FIR filter + float cutoff_freq = 15000 * .8; + if(in_samplerate/2 < cutoff_freq) cutoff_freq = in_samplerate/2 * .8; + + + + low_pass_fir[FIR_HALF_SIZE-1] = 2 * cutoff_freq / 228000 /2; + // Here we divide this coefficient by two because it will be counted twice + // when applying the filter + + // Only store half of the filter since it is symmetric + for(int i=1; i= downsample_factor) { audio_pos -= downsample_factor; if(audio_len == 0) { for(int j=0; j<2; j++) { // one retry - audio_len = sf_read_float(inf, audio_buffer, LENGTH); + audio_len = sf_read_float(inf, audio_buffer, length); if (audio_len < 0) { fprintf(stderr, "Error reading audio\n"); - exit(EXIT_FAILURE); + return -1; } if(audio_len == 0) { sf_seek(inf, 0, SEEK_SET); @@ -136,49 +171,72 @@ int fm_mpx_get_samples(float *mpx_buffer) { // TODO accept length in argument } audio_index = 0; } else { - audio_index++; - audio_len--; + audio_index += channels; + audio_len -= channels; } } - // Apply FIR low-pass filter - fir_buffer[fir_index] = audio_buffer[audio_index]; + + // First store the current sample(s) into the FIR filter's ring buffer + if(channels == 0) { + fir_buffer_mono[fir_index] = audio_buffer[audio_index]; + } else { + // In stereo operation, generate sum and difference signals + fir_buffer_mono[fir_index] = + audio_buffer[audio_index] + audio_buffer[audio_index+1]; + fir_buffer_stereo[fir_index] = + audio_buffer[audio_index] - audio_buffer[audio_index+1]; + } fir_index++; if(fir_index >= FIR_SIZE) fir_index = 0; + // Now apply the FIR low-pass filter /* As the FIR filter is symmetric, we do not multiply all the coefficients independently, but two-by-two, thus reducing the total number of multiplications by a factor of two */ - out = 0; + float out_mono = 0; + float out_stereo = 0; int ifbi = fir_index; // ifbi = increasing FIR Buffer Index int dfbi = fir_index; // dfbi = decreasing FIR Buffer Index for(int fi=0; fi 1) { + out_stereo += + low_pass_fir[fi] * + (fir_buffer_stereo[ifbi] + fir_buffer_stereo[dfbi]); + } ifbi++; if(ifbi >= FIR_SIZE) ifbi = 0; } // End of FIR filter - mpx_buffer[i] = (rds_buffer[i] + - 4*out /* + - 2 * carrier_38[phase_38] * out + - .1*carrier_19[phase_19]*/) / 10; - - phase_19++; - phase_38++; - if(phase_19 >= 12) phase_19 = 0; - if(phase_38 >= 6) phase_38 = 0; - + mpx_buffer[i] = + mpx_buffer[i] + // RDS data samples are currently in mpx_buffer + 4.05*out_mono; // Unmodulated monophonic (or stereo-sum) signal + + if(channels>1) { + mpx_buffer[i] += + 4.05 * carrier_38[phase_38] * out_stereo + // Stereo difference signal + .09*carrier_19[phase_19]; // Stereo pilot tone + + phase_19++; + phase_38++; + if(phase_19 >= 12) phase_19 = 0; + if(phase_38 >= 6) phase_38 = 0; + } + audio_pos++; } - return 0; // TODO + return 0; } @@ -186,5 +244,8 @@ int fm_mpx_close() { if(sf_close(inf) ) { fprintf(stderr, "Error closing audio file"); } - return 0; // TODO + + free(audio_buffer); + + return 0; } \ No newline at end of file diff --git a/src/fm_mpx.h b/src/fm_mpx.h index c1cc120..81b61be 100644 --- a/src/fm_mpx.h +++ b/src/fm_mpx.h @@ -21,6 +21,6 @@ along with this program. If not, see . */ -extern int fm_mpx_open(char *filename); +extern int fm_mpx_open(char *filename, size_t len); extern int fm_mpx_get_samples(float *mpx_buffer); extern int fm_mpx_close(); \ No newline at end of file diff --git a/src/rds_wav.c b/src/rds_wav.c index f46ef9a..8d90a9f 100644 --- a/src/rds_wav.c +++ b/src/rds_wav.c @@ -36,17 +36,20 @@ /* Simple test program */ int main(int argc, char **argv) { - if(argc < 3) { + if(argc < 4) { fprintf(stderr, "Error: missing argument.\n"); - fprintf(stderr, "Syntax: rds_wav \n"); + fprintf(stderr, "Syntax: rds_wav \n"); return EXIT_FAILURE; } set_rds_pi(0x1234); - set_rds_ps(argv[2]); - set_rds_rt(argv[2]); + set_rds_ps(argv[3]); + set_rds_rt(argv[3]); - fm_mpx_open("sound_22050.wav"); + if(fm_mpx_open(argv[1], LENGTH) != 0) { + printf("Could not setup FM mulitplex generator.\n"); + return EXIT_FAILURE; + } @@ -62,8 +65,8 @@ int main(int argc, char **argv) { sfinfo.seekable = 0; // Open the output file - if (! (outf = sf_open(argv[1], SFM_WRITE, &sfinfo))) { - fprintf(stderr, "Error: could not open output file %s.\n", argv[1]) ; + if (! (outf = sf_open(argv[2], SFM_WRITE, &sfinfo))) { + fprintf(stderr, "Error: could not open output file %s.\n", argv[2]) ; return EXIT_FAILURE; } @@ -71,6 +74,11 @@ int main(int argc, char **argv) { for(int j=0; j<40; j++) { fm_mpx_get_samples(mpx_buffer); + + // scale samples + for(int i=0; i