This commit is contained in:
Blenderpics 2024-02-19 08:03:10 -07:00 committed by GitHub
commit 0565565af7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 62 additions and 12 deletions

View File

@ -53,7 +53,7 @@ To test stereophonic audio, you can try the file `stereo_44100.wav` provided.
The more general syntax for running Pi-FM-RDS is as follows:
```
pi_fm_rds [-freq freq] [-audio file] [-ppm ppm_error] [-pi pi_code] [-ps ps_text] [-rt rt_text]
pi_fm_rds [-freq freq] [-audio file] [-ppm ppm_error] [-pi pi_code] [-ps ps_text] [-rt rt_text] [-cutoff cutoff_freq] [-preemph preemphasis_mode]
```
All arguments are optional:
@ -65,6 +65,8 @@ All arguments are optional:
* `-rt` specifies the radiotext (RT) to be transmitted. Limit: 64 characters. Example: `-rt 'Hello, world!'`.
* `-ctl` specifies a named pipe (FIFO) to use as a control channel to change PS and RT at run-time (see below).
* `-ppm` specifies your Raspberry Pi's oscillator error in parts per million (ppm), see below.
* `-cutoff` specifies the cutoff frequency (in Hz, 'compliant' for 15,000Hz or 'quality' for 22,050Hz) used by Pi-FM-RDS' internal lowpass filter. Values greater than 15000 are not compliant. Use carefully.
* `-preemph` specifies which preemph should be used, since it differs from location. For Europe choose 'eu', for the US choose 'us'.
By default the PS changes back and forth between `Pi-FmRds` and a sequence number, starting at `00000000`. The PS changes around one time per second.

View File

@ -66,6 +66,10 @@ float fir_buffer_stereo[FIR_SIZE] = {0};
int fir_index = 0;
int channels;
float *last_buffer_val;
float preemphasis_prewarp;
float preemphasis_coefficient;
SNDFILE *inf;
@ -80,7 +84,7 @@ float *alloc_empty_buffer(size_t length) {
}
int fm_mpx_open(char *filename, size_t len) {
int fm_mpx_open(char *filename, size_t len, float cutoff_freq, float preemphasis_corner_freq) {
length = len;
if(filename != NULL) {
@ -114,13 +118,19 @@ int fm_mpx_open(char *filename, size_t len) {
printf("%d channels, generating stereo multiplex.\n", channels);
} else {
printf("1 channel, monophonic operation.\n");
}
}
// Create the preemphasis
last_buffer_val = (float*) malloc(sizeof(float)*channels);
for(int i=0;i<channels;i++) last_buffer_val[i] = 0;
preemphasis_prewarp = tan(PI*preemphasis_corner_freq/in_samplerate);
preemphasis_coefficient = (1.0 + (1.0 - preemphasis_prewarp)/(1.0 + preemphasis_prewarp))/2.0;
printf("Created preemphasis with cutoff at %.1f Hz\n", preemphasis_corner_freq);
// Create the low-pass FIR filter
float cutoff_freq = 15000 * .8;
if(in_samplerate/2 < cutoff_freq) cutoff_freq = in_samplerate/2 * .8;
if(in_samplerate/2 < cutoff_freq) cutoff_freq = in_samplerate/2;
low_pass_fir[FIR_HALF_SIZE-1] = 2 * cutoff_freq / 228000 /2;
@ -181,6 +191,18 @@ int fm_mpx_get_samples(float *mpx_buffer) {
return -1;
}
} else {
//apply preemphasis
int k;
int l;
float tmp;
for(k=0;k<audio_len;k+=channels) {
for(l=0;l<channels;l++) {
tmp = audio_buffer[k+l];
audio_buffer[k+l] = audio_buffer[k+l] - preemphasis_coefficient*last_buffer_val[l];
last_buffer_val[l] = tmp;
}
}
break;
}
}

View File

@ -21,6 +21,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
extern int fm_mpx_open(char *filename, size_t len);
extern int fm_mpx_open(char *filename, size_t len, float cutoff_freq, float preemphasis_corner_freq);
extern int fm_mpx_get_samples(float *mpx_buffer);
extern int fm_mpx_close();

View File

@ -197,7 +197,6 @@
// (broadcast radio) and about 3.5 for NBFM (walkie-talkie style radio)
#define DEVIATION 25.0
typedef struct {
uint32_t info, src, dst, length,
stride, next, pad[2];
@ -317,7 +316,7 @@ map_peripheral(uint32_t base, uint32_t len)
#define DATA_SIZE 5000
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, float ppm, char *control_pipe) {
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, float ppm, char *control_pipe, float cutoff, float preemphasis_cutoff) {
// Catch all signals possible - it is vital we kill the DMA engine
// on process exit!
for (int i = 0; i < 64; i++) {
@ -452,7 +451,7 @@ int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt,
int data_index = 0;
// Initialize the baseband generator
if(fm_mpx_open(audio_file, DATA_SIZE) < 0) return 1;
if(fm_mpx_open(audio_file, DATA_SIZE, cutoff, preemphasis_cutoff) < 0) return 1;
// Initialize the RDS modulator
char myps[9] = {0};
@ -543,6 +542,11 @@ int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt,
return 0;
}
#define PREEMPHASIS_EU 3185
#define PREEMPHASIS_US 2120
#define CUTOFF_COMPLIANT 15000
#define CUTOFF_QUALITY 22050
int main(int argc, char **argv) {
char *audio_file = NULL;
@ -552,6 +556,8 @@ int main(int argc, char **argv) {
char *rt = "PiFmRds: live FM-RDS transmission from the RaspberryPi";
uint16_t pi = 0x1234;
float ppm = 0;
float cutoff = CUTOFF_COMPLIANT;
float preemphasis_cutoff = PREEMPHASIS_US;
// Parse command-line arguments
@ -584,6 +590,26 @@ int main(int argc, char **argv) {
} else if(strcmp("-ctl", arg)==0 && param != NULL) {
i++;
control_pipe = param;
} else if(strcmp("-preemph", arg)==0 && param != NULL) {
i++;
if(strcmp("eu", param)==0) {
preemphasis_cutoff = PREEMPHASIS_EU;
} else if(strcmp("us", param)==0) {
preemphasis_cutoff = PREEMPHASIS_US;
}
else {
preemphasis_cutoff = atof(param);
}
} else if(strcmp("-cutoff", arg)==0 && param != NULL) {
i++;
if(strcmp("compliant", param)==0) {
cutoff = CUTOFF_COMPLIANT;
} else if(strcmp("quality", param)==0) {
cutoff = CUTOFF_QUALITY;
}
else {
cutoff = atof(param);
}
} else {
fatal("Unrecognised argument: %s.\n"
"Syntax: pi_fm_rds [-freq freq] [-audio file] [-ppm ppm_error] [-pi pi_code]\n"
@ -591,7 +617,7 @@ int main(int argc, char **argv) {
}
}
int errcode = tx(carrier_freq, audio_file, pi, ps, rt, ppm, control_pipe);
int errcode = tx(carrier_freq, audio_file, pi, ps, rt, ppm, control_pipe, cutoff, preemphasis_cutoff);
terminate(errcode);
}