fl2k_fm: add stereo and RDS support
Signed-off-by: Steve Markgraf <steve@steve-m.de>palette
parent
12ec69362e
commit
632482623d
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* RDS Modulator from:
|
||||
* PiFmRds - FM/RDS transmitter for the Raspberry Pi
|
||||
* https://github.com/ChristopheJacquet/PiFmRds
|
||||
*
|
||||
* Copyright (C) 2014 by Christophe Jacquet, F8FTK
|
||||
*
|
||||
* adapted for use with fl2k_fm:
|
||||
* Copyright (C) 2018 by Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RDS_H
|
||||
#define RDS_H
|
||||
|
||||
#define RDS_MODULATOR_RATE (57000 * 4)
|
||||
|
||||
void get_rds_samples(double *buffer, int count);
|
||||
void set_rds_pi(uint16_t pi_code);
|
||||
void set_rds_rt(char *rt);
|
||||
void set_rds_ps(char *ps);
|
||||
void set_rds_ta(int ta);
|
||||
|
||||
#endif /* RDS_H */
|
|
@ -76,7 +76,7 @@ endif()
|
|||
add_executable(fl2k_file fl2k_file.c)
|
||||
add_executable(fl2k_tcp fl2k_tcp.c)
|
||||
add_executable(fl2k_test fl2k_test.c)
|
||||
add_executable(fl2k_fm fl2k_fm.c)
|
||||
add_executable(fl2k_fm fl2k_fm.c rds_waveforms.c rds_mod.c)
|
||||
set(INSTALL_TARGETS libosmo-fl2k_shared libosmo-fl2k_static fl2k_file fl2k_tcp fl2k_test fl2k_fm)
|
||||
|
||||
target_link_libraries(fl2k_file libosmo-fl2k_shared
|
||||
|
|
151
src/fl2k_fm.c
151
src/fl2k_fm.c
|
@ -30,6 +30,7 @@
|
|||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
|
@ -41,6 +42,7 @@
|
|||
#include <pthread.h>
|
||||
|
||||
#include "osmo-fl2k.h"
|
||||
#include "rds_mod.h"
|
||||
|
||||
#define BUFFER_SAMPLES_SHIFT 16
|
||||
#define BUFFER_SAMPLES (1 << BUFFER_SAMPLES_SHIFT)
|
||||
|
@ -66,10 +68,15 @@ int8_t *buf2 = NULL;
|
|||
uint32_t samp_rate = 100000000;
|
||||
|
||||
/* default signal parameters */
|
||||
#define PILOT_FREQ 19000 /* In Hz */
|
||||
#define STEREO_CARRIER 38000 /* In Hz */
|
||||
|
||||
int delta_freq = 75000;
|
||||
int carrier_freq = 97000000;
|
||||
int carrier_per_signal;
|
||||
int input_freq = 44100;
|
||||
int stereo_flag = 0;
|
||||
int rds_flag = 0;
|
||||
|
||||
double *freqbuf;
|
||||
double *slopebuf;
|
||||
|
@ -83,7 +90,7 @@ void usage(void)
|
|||
"\t[-d device index (default: 0)]\n"
|
||||
"\t[-c carrier frequency (default: 9.7 MHz)]\n"
|
||||
"\t[-f FM deviation (default: 75000 Hz, WBFM)]\n"
|
||||
"\t[-i input audio sample rate (default: 44100 Hz)]\n"
|
||||
"\t[-i input audio sample rate (default: 44100 Hz for mono FM)]\n"
|
||||
"\t[-s samplerate in Hz (default: 100 MS/s)]\n"
|
||||
"\tfilename (use '-' to read from stdin)\n\n"
|
||||
);
|
||||
|
@ -295,15 +302,16 @@ inline double modulate_sample(int lastwritepos, double lastfreq, double sample)
|
|||
return freq;
|
||||
}
|
||||
|
||||
void modulator(void)
|
||||
void fm_modulator_mono(int use_rds)
|
||||
{
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
double freq;
|
||||
double lastfreq = carrier_freq;
|
||||
double slope;
|
||||
int16_t audio_buf[AUDIO_BUF_SIZE];
|
||||
uint32_t lastwritepos = writepos;
|
||||
double sample;
|
||||
double rds_samples[AUDIO_BUF_SIZE];
|
||||
|
||||
while (!do_exit) {
|
||||
len = writelen(AUDIO_BUF_SIZE);
|
||||
|
@ -313,10 +321,88 @@ void modulator(void)
|
|||
if (len == 0)
|
||||
do_exit = 1;
|
||||
|
||||
if (use_rds)
|
||||
get_rds_samples(rds_samples, len);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
sample = audio_buf[i] / 32767.0;
|
||||
|
||||
if (use_rds) {
|
||||
sample *= 4;
|
||||
sample += rds_samples[i];
|
||||
sample /= 5;
|
||||
}
|
||||
|
||||
/* Modulate and buffer the sample */
|
||||
lastfreq = modulate_sample(lastwritepos, lastfreq,
|
||||
audio_buf[i]/32767.0);
|
||||
lastfreq = modulate_sample(lastwritepos, lastfreq, sample);
|
||||
lastwritepos = writepos++;
|
||||
writepos %= BUFFER_SAMPLES;
|
||||
}
|
||||
} else {
|
||||
pthread_cond_wait(&fm_cond, &fm_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fm_modulator_stereo(int use_rds)
|
||||
{
|
||||
unsigned int i;
|
||||
size_t len, sample_cnt;
|
||||
double freq;
|
||||
double lastfreq = carrier_freq;
|
||||
int16_t audio_buf[AUDIO_BUF_SIZE];
|
||||
uint32_t lastwritepos = writepos;
|
||||
|
||||
dds_t pilot, stereo;
|
||||
double L, R, LpR, LmR, sample;
|
||||
double rds_samples[AUDIO_BUF_SIZE];
|
||||
|
||||
/* Prepare stereo carriers */
|
||||
pilot = dds_init(input_freq, PILOT_FREQ, 0);
|
||||
stereo = dds_init(input_freq, STEREO_CARRIER, 0);
|
||||
|
||||
while (!do_exit) {
|
||||
len = writelen(AUDIO_BUF_SIZE);
|
||||
if (len > 1 && !(len % 2)) {
|
||||
len = fread(audio_buf, 2, len, file);
|
||||
|
||||
if (len == 0)
|
||||
do_exit = 1;
|
||||
|
||||
/* stereo => two audio samples per baseband sample */
|
||||
sample_cnt = len/2;
|
||||
|
||||
if (use_rds)
|
||||
get_rds_samples(rds_samples, sample_cnt);
|
||||
|
||||
for (i = 0; i < sample_cnt; i++) {
|
||||
/* Get samples for both channels, and calculate the
|
||||
* mono (L+R) and the difference signal used to recreate
|
||||
* the stereo data (L-R). */
|
||||
L = audio_buf[i*2] / 32767.0;
|
||||
R = audio_buf[i*2+1] / 32767.0;
|
||||
LpR = (L + R) / 2;
|
||||
LmR = (L - R) / 2;
|
||||
|
||||
/* Create a composite sample consisting of the mono
|
||||
* signal at baseband, a 19kHz pilot and a the difference
|
||||
* signal DSB-SC modulated on a 38kHz carrier */
|
||||
sample = 4.05 * LpR; /* Mono signal */
|
||||
sample += 0.9 * (dds_real(&pilot)/127.0); /* Pilot */
|
||||
sample += 4.05 * LmR * (dds_real(&stereo)/127.0); /* DSB-SC stereo */
|
||||
|
||||
if (use_rds) {
|
||||
/* add RDS signal */
|
||||
sample += rds_samples[i];
|
||||
|
||||
/* Normalize so we get the signal within [-1, 1] */
|
||||
sample /= 10;
|
||||
} else {
|
||||
sample /= 9;
|
||||
}
|
||||
|
||||
lastfreq = modulate_sample(lastwritepos, lastfreq, sample);
|
||||
|
||||
lastwritepos = writepos++;
|
||||
writepos %= BUFFER_SAMPLES;
|
||||
}
|
||||
|
@ -346,13 +432,30 @@ int main(int argc, char **argv)
|
|||
int dev_index = 0;
|
||||
pthread_attr_t attr;
|
||||
char *filename = NULL;
|
||||
int option_index = 0;
|
||||
int input_freq_specified = 0;
|
||||
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact, sigign;
|
||||
#endif
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:c:f:i:s:")) != -1) {
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"stereo", no_argument, &stereo_flag, 1},
|
||||
{"rds", no_argument, &rds_flag, 1},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while (1) {
|
||||
opt = getopt_long(argc, argv, "d:c:f:i:s:", long_options, &option_index);
|
||||
|
||||
/* end of options reached */
|
||||
if (opt == -1)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case 0:
|
||||
break;
|
||||
case 'd':
|
||||
dev_index = (uint32_t)atoi(optarg);
|
||||
break;
|
||||
|
@ -364,6 +467,7 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
case 'i':
|
||||
input_freq = (uint32_t)atof(optarg);
|
||||
input_freq_specified = 1;
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atof(optarg);
|
||||
|
@ -384,7 +488,24 @@ int main(int argc, char **argv)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if(strcmp(filename, "-") == 0) { /* Read samples from stdin */
|
||||
if (rds_flag && input_freq_specified) {
|
||||
if (input_freq != RDS_MODULATOR_RATE) {
|
||||
fprintf(stderr, "RDS modulator only works with "
|
||||
"228 kHz audio sample rate!\n");
|
||||
exit(1);
|
||||
}
|
||||
} else if (rds_flag && !input_freq_specified) {
|
||||
input_freq = RDS_MODULATOR_RATE;
|
||||
}
|
||||
|
||||
if (stereo_flag && input_freq < (RDS_MODULATOR_RATE/2)) {
|
||||
fprintf(stderr, "Audio sample rate needs to be at least "
|
||||
"114 kHz for stereo FM!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if (strcmp(filename, "-") == 0) { /* Read samples from stdin */
|
||||
file = stdin;
|
||||
#ifdef _WIN32
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
|
@ -452,8 +573,10 @@ int main(int argc, char **argv)
|
|||
/* Calculate needed constants */
|
||||
carrier_per_signal = samp_rate / input_freq;
|
||||
|
||||
carrier_freq = samp_rate - carrier_freq;
|
||||
|
||||
/* Set RDS parameters */
|
||||
set_rds_pi(0x0dac);
|
||||
set_rds_ps("fl2k_fm");
|
||||
set_rds_rt("VGA FM transmitter");
|
||||
|
||||
#ifndef _WIN32
|
||||
sigact.sa_handler = sighandler;
|
||||
|
@ -468,7 +591,15 @@ int main(int argc, char **argv)
|
|||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
|
||||
#endif
|
||||
|
||||
modulator();
|
||||
if (stereo_flag) {
|
||||
fm_modulator_stereo(rds_flag);
|
||||
} else {
|
||||
if (rds_flag)
|
||||
fprintf(stderr, "Warning: RDS with mono (without 19 kHz pilot"
|
||||
" tone) doesn't work with all receivers!\n");
|
||||
|
||||
fm_modulator_mono(rds_flag);
|
||||
}
|
||||
|
||||
out:
|
||||
fl2k_close(dev);
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* RDS Modulator from:
|
||||
* PiFmRds - FM/RDS transmitter for the Raspberry Pi
|
||||
* https://github.com/ChristopheJacquet/PiFmRds
|
||||
*
|
||||
* Copyright (C) 2014 by Christophe Jacquet, F8FTK
|
||||
*
|
||||
* adapted for use with fl2k_fm:
|
||||
* Copyright (C) 2018 by Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define RT_LENGTH 64
|
||||
#define PS_LENGTH 8
|
||||
#define GROUP_LENGTH 4
|
||||
|
||||
extern double waveform_biphase[576];
|
||||
|
||||
struct {
|
||||
uint16_t pi;
|
||||
int ta;
|
||||
char ps[PS_LENGTH];
|
||||
char rt[RT_LENGTH];
|
||||
} rds_params = { 0 };
|
||||
|
||||
/* The RDS error-detection code generator polynomial is
|
||||
x^10 + x^8 + x^7 + x^5 + x^4 + x^3 + x^0
|
||||
*/
|
||||
#define POLY 0x1B9
|
||||
#define POLY_DEG 10
|
||||
#define MSB_BIT (1 << 15)
|
||||
#define BLOCK_SIZE 16
|
||||
|
||||
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE+POLY_DEG))
|
||||
#define SAMPLES_PER_BIT 192
|
||||
#define FILTER_SIZE (sizeof(waveform_biphase)/sizeof(double))
|
||||
#define SAMPLE_BUFFER_SIZE (SAMPLES_PER_BIT + FILTER_SIZE)
|
||||
|
||||
|
||||
uint16_t offset_words[] = { 0x0FC, 0x198, 0x168, 0x1B4 };
|
||||
// We don't handle offset word C' here for the sake of simplicity
|
||||
|
||||
/* Classical CRC computation */
|
||||
uint16_t crc(uint16_t block)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
int i, bit, msb;
|
||||
|
||||
for (i = 0; i < BLOCK_SIZE; i++) {
|
||||
bit = (block & MSB_BIT) != 0;
|
||||
block <<= 1;
|
||||
|
||||
msb = (crc >> (POLY_DEG-1)) & 1;
|
||||
crc <<= 1;
|
||||
|
||||
if ((msb ^ bit) != 0)
|
||||
crc = crc ^ POLY;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Possibly generates a CT (clock time) group if the minute has just changed
|
||||
Returns 1 if the CT group was generated, 0 otherwise
|
||||
*/
|
||||
int get_rds_ct_group(uint16_t *blocks)
|
||||
{
|
||||
static int latest_minutes = -1;
|
||||
int l, mjd, offset;
|
||||
|
||||
// Check time
|
||||
time_t now;
|
||||
struct tm *utc;
|
||||
|
||||
now = time(NULL);
|
||||
utc = gmtime(&now);
|
||||
|
||||
if(utc->tm_min != latest_minutes) {
|
||||
// Generate CT group
|
||||
latest_minutes = utc->tm_min;
|
||||
|
||||
l = utc->tm_mon <= 1 ? 1 : 0;
|
||||
mjd = 14956 + utc->tm_mday +
|
||||
(int)((utc->tm_year - l) * 365.25) +
|
||||
(int)((utc->tm_mon + 2 + l*12) * 30.6001);
|
||||
|
||||
blocks[1] = 0x4400 | (mjd>>15);
|
||||
blocks[2] = (mjd<<1) | (utc->tm_hour>>4);
|
||||
blocks[3] = (utc->tm_hour & 0xF)<<12 | utc->tm_min<<6;
|
||||
|
||||
utc = localtime(&now);
|
||||
|
||||
offset = utc->tm_gmtoff / (30 * 60);
|
||||
blocks[3] |= abs(offset);
|
||||
if (offset < 0)
|
||||
blocks[3] |= 0x20;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Creates an RDS group. This generates sequences of the form 0A, 0A, 0A, 0A, 2A, etc.
|
||||
The pattern is of length 5, the variable 'state' keeps track of where we are in the
|
||||
pattern. 'ps_state' and 'rt_state' keep track of where we are in the PS (0A) sequence
|
||||
or RT (2A) sequence, respectively.
|
||||
*/
|
||||
void get_rds_group(int *buffer)
|
||||
{
|
||||
static int state = 0;
|
||||
static int ps_state = 0;
|
||||
static int rt_state = 0;
|
||||
uint16_t blocks[GROUP_LENGTH] = { rds_params.pi, 0, 0, 0 };
|
||||
uint16_t block, check;
|
||||
int i, j;
|
||||
|
||||
// Generate block content
|
||||
if (!get_rds_ct_group(blocks)) { // CT (clock time) has priority on other group types
|
||||
if (state < 4) {
|
||||
blocks[1] = 0x0400 | ps_state;
|
||||
|
||||
if (rds_params.ta)
|
||||
blocks[1] |= 0x0010;
|
||||
|
||||
blocks[2] = 0xCDCD; // no AF
|
||||
blocks[3] = rds_params.ps[ps_state*2] << 8 | rds_params.ps[ps_state*2+1];
|
||||
ps_state++;
|
||||
|
||||
if (ps_state >= 4)
|
||||
ps_state = 0;
|
||||
} else { // state == 5
|
||||
blocks[1] = 0x2400 | rt_state;
|
||||
blocks[2] = rds_params.rt[rt_state*4+0] << 8 | rds_params.rt[rt_state*4+1];
|
||||
blocks[3] = rds_params.rt[rt_state*4+2] << 8 | rds_params.rt[rt_state*4+3];
|
||||
rt_state++;
|
||||
if (rt_state >= 16)
|
||||
rt_state = 0;
|
||||
}
|
||||
|
||||
state++;
|
||||
if (state >= 5)
|
||||
state = 0;
|
||||
}
|
||||
|
||||
// Calculate the checkword for each block and emit the bits
|
||||
for (i = 0; i < GROUP_LENGTH; i++) {
|
||||
block = blocks[i];
|
||||
check = crc(block) ^ offset_words[i];
|
||||
for (j = 0; j < BLOCK_SIZE; j++) {
|
||||
*buffer++ = ((block & (1 << (BLOCK_SIZE-1))) != 0);
|
||||
block <<= 1;
|
||||
}
|
||||
for (j = 0; j < POLY_DEG; j++) {
|
||||
*buffer++ = ((check & (1 << (POLY_DEG-1))) != 0);
|
||||
check <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a number of RDS samples. This generates the envelope of the waveform using
|
||||
pre-generated elementary waveform samples, and then it amplitude-modulates the
|
||||
envelope with a 57 kHz carrier, which is very efficient as 57 kHz is 4 times the
|
||||
sample frequency we are working at (228 kHz).
|
||||
*/
|
||||
void get_rds_samples(double *buffer, uint32_t count)
|
||||
{
|
||||
static int bit_buffer[BITS_PER_GROUP];
|
||||
static int bit_pos = BITS_PER_GROUP;
|
||||
static double sample_buffer[SAMPLE_BUFFER_SIZE] = {0};
|
||||
|
||||
static int prev_output = 0;
|
||||
static int cur_output = 0;
|
||||
static int cur_bit = 0;
|
||||
static int sample_count = SAMPLES_PER_BIT;
|
||||
static int inverting = 0;
|
||||
static int phase = 0;
|
||||
|
||||
static unsigned int in_sample_index = 0;
|
||||
static unsigned int out_sample_index = SAMPLE_BUFFER_SIZE-1;
|
||||
|
||||
unsigned int i, j, idx;
|
||||
double val, sample;
|
||||
double *src;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (sample_count >= SAMPLES_PER_BIT) {
|
||||
if (bit_pos >= BITS_PER_GROUP) {
|
||||
get_rds_group(bit_buffer);
|
||||
bit_pos = 0;
|
||||
}
|
||||
|
||||
// do differential encoding
|
||||
cur_bit = bit_buffer[bit_pos];
|
||||
prev_output = cur_output;
|
||||
cur_output = prev_output ^ cur_bit;
|
||||
|
||||
inverting = (cur_output == 1);
|
||||
|
||||
src = waveform_biphase;
|
||||
idx = in_sample_index;
|
||||
|
||||
for (j = 0; j < FILTER_SIZE; j++) {
|
||||
val = *src++;
|
||||
if (inverting)
|
||||
val = -val;
|
||||
|
||||
sample_buffer[idx++] += val;
|
||||
|
||||
if (idx >= SAMPLE_BUFFER_SIZE)
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
in_sample_index += SAMPLES_PER_BIT;
|
||||
if (in_sample_index >= SAMPLE_BUFFER_SIZE)
|
||||
in_sample_index -= SAMPLE_BUFFER_SIZE;
|
||||
|
||||
bit_pos++;
|
||||
sample_count = 0;
|
||||
}
|
||||
|
||||
sample = sample_buffer[out_sample_index];
|
||||
sample_buffer[out_sample_index] = 0;
|
||||
out_sample_index++;
|
||||
if (out_sample_index >= SAMPLE_BUFFER_SIZE)
|
||||
out_sample_index = 0;
|
||||
|
||||
// modulate at 57 kHz
|
||||
// use phase for this
|
||||
switch (phase) {
|
||||
case 0:
|
||||
case 2: sample = 0; break;
|
||||
case 1: break;
|
||||
case 3: sample = -sample; break;
|
||||
}
|
||||
phase++;
|
||||
if (phase >= 4)
|
||||
phase = 0;
|
||||
|
||||
*buffer++ = sample;
|
||||
sample_count++;
|
||||
}
|
||||
}
|
||||
|
||||
void set_rds_pi(uint16_t pi_code)
|
||||
{
|
||||
rds_params.pi = pi_code;
|
||||
}
|
||||
|
||||
void set_rds_rt(char *rt)
|
||||
{
|
||||
int i;
|
||||
|
||||
strncpy(rds_params.rt, rt, 64);
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (rds_params.rt[i] == 0)
|
||||
rds_params.rt[i] = 32;
|
||||
}
|
||||
}
|
||||
|
||||
void set_rds_ps(char *ps)
|
||||
{
|
||||
int i;
|
||||
|
||||
strncpy(rds_params.ps, ps, 8);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (rds_params.ps[i] == 0)
|
||||
rds_params.ps[i] = 32;
|
||||
}
|
||||
}
|
||||
|
||||
void set_rds_ta(int ta)
|
||||
{
|
||||
rds_params.ta = ta;
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/* This file was automatically generated by "generate_waveforms.py" from
|
||||
* https://github.com/ChristopheJacquet/PiFmRds/
|
||||
*
|
||||
* (C) 2014 Christophe Jacquet.
|
||||
* Released under the GNU GPL v3 license.
|
||||
*/
|
||||
|
||||
double waveform_biphase[] = {
|
||||
0.00253265133022, 0.00255504491037, 0.00256667102126, 0.00256723854970,
|
||||
0.00255649674667, 0.00253423716573, 0.00250029547253, 0.00245455311551,
|
||||
0.00239693884806, 0.00232743009314, 0.00224605414143, 0.00215288917468,
|
||||
0.00204806510656, 0.00193176423352, 0.00180422168917, 0.00166572569587,
|
||||
0.00151661760823, 0.00135729174364, 0.00118819499588, 0.00100982622839,
|
||||
0.00082273544470, 0.00062752273428, 0.00042483699288, 0.00021537441720,
|
||||
-0.00000012322530, -0.00022087054977, -0.00044604072817, -0.00067476788077,
|
||||
-0.00090614968071, -0.00113925016637, -0.00137310275567, -0.00160671345499,
|
||||
-0.00183906425517, -0.00206911670572, -0.00229581565752, -0.00251809316382,
|
||||
-0.00273487252813, -0.00294507248686, -0.00314761151410, -0.00334141223473,
|
||||
-0.00352540593170, -0.00369853713255, -0.00385976825946, -0.00400808432674,
|
||||
-0.00414249766903, -0.00426205268297, -0.00436583056466, -0.00445295402495,
|
||||
-0.00452259196407, -0.00457396408696, -0.00460634544047, -0.00461907085337,
|
||||
-0.00461153926002, -0.00458321788861, -0.00453364629481, -0.00446244022186,
|
||||
-0.00436929526830, -0.00425399034471, -0.00411639090130, -0.00395645190841,
|
||||
-0.00377422057251, -0.00356983877090, -0.00334354518872, -0.00309567714275,
|
||||
-0.00282667207705, -0.00253706871632, -0.00222750786389, -0.00189873283191,
|
||||
-0.00155158949247, -0.00118702593940, -0.00080609175162, -0.00040993684994,
|
||||
0.00000019005938, 0.00042294345989, 0.00085688342327, 0.00130047843362,
|
||||
0.00175210863919, 0.00221006953169, 0.00267257605183, 0.00313776711824,
|
||||
0.00360371057560, 0.00406840855594, 0.00452980324611, 0.00498578305229,
|
||||
0.00543418915128, 0.00587282241677, 0.00629945070701, 0.00671181649912,
|
||||
0.00710764485348, 0.00748465169059, 0.00784055236082, 0.00817307048659,
|
||||
0.00847994705483, 0.00875894973632, 0.00900788240743, 0.00922459484812,
|
||||
0.00940699258958, 0.00955304688301, 0.00966080476069, 0.00972839915915,
|
||||
0.00975405907344, 0.00973611971083, 0.00967303261139, 0.00956337570235,
|
||||
0.00940586325271, 0.00919935569384, 0.00894286927184, 0.00863558549687,
|
||||
0.00827686035476, 0.00786623324593, 0.00740343561706, 0.00688839925073,
|
||||
0.00632126417893, 0.00570238618641, 0.00503234387065, 0.00431194522560,
|
||||
0.00354223371723, 0.00272449381977, 0.00186025598240, 0.00095130099727,
|
||||
-0.00000033625901, -0.00099236373728, -0.00202222980620, -0.00308712154498,
|
||||
-0.00418396376074, -0.00530941875093, -0.00645988682960, -0.00763150763453,
|
||||
-0.00882016223000, -0.01002147601830, -0.01123082247100, -0.01244332768770,
|
||||
-0.01365387579080, -0.01485711515770, -0.01604746549480, -0.01721912575140,
|
||||
-0.01836608287050, -0.01948212137170, -0.02056083375870, -0.02159563173920,
|
||||
-0.02257975824610, -0.02350630024450, -0.02436820230520, -0.02515828092590,
|
||||
-0.02586923957590, -0.02649368443980, -0.02702414083260, -0.02745307025480,
|
||||
-0.02777288805630, -0.02797598167370, -0.02805472940410, -0.02800151967640,
|
||||
-0.02780877077830, -0.02746895099680, -0.02697459912600, -0.02631834529620,
|
||||
-0.02549293207490, -0.02449123579000, -0.02330628802350, -0.02193129722250,
|
||||
-0.02035967037330, -0.01858503468320, -0.01660125921430, -0.01440247641080,
|
||||
-0.01198310346410, -0.00933786345535, -0.00646180621834, -0.00335032886310,
|
||||
0.00000080409844, 0.00359544108347, 0.00743702428450, 0.01152857108890,
|
||||
0.01587265612930, 0.02047139402060, 0.02532642284170, 0.03043888841330,
|
||||
0.03580942942790, 0.04143816348300, 0.04732467406730, 0.05346799854990,
|
||||
0.05986661721770, 0.06651844340760, 0.07342081477420, 0.08057048573450,
|
||||
0.08796362112670, 0.09559579111960, 0.10346196740200, 0.11155652068800,
|
||||
0.11987321955300, 0.12840523064300, 0.13714512025400, 0.14608485732300,
|
||||
0.15521581782400, 0.16452879059300, 0.17401398458500, 0.18366103756000,
|
||||
0.19345902621300, 0.20339647772800, 0.21346138276100, 0.22364120983400,
|
||||
0.23392292112600, 0.24429298964900, 0.25473741777900, 0.26524175712200,
|
||||
0.27579112968500, 0.28637025030900, 0.29696345035600, 0.30755470256700,
|
||||
0.31812764709700, 0.32866561863200, 0.33915167458400, 0.34956862427200,
|
||||
0.35989905906300, 0.37012538339000, 0.38022984661400, 0.39019457563000,
|
||||
0.40000160819100, 0.40963292682000, 0.41907049336100, 0.42829628390300,
|
||||
0.43729232419900, 0.44604072538100, 0.45452371993000, 0.46272369782900,
|
||||
0.47062324279700, 0.47820516854900, 0.48545255496600, 0.49234878413200,
|
||||
0.49887757611800, 0.50502302444800, 0.51076963117100, 0.51610234143400,
|
||||
0.52100657748800, 0.52546827205100, 0.52947390092900, 0.53301051483100,
|
||||
0.53606577028900, 0.53862795962200, 0.54068603984100, 0.54222966045900,
|
||||
0.54324919009800, 0.54373574185300, 0.54368119733200, 0.54307822931100,
|
||||
0.54192032294800, 0.54020179549500, 0.53791781445300, 0.53506441412200,
|
||||
0.53163851050000, 0.52763791447900, 0.52306134330900, 0.51790843029000,
|
||||
0.51217973265200, 0.50587673761100, 0.49900186656100, 0.49155847739800,
|
||||
0.48355086494200, 0.47498425946700, 0.46586482332000, 0.45619964562500,
|
||||
0.44599673508500, 0.43526501088000, 0.42401429168100, 0.41225528278300,
|
||||
0.39999956139700, 0.38725956008100, 0.37404854845100, 0.36038061302100,
|
||||
0.34627063539800, 0.33173426875400, 0.31678791267100, 0.30144868639300,
|
||||
0.28573440054000, 0.26966352734900, 0.25325516949400, 0.23652902755300,
|
||||
0.21950536619500, 0.20220497914700, 0.18464915302200, 0.16685963008900,
|
||||
0.14885857004900, 0.13066851092000, 0.11231232909100, 0.09381319865270,
|
||||
0.07519455007850, 0.05648002834940, 0.03769345061440, 0.01885876347700,
|
||||
0.00000000000000, -0.01885876347700, -0.03769345061440, -0.05648002834940,
|
||||
-0.07519455007850, -0.09381319865270, -0.11231232909100, -0.13066851092000,
|
||||
-0.14885857004900, -0.16685963008900, -0.18464915302200, -0.20220497914700,
|
||||
-0.21950536619500, -0.23652902755300, -0.25325516949400, -0.26966352734900,
|
||||
-0.28573440054000, -0.30144868639300, -0.31678791267100, -0.33173426875400,
|
||||
-0.34627063539800, -0.36038061302100, -0.37404854845100, -0.38725956008100,
|
||||
-0.39999956139700, -0.41225528278300, -0.42401429168100, -0.43526501088000,
|
||||
-0.44599673508500, -0.45619964562500, -0.46586482332000, -0.47498425946700,
|
||||
-0.48355086494200, -0.49155847739800, -0.49900186656100, -0.50587673761100,
|
||||
-0.51217973265200, -0.51790843029000, -0.52306134330900, -0.52763791447900,
|
||||
-0.53163851050000, -0.53506441412200, -0.53791781445300, -0.54020179549500,
|
||||
-0.54192032294800, -0.54307822931100, -0.54368119733200, -0.54373574185300,
|
||||
-0.54324919009800, -0.54222966045900, -0.54068603984100, -0.53862795962200,
|
||||
-0.53606577028900, -0.53301051483100, -0.52947390092900, -0.52546827205100,
|
||||
-0.52100657748800, -0.51610234143400, -0.51076963117100, -0.50502302444800,
|
||||
-0.49887757611800, -0.49234878413200, -0.48545255496600, -0.47820516854900,
|
||||
-0.47062324279700, -0.46272369782900, -0.45452371993000, -0.44604072538100,
|
||||
-0.43729232419900, -0.42829628390300, -0.41907049336100, -0.40963292682000,
|
||||
-0.40000160819100, -0.39019457563000, -0.38022984661400, -0.37012538339000,
|
||||
-0.35989905906300, -0.34956862427200, -0.33915167458400, -0.32866561863200,
|
||||
-0.31812764709700, -0.30755470256700, -0.29696345035600, -0.28637025030900,
|
||||
-0.27579112968500, -0.26524175712200, -0.25473741777900, -0.24429298964900,
|
||||
-0.23392292112600, -0.22364120983400, -0.21346138276100, -0.20339647772800,
|
||||
-0.19345902621300, -0.18366103756000, -0.17401398458500, -0.16452879059300,
|
||||
-0.15521581782400, -0.14608485732300, -0.13714512025400, -0.12840523064300,
|
||||
-0.11987321955300, -0.11155652068800, -0.10346196740200, -0.09559579111960,
|
||||
-0.08796362112670, -0.08057048573450, -0.07342081477420, -0.06651844340760,
|
||||
-0.05986661721770, -0.05346799854990, -0.04732467406730, -0.04143816348300,
|
||||
-0.03580942942790, -0.03043888841330, -0.02532642284170, -0.02047139402060,
|
||||
-0.01587265612930, -0.01152857108890, -0.00743702428450, -0.00359544108347,
|
||||
-0.00000080409844, 0.00335032886310, 0.00646180621834, 0.00933786345535,
|
||||
0.01198310346410, 0.01440247641080, 0.01660125921430, 0.01858503468320,
|
||||
0.02035967037330, 0.02193129722250, 0.02330628802350, 0.02449123579000,
|
||||
0.02549293207490, 0.02631834529620, 0.02697459912600, 0.02746895099680,
|
||||
0.02780877077830, 0.02800151967640, 0.02805472940410, 0.02797598167370,
|
||||
0.02777288805630, 0.02745307025480, 0.02702414083260, 0.02649368443980,
|
||||
0.02586923957590, 0.02515828092590, 0.02436820230520, 0.02350630024450,
|
||||
0.02257975824610, 0.02159563173920, 0.02056083375870, 0.01948212137170,
|
||||
0.01836608287050, 0.01721912575140, 0.01604746549480, 0.01485711515770,
|
||||
0.01365387579080, 0.01244332768770, 0.01123082247100, 0.01002147601830,
|
||||
0.00882016223000, 0.00763150763453, 0.00645988682960, 0.00530941875093,
|
||||
0.00418396376074, 0.00308712154498, 0.00202222980620, 0.00099236373728,
|
||||
0.00000033625901, -0.00095130099727, -0.00186025598240, -0.00272449381977,
|
||||
-0.00354223371723, -0.00431194522560, -0.00503234387065, -0.00570238618641,
|
||||
-0.00632126417893, -0.00688839925073, -0.00740343561706, -0.00786623324593,
|
||||
-0.00827686035476, -0.00863558549687, -0.00894286927184, -0.00919935569384,
|
||||
-0.00940586325271, -0.00956337570235, -0.00967303261139, -0.00973611971083,
|
||||
-0.00975405907344, -0.00972839915915, -0.00966080476069, -0.00955304688301,
|
||||
-0.00940699258958, -0.00922459484812, -0.00900788240743, -0.00875894973632,
|
||||
-0.00847994705483, -0.00817307048659, -0.00784055236082, -0.00748465169059,
|
||||
-0.00710764485348, -0.00671181649912, -0.00629945070701, -0.00587282241677,
|
||||
-0.00543418915128, -0.00498578305229, -0.00452980324611, -0.00406840855594,
|
||||
-0.00360371057560, -0.00313776711824, -0.00267257605183, -0.00221006953169,
|
||||
-0.00175210863919, -0.00130047843362, -0.00085688342327, -0.00042294345989,
|
||||
-0.00000019005938, 0.00040993684994, 0.00080609175162, 0.00118702593940,
|
||||
0.00155158949247, 0.00189873283191, 0.00222750786389, 0.00253706871632,
|
||||
0.00282667207705, 0.00309567714275, 0.00334354518872, 0.00356983877090,
|
||||
0.00377422057251, 0.00395645190841, 0.00411639090130, 0.00425399034471,
|
||||
0.00436929526830, 0.00446244022186, 0.00453364629481, 0.00458321788861,
|
||||
0.00461153926002, 0.00461907085337, 0.00460634544047, 0.00457396408696,
|
||||
0.00452259196407, 0.00445295402495, 0.00436583056466, 0.00426205268297,
|
||||
0.00414249766903, 0.00400808432674, 0.00385976825946, 0.00369853713255,
|
||||
0.00352540593170, 0.00334141223473, 0.00314761151410, 0.00294507248686,
|
||||
0.00273487252813, 0.00251809316382, 0.00229581565752, 0.00206911670572,
|
||||
0.00183906425517, 0.00160671345499, 0.00137310275567, 0.00113925016637,
|
||||
0.00090614968071, 0.00067476788077, 0.00044604072817, 0.00022087054977,
|
||||
0.00000012322530, -0.00021537441720, -0.00042483699288, -0.00062752273428,
|
||||
-0.00082273544470, -0.00100982622839, -0.00118819499588, -0.00135729174364,
|
||||
-0.00151661760823, -0.00166572569587, -0.00180422168917, -0.00193176423352,
|
||||
-0.00204806510656, -0.00215288917468, -0.00224605414143, -0.00232743009314,
|
||||
-0.00239693884806, -0.00245455311551, -0.00250029547253, -0.00253423716573,
|
||||
-0.00255649674667, -0.00256723854970, -0.00256667102126, -0.00255504491037,
|
||||
};
|
Loading…
Reference in New Issue