From 38f357183c53e51c3a7056a76ffb53e453ff96df Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Tue, 28 Apr 2026 20:20:36 +0200 Subject: [PATCH] fix order --- fm95.md | 4 ---- src/fm95.c | 19 ++++++++----------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/fm95.md b/fm95.md index af54c48..cd09fa9 100644 --- a/fm95.md +++ b/fm95.md @@ -23,10 +23,6 @@ Simple boolean, set to 0, or 1 Integer from 0 to 4, it sets how many channels to capture from RDS95, note that both values have to match, otherwise god may have mercy on your RDS decoders -### clipper_threshold - -Sets the peak to peak value of the Audio Clipper, defaults to one, but can be disabled by setting 0 - ### preemphasis Sets the Preemphasis tau, basically how much highs is boosted, by default and in Europe it is 50µs, but in the USA and South Korea, use 75µs. Expects unit in integer microseconds diff --git a/src/fm95.c b/src/fm95.c index b1e5429..a6eab02 100644 --- a/src/fm95.c +++ b/src/fm95.c @@ -26,6 +26,9 @@ static volatile sig_atomic_t to_run = 1; static volatile sig_atomic_t to_reload = 0; inline float hard_clip(float sample, float threshold) { return fmaxf(-threshold, fminf(threshold, sample)); } +static inline float soft_clip(float x) { + return tanhf(x); +} typedef struct { bool rds_on; @@ -47,7 +50,6 @@ typedef struct { uint8_t rds_streams; - float clipper_threshold; uint8_t preemphasis; uint8_t calibration; float mpx_power; @@ -212,23 +214,21 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) { r *= agc_gain; } - if (config.clipper_threshold != 0) { - l = hard_clip(l * config.audio_volume, config.clipper_threshold); - r = hard_clip(r * config.audio_volume, config.clipper_threshold); - } - float mod_l, mod_r; if(config.lpf_cutoff != 0) { 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); } + mod_l = soft_clip(mod_l); + mod_r = soft_clip(mod_r); + mpx = stereo_encode(&runtime->stencode, config.stereo, mod_l, mod_r, &audio); if(rds_on) { @@ -247,7 +247,7 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) { mpx = bs412_compress(&runtime->bs412, audio, mpx+mpx_in[i]); - output[i] = hard_clip(mpx, 1.0)*config.master_volume; // Ensure peak deviation of 75 khz (or the set deviation), assuming we're calibrated correctly + output[i] = hard_clip(soft_clip(mpx), 1.0)*config.master_volume; // Ensure peak deviation of 75 khz (or the set deviation), assuming we're calibrated correctly advance_oscillator(&runtime->osc); } @@ -313,8 +313,6 @@ static int config_handler(void* user, const char* section, const char* name, con printf("RDS Streams more than 4? Nuh uh\n"); return 0; } - } else if (MATCH("fm95", "clipper_threshold")) { - pconfig->clipper_threshold = strtof(value, NULL); } else if (MATCH("fm95", "preemphasis")) { pconfig->preemphasis = atoi(value); } else if (MATCH("fm95", "calibration")) { @@ -508,7 +506,6 @@ int main(int argc, char **argv) { .rds_streams = 1, // You have to match this with RDS95, otherwise may god have mercy on your RDS decoders - .clipper_threshold = 1.0f, // At what level for the clipper to work, 1.0f, clips the audio at 1 volt peak to peak, so it will be always between -1 and 1 .preemphasis = 50, // Europe, the "freedomers" use 75µs .calibration = 0, // Off .mpx_power = 3.0f, // dbr, this is for BS412, simplest bs412