From 1089f8d1ea0aa6df4b3fb824d1db2ecc27e6813a Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Sun, 15 Feb 2026 15:00:20 +0100 Subject: [PATCH] configs --- modulation/stereo_encoder.c | 54 ++++++++++++++++++++----------------- modulation/stereo_encoder.h | 7 +++-- src/fm95.c | 43 +++++++++++++---------------- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/modulation/stereo_encoder.c b/modulation/stereo_encoder.c index e8bc3c8..4d887e0 100644 --- a/modulation/stereo_encoder.c +++ b/modulation/stereo_encoder.c @@ -1,49 +1,53 @@ #include "stereo_encoder.h" // 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->osc = osc; st->pilot_volume = pilot_volume; st->audio_volume = audio_volume; - #ifdef STEREO_SSB - init_delay_line(&st->delay_pilot, STEREO_SSB*2+1); - init_delay_line(&st->delay, STEREO_SSB*2+1); - #endif + if(stereo_ssb) { + init_delay_line(&st->delay_pilot, stereo_ssb*2+1); + init_delay_line(&st->delay, stereo_ssb*2+1); + 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; if(!enabled) return mid * st->audio_volume; - #ifdef STEREO_SSB - mid = delay_line(&st->delay, mid); - #endif + + if(st->stereo_hilbert) mid = delay_line(&st->delay, mid); float half_audio = st->audio_volume * 0.5f; float side = (left-right) * 0.5f; -#ifdef STEREO_SSB - float complex stereo_hilbert; - firhilbf_r2c_execute(*hilbert, side, &stereo_hilbert); - float signalx2cos = get_oscillator_cos_multiplier_ni(st->osc, st->multiplier * 2.0f); -#endif + float complex stereo_hilbert = 0+0*I; + if(st->stereo_hilbert) firhilbf_r2c_execute(st->stereo_hilbert, side, &stereo_hilbert); float signalx1 = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier); - #ifdef STEREO_SSB - signalx1 = delay_line(&st->delay_pilot, signalx1); - #endif + + float signalx2cos = 0.0f; + 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); -#ifdef STEREO_SSB - float stereo = (crealf(stereo_hilbert) * signalx2cos) + (cimagf(stereo_hilbert) * signalx2); - return (mid*half_audio) + (signalx1*st->pilot_volume) + (stereo * half_audio); -#else - return (mid*half_audio) + (signalx1*st->pilot_volume) + ((side*signalx2) * half_audio); -#endif + if(st->stereo_hilbert) { + float stereo = (crealf(stereo_hilbert) * signalx2cos) + (cimagf(stereo_hilbert) * signalx2); + return (mid*half_audio) + (signalx1*st->pilot_volume) + (stereo * half_audio); + } else { + return (mid*half_audio) + (signalx1*st->pilot_volume) + ((side*signalx2) * half_audio); + } } void exit_stereo_encoder(StereoEncoder* st) { - exit_delay_line(&st->delay); - exit_delay_line(&st->delay_pilot); + if(st->stereo_hilbert) { + exit_delay_line(&st->delay); + exit_delay_line(&st->delay_pilot); + firhilbf_destroy(st->stereo_hilbert); + st->stereo_hilbert = NULL; + } } \ No newline at end of file diff --git a/modulation/stereo_encoder.h b/modulation/stereo_encoder.h index 08a7b19..2c210f6 100644 --- a/modulation/stereo_encoder.h +++ b/modulation/stereo_encoder.h @@ -1,7 +1,5 @@ #pragma once -#define STEREO_SSB 12 - #include #include "../dsp/oscillator.h" #include @@ -16,8 +14,9 @@ typedef struct float pilot_volume; delay_line_t delay; delay_line_t delay_pilot; + firhilbf stereo_hilbert; } StereoEncoder; -void init_stereo_encoder(StereoEncoder *st, 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); +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); void exit_stereo_encoder(StereoEncoder* st); \ No newline at end of file diff --git a/src/fm95.c b/src/fm95.c index 64e9fd1..b85c775 100644 --- a/src/fm95.c +++ b/src/fm95.c @@ -5,8 +5,8 @@ #define DEFAULT_INI_PATH "/etc/fm95.conf" -#define buffer_maxlength 73728 -#define buffer_tlength_fragsize 73728 +#define buffer_maxlength 64512 +#define buffer_tlength_fragsize 64512 #include "../dsp/oscillator.h" #include "../filter/iir.h" @@ -14,7 +14,7 @@ #include "../filter/bs412.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" @@ -47,6 +47,7 @@ typedef struct FM95_Volumes volumes; bool stereo; + int stereo_ssb; uint8_t rds_streams; @@ -83,7 +84,6 @@ typedef struct float* rds_in; Oscillator osc; iirfilt_rrrf lpf_l, lpf_r; - firhilbf stereo_hilbert; ResistorCapacitor preemp_l, preemp_r; BS412Compressor bs412; 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_r); } - #ifdef STEREO_SSB - firhilbf_destroy(runtime->stereo_hilbert); exit_stereo_encoder(&runtime->stencode); - #endif } 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 r = audio_stereo_input[2*i+1]*config.audio_preamp; - + if(config.agc_max != 0.0) { float agc_gain = process_agc(&runtime->agc, 0.5f * (fabsf(l) + fabsf(r))); 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_r, r, &mod_r); } - + if(config.preemphasis != 0) { mod_l = apply_preemphasis(&runtime->preemp_l, mod_l); 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) { 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; if(osc_stream >= 13) osc_stream++; -#ifdef 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; -#else - mpx += (runtime->rds_in[config.rds_streams * i + stream] * get_oscillator_cos_multiplier_ni(&runtime->osc, osc_stream)) * rds_level; -#endif + 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; + else mpx += (runtime->rds_in[config.rds_streams * i + stream] * get_oscillator_cos_multiplier_ni(&runtime->osc, osc_stream)) * rds_level; 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); } else if(MATCH("advanced", "lpf_order")) { pconfig->lpf_order = atoi(value); + } else if(MATCH("advanced", "stereo_ssb")) { + pconfig->stereo_ssb = atoi(value); } else if(MATCH("advanced", "preemp_unity")) { pconfig->preemp_unity_freq = strtof(value, NULL); } 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; } -void init_runtime(FM95_Runtime* runtime, const FM95_Config config) { +void init_runtime(FM95_Runtime* runtime, const FM95_Config config) { if(config.calibration != 0) { init_oscillator(&runtime->osc, (config.calibration == 2) ? 60 : ((config.calibration == 1) ? 400 : 19000), config.sample_rate); return; @@ -487,15 +483,13 @@ void init_runtime(FM95_Runtime* runtime, const FM95_Config config) { else init_oscillator(&runtime->osc, 4750, config.sample_rate); 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_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_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, 40.0f); } - #ifdef 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], STEREO_SSB*2+1); - #endif + if(config.stereo_ssb) { + for(int i = 0; i < config.rds_streams; i++) init_delay_line(&runtime->rds_delays[i], config.stereo_ssb*2+1); + } if(config.preemphasis != 0) { 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.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) { last_gain = 1.0f; @@ -544,6 +538,7 @@ int main(int argc, char **argv) { .headroom = 0.05f }, .stereo = 1, + .stereo_ssb = 0, .rds_streams = 1, // You have to match this with RDS95, otherwise may god have mercy on your RDS decoders