0
1
mirror of https://github.com/radio95-rnt/fm95.git synced 2026-02-26 19:23:51 +01:00

add headroom option

This commit is contained in:
2025-08-06 19:56:16 +02:00
parent 07bf22e3ff
commit 7350cbcf1e
5 changed files with 23 additions and 22 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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");