diff --git a/src/Makefile b/src/Makefile index d4f5e8f..4125d00 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,8 +4,8 @@ CFLAGS = -Wall -std=gnu99 -c -g -O2 app: rds.o waveforms.o pi_fm_rds.o $(CC) -o pi_fm_rds rds.o waveforms.o pi_fm_rds.o -lm -lsndfile -rds_wav: rds.o waveforms.o rds_wav.o - $(CC) -o rds_wav rds_wav.o rds.o waveforms.o -lsndfile +rds_wav: rds.o waveforms.o rds_wav.o fm_mpx.o + $(CC) -o rds_wav rds_wav.o rds.o waveforms.o fm_mpx.o -lm -lsndfile rds.o: rds.c waveforms.h $(CC) $(CFLAGS) rds.c @@ -19,5 +19,8 @@ pi_fm_rds.o: pi_fm_rds.c rds_wav.o: rds_wav.c $(CC) $(CFLAGS) rds_wav.c +fm_mpx.o: fm_mpx.c fm_mpx.h + $(CC) $(CFLAGS) fm_mpx.c + clean: rm *.o diff --git a/src/fm_mpx.c b/src/fm_mpx.c new file mode 100644 index 0000000..7fa869c --- /dev/null +++ b/src/fm_mpx.c @@ -0,0 +1,190 @@ +/* + PiFmRds - FM/RDS transmitter for the Raspberry Pi + Copyright (C) 2014 Christophe Jacquet, F8FTK + + See https://github.com/ChristopheJacquet/PiFmRds + + rds_wav.c is a test program that writes a RDS baseband signal to a WAV + file. It requires libsndfile. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include + +#include "rds.h" + + +#define PI 3.141592654 + + +#define FIR_HALF_SIZE 30 +#define FIR_SIZE (2*FIR_HALF_SIZE-1) + +#define LENGTH 114000 +// TODO: remove constant + +// coefficients of the low-pass FIR filter +float low_pass_fir[FIR_HALF_SIZE]; + + +float carrier_38[] = {0.0, 0.8660254037844386, 0.8660254037844388, 1.2246467991473532e-16, -0.8660254037844384, -0.8660254037844386}; + +float carrier_19[] = {0.0, 0.5, 0.8660254037844386, 1.0, 0.8660254037844388, 0.5, 1.2246467991473532e-16, -0.5, -0.8660254037844384, -1.0, -0.8660254037844386, -0.5}; + +int phase_38 = 0; +int phase_19 = 0; + + +float downsample_factor; + + +float rds_buffer[LENGTH] = {0}; +float audio_buffer[LENGTH] = {0}; +int audio_index = 0; +int audio_len = 0; +float audio_pos; +float out = 0; +float alpha = .03; + +float fir_buffer[FIR_SIZE] = {0}; +int fir_index = 0; + +SNDFILE *inf; + + + + +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 + + // 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); + if (audio_len < 0) { + fprintf(stderr, "Error reading audio\n"); + exit(EXIT_FAILURE); + } + if(audio_len == 0) { + sf_seek(inf, 0, SEEK_SET); + } else { + break; + } + } + audio_index = 0; + } else { + audio_index++; + audio_len--; + } + } + + // Apply FIR low-pass filter + fir_buffer[fir_index] = audio_buffer[audio_index]; + fir_index++; + if(fir_index >= FIR_SIZE) fir_index = 0; + + + /* 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; + int ifbi = fir_index; // ifbi = increasing FIR Buffer Index + int dfbi = fir_index; // dfbi = decreasing FIR Buffer Index + for(int fi=0; fi= 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; + + audio_pos++; + + } + + return 0; // TODO +} + + +int fm_mpx_close() { + if(sf_close(inf) ) { + fprintf(stderr, "Error closing audio file"); + } + return 0; // TODO +} \ No newline at end of file diff --git a/src/fm_mpx.h b/src/fm_mpx.h new file mode 100644 index 0000000..c1cc120 --- /dev/null +++ b/src/fm_mpx.h @@ -0,0 +1,26 @@ +/* + PiFmRds - FM/RDS transmitter for the Raspberry Pi + Copyright (C) 2014 Christophe Jacquet, F8FTK + + See https://github.com/ChristopheJacquet/PiFmRds + + rds_wav.c is a test program that writes a RDS baseband signal to a WAV + file. It requires libsndfile. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +extern int fm_mpx_open(char *filename); +extern int fm_mpx_get_samples(float *mpx_buffer); +extern int fm_mpx_close(); \ No newline at end of file diff --git a/src/noise_22050.wav b/src/noise_22050.wav new file mode 100644 index 0000000..5fb079a Binary files /dev/null and b/src/noise_22050.wav differ diff --git a/src/rds.h b/src/rds.h index 9a2aebc..fa839ef 100644 --- a/src/rds.h +++ b/src/rds.h @@ -18,6 +18,9 @@ along with this program. If not, see . */ +#ifndef RDS_H +#define RDS_H + #include @@ -25,3 +28,6 @@ extern void get_rds_samples(float *buffer, int count); extern void set_rds_pi(uint16_t pi_code); extern void set_rds_rt(char *rt); extern void set_rds_ps(char *ps); + + +#endif /* RDS_H */ \ No newline at end of file diff --git a/src/rds_wav.c b/src/rds_wav.c index 190b35d..f46ef9a 100644 --- a/src/rds_wav.c +++ b/src/rds_wav.c @@ -24,12 +24,16 @@ #include #include +#include #include #include "rds.h" +#include "fm_mpx.h" + #define LENGTH 114000 + /* Simple test program */ int main(int argc, char **argv) { if(argc < 3) { @@ -42,11 +46,14 @@ int main(int argc, char **argv) { set_rds_ps(argv[2]); set_rds_rt(argv[2]); - float buffer[LENGTH]; + fm_mpx_open("sound_22050.wav"); + + // Set the format of the output file SNDFILE *outf; SF_INFO sfinfo; + sfinfo.frames = LENGTH; sfinfo.samplerate = 228000; sfinfo.channels = 1; @@ -60,11 +67,12 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } + float mpx_buffer[LENGTH]; for(int j=0; j<40; j++) { - get_rds_samples(buffer, LENGTH); + fm_mpx_get_samples(mpx_buffer); - if(sf_write_float(outf, buffer, LENGTH) != LENGTH) { + if(sf_write_float(outf, mpx_buffer, LENGTH) != LENGTH) { fprintf(stderr, "Error: writing to file %s.\n", argv[1]); return EXIT_FAILURE; } @@ -74,5 +82,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error: closing file %s.\n", argv[1]); } + fm_mpx_close(); + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/src/sound_22050.wav b/src/sound_22050.wav new file mode 100644 index 0000000..f261265 Binary files /dev/null and b/src/sound_22050.wav differ