mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 19:23:51 +01:00
configs
This commit is contained in:
@@ -1,49 +1,53 @@
|
|||||||
#include "stereo_encoder.h"
|
#include "stereo_encoder.h"
|
||||||
|
|
||||||
// Multiplier is the multiplier to get to 19 khz
|
// Multiplier is the multiplier to get to 19 khz
|
||||||
void init_stereo_encoder(StereoEncoder* st, uint8_t multiplier, Oscillator* osc, float audio_volume, float pilot_volume) {
|
void init_stereo_encoder(StereoEncoder* st, uint8_t stereo_ssb, uint8_t multiplier, Oscillator* osc, float audio_volume, float pilot_volume) {
|
||||||
st->multiplier = multiplier;
|
st->multiplier = multiplier;
|
||||||
st->osc = osc;
|
st->osc = osc;
|
||||||
st->pilot_volume = pilot_volume;
|
st->pilot_volume = pilot_volume;
|
||||||
st->audio_volume = audio_volume;
|
st->audio_volume = audio_volume;
|
||||||
#ifdef STEREO_SSB
|
if(stereo_ssb) {
|
||||||
init_delay_line(&st->delay_pilot, STEREO_SSB*2+1);
|
init_delay_line(&st->delay_pilot, stereo_ssb*2+1);
|
||||||
init_delay_line(&st->delay, STEREO_SSB*2+1);
|
init_delay_line(&st->delay, stereo_ssb*2+1);
|
||||||
#endif
|
st->stereo_hilbert = firhilbf_create(stereo_ssb, 60);
|
||||||
|
} else st->stereo_hilbert = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
float stereo_encode(StereoEncoder* st, uint8_t enabled, float left, float right, firhilbf *hilbert) {
|
float stereo_encode(StereoEncoder* st, uint8_t enabled, float left, float right) {
|
||||||
float mid = (left+right) * 0.5f;
|
float mid = (left+right) * 0.5f;
|
||||||
if(!enabled) return mid * st->audio_volume;
|
if(!enabled) return mid * st->audio_volume;
|
||||||
#ifdef STEREO_SSB
|
|
||||||
mid = delay_line(&st->delay, mid);
|
if(st->stereo_hilbert) mid = delay_line(&st->delay, mid);
|
||||||
#endif
|
|
||||||
|
|
||||||
float half_audio = st->audio_volume * 0.5f;
|
float half_audio = st->audio_volume * 0.5f;
|
||||||
|
|
||||||
float side = (left-right) * 0.5f;
|
float side = (left-right) * 0.5f;
|
||||||
|
|
||||||
#ifdef STEREO_SSB
|
float complex stereo_hilbert = 0+0*I;
|
||||||
float complex stereo_hilbert;
|
if(st->stereo_hilbert) firhilbf_r2c_execute(st->stereo_hilbert, side, &stereo_hilbert);
|
||||||
firhilbf_r2c_execute(*hilbert, side, &stereo_hilbert);
|
|
||||||
float signalx2cos = get_oscillator_cos_multiplier_ni(st->osc, st->multiplier * 2.0f);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float signalx1 = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier);
|
float signalx1 = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier);
|
||||||
#ifdef STEREO_SSB
|
|
||||||
signalx1 = delay_line(&st->delay_pilot, signalx1);
|
float signalx2cos = 0.0f;
|
||||||
#endif
|
if(st->stereo_hilbert) {
|
||||||
|
signalx1 = delay_line(&st->delay_pilot, signalx1);
|
||||||
|
signalx2cos = get_oscillator_cos_multiplier_ni(st->osc, st->multiplier * 2.0f);
|
||||||
|
}
|
||||||
float signalx2 = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier * 2.0f);
|
float signalx2 = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier * 2.0f);
|
||||||
|
|
||||||
#ifdef STEREO_SSB
|
if(st->stereo_hilbert) {
|
||||||
float stereo = (crealf(stereo_hilbert) * signalx2cos) + (cimagf(stereo_hilbert) * signalx2);
|
float stereo = (crealf(stereo_hilbert) * signalx2cos) + (cimagf(stereo_hilbert) * signalx2);
|
||||||
return (mid*half_audio) + (signalx1*st->pilot_volume) + (stereo * half_audio);
|
return (mid*half_audio) + (signalx1*st->pilot_volume) + (stereo * half_audio);
|
||||||
#else
|
} else {
|
||||||
return (mid*half_audio) + (signalx1*st->pilot_volume) + ((side*signalx2) * half_audio);
|
return (mid*half_audio) + (signalx1*st->pilot_volume) + ((side*signalx2) * half_audio);
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit_stereo_encoder(StereoEncoder* st) {
|
void exit_stereo_encoder(StereoEncoder* st) {
|
||||||
exit_delay_line(&st->delay);
|
if(st->stereo_hilbert) {
|
||||||
exit_delay_line(&st->delay_pilot);
|
exit_delay_line(&st->delay);
|
||||||
|
exit_delay_line(&st->delay_pilot);
|
||||||
|
firhilbf_destroy(st->stereo_hilbert);
|
||||||
|
st->stereo_hilbert = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define STEREO_SSB 12
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "../dsp/oscillator.h"
|
#include "../dsp/oscillator.h"
|
||||||
#include <liquid/liquid.h>
|
#include <liquid/liquid.h>
|
||||||
@@ -16,8 +14,9 @@ typedef struct
|
|||||||
float pilot_volume;
|
float pilot_volume;
|
||||||
delay_line_t delay;
|
delay_line_t delay;
|
||||||
delay_line_t delay_pilot;
|
delay_line_t delay_pilot;
|
||||||
|
firhilbf stereo_hilbert;
|
||||||
} StereoEncoder;
|
} StereoEncoder;
|
||||||
|
|
||||||
void init_stereo_encoder(StereoEncoder *st, uint8_t multiplier, Oscillator *osc, float audio_volume, float pilot_volume);
|
void init_stereo_encoder(StereoEncoder *st, uint8_t stereo_ssb, uint8_t multiplier, Oscillator *osc, float audio_volume, float pilot_volume);
|
||||||
float stereo_encode(StereoEncoder* st, uint8_t enabled, float left, float right, firhilbf *hilbert);
|
float stereo_encode(StereoEncoder* st, uint8_t enabled, float left, float right);
|
||||||
void exit_stereo_encoder(StereoEncoder* st);
|
void exit_stereo_encoder(StereoEncoder* st);
|
||||||
43
src/fm95.c
43
src/fm95.c
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
#define DEFAULT_INI_PATH "/etc/fm95.conf"
|
#define DEFAULT_INI_PATH "/etc/fm95.conf"
|
||||||
|
|
||||||
#define buffer_maxlength 73728
|
#define buffer_maxlength 64512
|
||||||
#define buffer_tlength_fragsize 73728
|
#define buffer_tlength_fragsize 64512
|
||||||
|
|
||||||
#include "../dsp/oscillator.h"
|
#include "../dsp/oscillator.h"
|
||||||
#include "../filter/iir.h"
|
#include "../filter/iir.h"
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#include "../filter/bs412.h"
|
#include "../filter/bs412.h"
|
||||||
#include "../filter/gain_control.h"
|
#include "../filter/gain_control.h"
|
||||||
|
|
||||||
#define BUFFER_SIZE 6144 // This defines how many samples to process at a time, because the loop here is this: get signal -> process signal -> output signal, and when we get signal we actually get BUFFER_SIZE of them
|
#define BUFFER_SIZE 7168 // This defines how many samples to process at a time, because the loop here is this: get signal -> process signal -> output signal, and when we get signal we actually get BUFFER_SIZE of them
|
||||||
|
|
||||||
#include "../io/audio.h"
|
#include "../io/audio.h"
|
||||||
|
|
||||||
@@ -47,6 +47,7 @@ typedef struct
|
|||||||
|
|
||||||
FM95_Volumes volumes;
|
FM95_Volumes volumes;
|
||||||
bool stereo;
|
bool stereo;
|
||||||
|
int stereo_ssb;
|
||||||
|
|
||||||
uint8_t rds_streams;
|
uint8_t rds_streams;
|
||||||
|
|
||||||
@@ -83,7 +84,6 @@ typedef struct
|
|||||||
float* rds_in;
|
float* rds_in;
|
||||||
Oscillator osc;
|
Oscillator osc;
|
||||||
iirfilt_rrrf lpf_l, lpf_r;
|
iirfilt_rrrf lpf_l, lpf_r;
|
||||||
firhilbf stereo_hilbert;
|
|
||||||
ResistorCapacitor preemp_l, preemp_r;
|
ResistorCapacitor preemp_l, preemp_r;
|
||||||
BS412Compressor bs412;
|
BS412Compressor bs412;
|
||||||
StereoEncoder stencode;
|
StereoEncoder stencode;
|
||||||
@@ -142,10 +142,7 @@ void cleanup_runtime(FM95_Runtime* runtime, const FM95_Config config) {
|
|||||||
iirfilt_rrrf_destroy(runtime->lpf_l);
|
iirfilt_rrrf_destroy(runtime->lpf_l);
|
||||||
iirfilt_rrrf_destroy(runtime->lpf_r);
|
iirfilt_rrrf_destroy(runtime->lpf_r);
|
||||||
}
|
}
|
||||||
#ifdef STEREO_SSB
|
|
||||||
firhilbf_destroy(runtime->stereo_hilbert);
|
|
||||||
exit_stereo_encoder(&runtime->stencode);
|
exit_stereo_encoder(&runtime->stencode);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_audio_runtime(FM95_Runtime *rt, const FM95_Options options) {
|
void cleanup_audio_runtime(FM95_Runtime *rt, const FM95_Options options) {
|
||||||
@@ -213,7 +210,7 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) {
|
|||||||
|
|
||||||
float l = audio_stereo_input[2*i+0]*config.audio_preamp;
|
float l = audio_stereo_input[2*i+0]*config.audio_preamp;
|
||||||
float r = audio_stereo_input[2*i+1]*config.audio_preamp;
|
float r = audio_stereo_input[2*i+1]*config.audio_preamp;
|
||||||
|
|
||||||
if(config.agc_max != 0.0) {
|
if(config.agc_max != 0.0) {
|
||||||
float agc_gain = process_agc(&runtime->agc, 0.5f * (fabsf(l) + fabsf(r)));
|
float agc_gain = process_agc(&runtime->agc, 0.5f * (fabsf(l) + fabsf(r)));
|
||||||
l *= agc_gain;
|
l *= agc_gain;
|
||||||
@@ -231,13 +228,13 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) {
|
|||||||
iirfilt_rrrf_execute(runtime->lpf_l, l, &mod_l);
|
iirfilt_rrrf_execute(runtime->lpf_l, l, &mod_l);
|
||||||
iirfilt_rrrf_execute(runtime->lpf_r, r, &mod_r);
|
iirfilt_rrrf_execute(runtime->lpf_r, r, &mod_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config.preemphasis != 0) {
|
if(config.preemphasis != 0) {
|
||||||
mod_l = apply_preemphasis(&runtime->preemp_l, mod_l);
|
mod_l = apply_preemphasis(&runtime->preemp_l, mod_l);
|
||||||
mod_r = apply_preemphasis(&runtime->preemp_r, mod_r);
|
mod_r = apply_preemphasis(&runtime->preemp_r, mod_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpx = stereo_encode(&runtime->stencode, config.stereo, mod_l, mod_r, &runtime->stereo_hilbert);
|
mpx = stereo_encode(&runtime->stencode, config.stereo, mod_l, mod_r);
|
||||||
|
|
||||||
if(rds_on) {
|
if(rds_on) {
|
||||||
float rds_level = config.volumes.rds;
|
float rds_level = config.volumes.rds;
|
||||||
@@ -245,11 +242,8 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) {
|
|||||||
uint8_t osc_stream = 12 + stream;
|
uint8_t osc_stream = 12 + stream;
|
||||||
if(osc_stream >= 13) osc_stream++;
|
if(osc_stream >= 13) osc_stream++;
|
||||||
|
|
||||||
#ifdef STEREO_SSB
|
if(config.stereo_ssb) mpx += (runtime->rds_in[config.rds_streams * i + stream] * delay_line(&runtime->rds_delays[stream], get_oscillator_cos_multiplier_ni(&runtime->osc, osc_stream))) * rds_level;
|
||||||
mpx += (runtime->rds_in[config.rds_streams * i + stream] * delay_line(&runtime->rds_delays[stream], get_oscillator_cos_multiplier_ni(&runtime->osc, osc_stream))) * rds_level;
|
else mpx += (runtime->rds_in[config.rds_streams * i + stream] * get_oscillator_cos_multiplier_ni(&runtime->osc, osc_stream)) * rds_level;
|
||||||
#else
|
|
||||||
mpx += (runtime->rds_in[config.rds_streams * i + stream] * get_oscillator_cos_multiplier_ni(&runtime->osc, osc_stream)) * rds_level;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
rds_level *= config.volumes.rds_step; // Prepare level for the next stream
|
rds_level *= config.volumes.rds_step; // Prepare level for the next stream
|
||||||
}
|
}
|
||||||
@@ -370,6 +364,8 @@ static int config_handler(void* user, const char* section, const char* name, con
|
|||||||
pconfig->bs412_release = strtof(value, NULL);
|
pconfig->bs412_release = strtof(value, NULL);
|
||||||
} else if(MATCH("advanced", "lpf_order")) {
|
} else if(MATCH("advanced", "lpf_order")) {
|
||||||
pconfig->lpf_order = atoi(value);
|
pconfig->lpf_order = atoi(value);
|
||||||
|
} else if(MATCH("advanced", "stereo_ssb")) {
|
||||||
|
pconfig->stereo_ssb = atoi(value);
|
||||||
} else if(MATCH("advanced", "preemp_unity")) {
|
} else if(MATCH("advanced", "preemp_unity")) {
|
||||||
pconfig->preemp_unity_freq = strtof(value, NULL);
|
pconfig->preemp_unity_freq = strtof(value, NULL);
|
||||||
} else if(MATCH("advanced", "sample_rate")) {
|
} else if(MATCH("advanced", "sample_rate")) {
|
||||||
@@ -479,7 +475,7 @@ int setup_audio(FM95_Runtime* runtime, const FM95_DeviceNames dv_names, const FM
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_runtime(FM95_Runtime* runtime, const FM95_Config config) {
|
void init_runtime(FM95_Runtime* runtime, const FM95_Config config) {
|
||||||
if(config.calibration != 0) {
|
if(config.calibration != 0) {
|
||||||
init_oscillator(&runtime->osc, (config.calibration == 2) ? 60 : ((config.calibration == 1) ? 400 : 19000), config.sample_rate);
|
init_oscillator(&runtime->osc, (config.calibration == 2) ? 60 : ((config.calibration == 1) ? 400 : 19000), config.sample_rate);
|
||||||
return;
|
return;
|
||||||
@@ -487,15 +483,13 @@ void init_runtime(FM95_Runtime* runtime, const FM95_Config config) {
|
|||||||
else init_oscillator(&runtime->osc, 4750, config.sample_rate);
|
else init_oscillator(&runtime->osc, 4750, config.sample_rate);
|
||||||
|
|
||||||
if(config.lpf_cutoff != 0) {
|
if(config.lpf_cutoff != 0) {
|
||||||
runtime->lpf_l = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, config.lpf_order, (config.lpf_cutoff/config.sample_rate), 0.0f, 1.0f, 60.0f);
|
runtime->lpf_l = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, config.lpf_order, (config.lpf_cutoff/config.sample_rate), 0.0f, 1.0f, 40.0f);
|
||||||
runtime->lpf_r = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, config.lpf_order, (config.lpf_cutoff/config.sample_rate), 0.0f, 1.0f, 60.0f);
|
runtime->lpf_r = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, config.lpf_order, (config.lpf_cutoff/config.sample_rate), 0.0f, 1.0f, 40.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STEREO_SSB
|
if(config.stereo_ssb) {
|
||||||
runtime->stereo_hilbert = firhilbf_create(STEREO_SSB, 80);
|
for(int i = 0; i < config.rds_streams; i++) init_delay_line(&runtime->rds_delays[i], config.stereo_ssb*2+1);
|
||||||
|
}
|
||||||
for(int i = 0; i < config.rds_streams; i++) init_delay_line(&runtime->rds_delays[i], STEREO_SSB*2+1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(config.preemphasis != 0) {
|
if(config.preemphasis != 0) {
|
||||||
init_preemphasis(&runtime->preemp_l, (float)config.preemphasis * 1.0e-6f, config.sample_rate, config.preemp_unity_freq);
|
init_preemphasis(&runtime->preemp_l, (float)config.preemphasis * 1.0e-6f, config.sample_rate, config.preemp_unity_freq);
|
||||||
@@ -521,7 +515,7 @@ void init_runtime(FM95_Runtime* runtime, const FM95_Config config) {
|
|||||||
runtime->bs412.sample_counter = last_sample_counter;
|
runtime->bs412.sample_counter = last_sample_counter;
|
||||||
runtime->bs412.second_counter = last_second_counter;
|
runtime->bs412.second_counter = last_second_counter;
|
||||||
|
|
||||||
init_stereo_encoder(&runtime->stencode, 4.0f, &runtime->osc, config.volumes.audio, config.volumes.pilot);
|
init_stereo_encoder(&runtime->stencode, config.stereo_ssb, 4.0f, &runtime->osc, config.volumes.audio, config.volumes.pilot);
|
||||||
|
|
||||||
if(config.agc_max != 0.0) {
|
if(config.agc_max != 0.0) {
|
||||||
last_gain = 1.0f;
|
last_gain = 1.0f;
|
||||||
@@ -544,6 +538,7 @@ int main(int argc, char **argv) {
|
|||||||
.headroom = 0.05f
|
.headroom = 0.05f
|
||||||
},
|
},
|
||||||
.stereo = 1,
|
.stereo = 1,
|
||||||
|
.stereo_ssb = 0,
|
||||||
|
|
||||||
.rds_streams = 1, // You have to match this with RDS95, otherwise may god have mercy on your RDS decoders
|
.rds_streams = 1, // You have to match this with RDS95, otherwise may god have mercy on your RDS decoders
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user