From 7350cbcf1e7d61b15a440b4bd5fd3f70c7bdeea9 Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Wed, 6 Aug 2025 19:56:16 +0200 Subject: [PATCH] add headroom option --- README.md | 2 +- fm95.md | 4 ++++ modulation/stereo_encoder.c | 11 ++++++----- modulation/stereo_encoder.h | 5 ++--- src/fm95.c | 23 ++++++++++------------- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index c17f159..0b31552 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ FM95 is a audio processor for FM, it does: Supports these inputs: - Audio (via Pulse) -- MPX (via Pulse, basically passthrough, i don't recommend this unless you have something else than rds or sca to modulate, you could run chimer95 via here, also you have 10% allowed here to be guarenteed with no clipping) +- MPX (via Pulse, basically passthrough, i don't recommend this unless you have something else than rds or sca to modulate, you could run chimer95 via here, also you have 5% allowed here by default to be guarenteed with no clipping, change how much headroom you have with the headroom option) - RDS (via Pulse, expects unmodulated RDS, rds95 is recommended here, in modulation this is quadrature to the pilot, number of channels is specified by the argument, each of the channels (max 4) go on these freqs: 57, 66.5, 71.25, 76) and one output: diff --git a/fm95.md b/fm95.md index a379cbd..af54c48 100644 --- a/fm95.md +++ b/fm95.md @@ -104,3 +104,7 @@ Default 192 khz, does not need change under most systems, and unit is in hz ### lpf_cutoff lpf cutoff, some run this at 15, because Big FMâ„¢ tells them to, but running this higher has no costs (unless you're running it above 18.5 khz), but no gains either, unit in hz + +### headroom + +fm95 now computes the volumes for mono and stereo automatically, and headroom is to select how much headroom you want to leave for the mpx, takes a simple float, 100 percent to mute audio diff --git a/modulation/stereo_encoder.c b/modulation/stereo_encoder.c index 71f8637..e32101c 100644 --- a/modulation/stereo_encoder.c +++ b/modulation/stereo_encoder.c @@ -1,22 +1,23 @@ #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 mono_volume, float pilot_volume, float stereo_volume) { +void init_stereo_encoder(StereoEncoder* st, uint8_t multiplier, Oscillator* osc, float audio_volume, float pilot_volume) { st->multiplier = multiplier; st->osc = osc; - st->mono_volume = mono_volume; st->pilot_volume = pilot_volume; - st->stereo_volume = stereo_volume; + st->audio_volume = audio_volume; } float stereo_encode(StereoEncoder* st, uint8_t enabled, float left, float right) { float mid = (left+right) * 0.5f; - if(!enabled) return mid * st->mono_volume; + if(!enabled) return mid * st->audio_volume; + + float half_audio = st->audio_volume * 0.5f; float side = (left-right) * 0.5f; float signalx1 = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier); float signalx2 = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier * 2.0f); - return (mid*st->mono_volume) + (signalx1*st->pilot_volume) + ((side*signalx2) * st->stereo_volume); + return (mid*half_audio) + (signalx1*st->pilot_volume) + ((side*signalx2) * half_audio); } \ No newline at end of file diff --git a/modulation/stereo_encoder.h b/modulation/stereo_encoder.h index 58e4307..05e3ed1 100644 --- a/modulation/stereo_encoder.h +++ b/modulation/stereo_encoder.h @@ -7,11 +7,10 @@ typedef struct { uint8_t multiplier; Oscillator* osc; - float mono_volume; + float audio_volume; float pilot_volume; - float stereo_volume; } StereoEncoder; -void init_stereo_encoder(StereoEncoder *st, uint8_t multiplier, Oscillator *osc, float mono_volume, float pilot_volume, float stereo_volume); +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); diff --git a/src/fm95.c b/src/fm95.c index cdd3fed..e004338 100644 --- a/src/fm95.c +++ b/src/fm95.c @@ -34,9 +34,9 @@ typedef struct } FM95_Options; typedef struct { - float mono; + float audio; + float headroom; float pilot; - float stereo; float rds; float rds_step; } FM95_Volumes; @@ -111,7 +111,7 @@ bool compare_dvs(const FM95_DeviceNames *a, const FM95_DeviceNames *b) { float calculate_sharedaudio_volume(const FM95_Volumes volumes, const int rds_streams) { float rds_volume = volumes.rds * powf(volumes.rds_step, rds_streams); - return 1.0f - rds_volume - volumes.pilot - 0.1f; // Give 10% of headroom, for MPX maybe + return 1.0f - rds_volume - volumes.pilot - volumes.headroom; } static void stop(int signum) { @@ -358,6 +358,8 @@ static int config_handler(void* user, const char* section, const char* name, con pconfig->lpf_cutoff = (pconfig->sample_rate * 0.5); fprintf(stderr, "LPF cutoff over niquist, limiting.\n"); } + } else if(MATCH("advanced", "headroom")) { + pconfig->volumes.headroom = strtof(value, NULL); } else if(MATCH("volumes", "pilot")) { pconfig->volumes.pilot = strtof(value, NULL); } else if(MATCH("volumes", "rds")) { @@ -459,7 +461,7 @@ void init_runtime(FM95_Runtime* runtime, const FM95_Config config) { if(config.tilt != 0) tilt_init(&runtime->tilter, (float)config.tilt / 127.0f); - init_stereo_encoder(&runtime->stencode, 4.0f, &runtime->osc, config.volumes.mono, config.volumes.pilot, config.volumes.stereo); + init_stereo_encoder(&runtime->stencode, 4.0f, &runtime->osc, config.volumes.audio, config.volumes.pilot); if(config.agc_max != 0.0) { last_gain = 1.0f; @@ -471,12 +473,6 @@ void init_runtime(FM95_Runtime* runtime, const FM95_Config config) { if(config.options.rds_on) memset(runtime->rds_in, 0, sizeof(float) * BUFFER_SIZE * config.rds_streams); } -void compute_audio_volumes(FM95_Volumes* volumes, const FM95_Config config) { - float shared = calculate_sharedaudio_volume(*volumes, config.rds_streams); - if(config.stereo != 0) volumes->mono = volumes->stereo = (shared / 2.0f); - else volumes->mono = shared; -} - int main(int argc, char **argv) { printf("fm95 (an FM Processor by radio95) version 2.2\n"); @@ -484,7 +480,8 @@ int main(int argc, char **argv) { .volumes = { .pilot = DEFAULT_PILOT_VOLUME, .rds = DEFAULT_RDS_VOLUME, - .rds_step = DEFAULT_RDS_VOLUME_STEP + .rds_step = DEFAULT_RDS_VOLUME_STEP, + .headroom = 0.05f }, .stereo = 1, @@ -547,7 +544,7 @@ int main(int argc, char **argv) { config.master_volume *= config.audio_deviation/75000.0f; - compute_audio_volumes(&config.volumes, config); + config.volumes.audio = calculate_sharedaudio_volume(config.volumes, config.rds_streams); FM95_Runtime runtime; memset(&runtime, 0, sizeof(runtime)); @@ -576,7 +573,7 @@ int main(int argc, char **argv) { printf("Could not parse the config file. (error code as return code)\n"); return err; } - compute_audio_volumes(&config.volumes, config); + config.volumes.audio = calculate_sharedaudio_volume(config.volumes, config.rds_streams); if(!compare_dvs(&dv_names, &old_dv_names)) printf("Warning! Audio Device name changes are not reloaded, please restart for that to take effect.\n"); old_dv_names = dv_names; if(config.rds_streams != old_streams) printf("Warning! change of rds_streams requires a restart, not a reload.\n");