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

change up the config stuff

This commit is contained in:
2025-06-28 18:32:01 +02:00
parent 26f9ccc0c7
commit 2091b87ea6
2 changed files with 32 additions and 31 deletions

View File

@@ -15,7 +15,7 @@ This section contains the core FM95 transmission parameters.
#### Audio Processing #### Audio Processing
- **`stereo`** (0 or 1, default: 0) - **`stereo`** (0 or 1, default: 0)
Enable stereo transmission. Set to 1 for stereo, 0 for mono. Enable stereo transmission. Set to 1 for stereo, 0 for mono. Or set to 2 for Polar Stereo
- **`audio_volume`** (float) - **`audio_volume`** (float)
Audio input volume multiplier. 1.0 = unity gain, values > 1.0 may cause distortion. Audio input volume multiplier. 1.0 = unity gain, values > 1.0 may cause distortion.
@@ -29,11 +29,6 @@ This section contains the core FM95 transmission parameters.
- **`preemphasis`** (float, microseconds) - **`preemphasis`** (float, microseconds)
Pre-emphasis time constant in microseconds. Common values: 50 (Europe), 75 (North America). Pre-emphasis time constant in microseconds. Common values: 50 (Europe), 75 (North America).
#### Stereo Processing
- **`polar_stereo`** (0 or 1, default: 0)
Enable polar stereo encoding.
#### RDS (Radio Data System) #### RDS (Radio Data System)
- **`rds_streams`** (integer, range: 1-4) - **`rds_streams`** (integer, range: 1-4)

View File

@@ -1,18 +1,14 @@
#include <getopt.h> #include <getopt.h>
#include <liquid/liquid.h> #include <liquid/liquid.h>
#include <stdbool.h>
#include "../inih/ini.h" #include "../inih/ini.h"
#define DEFAULT_INI_PATH "/etc/fm95.conf" #define DEFAULT_INI_PATH "/etc/fm95.conf"
#define LPF_ORDER 17
#define buffer_maxlength 12288 #define buffer_maxlength 12288
#define buffer_tlength_fragsize 12288 #define buffer_tlength_fragsize 12288
#define buffer_prebuf 8 #define buffer_prebuf 8
#define DEFAULT_STEREO 1 #define DEFAULT_STEREO 1
#define DEFAULT_STEREO_POLAR 0
#define DEFAULT_RDS_STREAMS 2 #define DEFAULT_RDS_STREAMS 2
#define DEFAULT_CLIPPER_THRESHOLD 1.0f #define DEFAULT_CLIPPER_THRESHOLD 1.0f
#define DEFAULT_PREEMPHASIS_TAU 50e-6 // Europe, the freedomers use 75µs (75e-6) #define DEFAULT_PREEMPHASIS_TAU 50e-6 // Europe, the freedomers use 75µs (75e-6)
@@ -53,8 +49,7 @@ inline float hard_clip(float sample, float threshold) { return fmaxf(-threshold,
typedef struct typedef struct
{ {
bool stereo; uint8_t stereo;
bool polar_stereo;
uint8_t rds_streams; uint8_t rds_streams;
@@ -70,6 +65,10 @@ typedef struct
// ini dont edit // ini dont edit
char ini_config_path[64]; char ini_config_path[64];
uint8_t lpf_order;
float preemp_unity_freq;
float agc_target;
} FM95_Config; } FM95_Config;
typedef struct typedef struct
@@ -139,27 +138,27 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) {
} }
Oscillator osc; Oscillator osc;
init_oscillator(&osc, config.polar_stereo ? 7812.5 : 4750, config.sample_rate); init_oscillator(&osc, (config.stereo == 2) ? 7812.5 : 4750, config.sample_rate);
iirfilt_rrrf lpf_l, lpf_r; iirfilt_rrrf lpf_l, lpf_r;
lpf_l = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, LPF_ORDER, (15000.0f/config.sample_rate), 0.0f, 1.0f, 60.0f); lpf_l = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, config.lpf_order, (15000.0f/config.sample_rate), 0.0f, 1.0f, 60.0f);
lpf_r = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, LPF_ORDER, (15000.0f/config.sample_rate), 0.0f, 1.0f, 60.0f); lpf_r = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, config.lpf_order, (15000.0f/config.sample_rate), 0.0f, 1.0f, 60.0f);
ResistorCapacitor preemp_l, preemp_r; ResistorCapacitor preemp_l, preemp_r;
init_preemphasis(&preemp_l, config.preemphasis, config.sample_rate, 15250.0f); init_preemphasis(&preemp_l, config.preemphasis, config.sample_rate, config.preemp_unity_freq);
init_preemphasis(&preemp_r, config.preemphasis, config.sample_rate, 15250.0f); init_preemphasis(&preemp_r, config.preemphasis, config.sample_rate, config.preemp_unity_freq);
MPXPowerMeasurement power; MPXPowerMeasurement power;
init_modulation_power_measure(&power, config.sample_rate); init_modulation_power_measure(&power, config.sample_rate);
StereoEncoder stencode; StereoEncoder stencode;
init_stereo_encoder(&stencode, 4.0f, &osc, config.polar_stereo, MONO_VOLUME, PILOT_VOLUME, STEREO_VOLUME); init_stereo_encoder(&stencode, 4.0f, &osc, (config.stereo == 2), MONO_VOLUME, PILOT_VOLUME, STEREO_VOLUME);
float bs412_audio_gain = 1.0f; float bs412_audio_gain = 1.0f;
AGC agc; AGC agc;
// fs target min max attack release // min max attack release
initAGC(&agc, config.sample_rate, 0.625f, 1.0f, 1.75f, 0.03f, 0.225f); initAGC(&agc, config.sample_rate, config.agc_target, 0.1f, 2.75f, 0.03f, 0.225f);
int pulse_error; int pulse_error;
@@ -179,15 +178,13 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) {
} }
if(mpx_on) { if(mpx_on) {
if((pulse_error = read_PulseInputDevice(&runtime->mpx_device, mpx_in, sizeof(mpx_in)))) { if((pulse_error = read_PulseInputDevice(&runtime->mpx_device, mpx_in, sizeof(mpx_in)))) {
fprintf(stderr, "Error reading from MPX device: %s\n", pa_strerror(pulse_error)); fprintf(stderr, "Error reading from MPX device: %s\nDisabling MPX.\n", pa_strerror(pulse_error));
fprintf(stderr, "Disabling MPX.\n");
mpx_on = 0; mpx_on = 0;
} }
} }
if(rds_on) { if(rds_on) {
if((pulse_error = read_PulseInputDevice(&runtime->rds_device, rds_in, sizeof(float) * BUFFER_SIZE * config.rds_streams))) { if((pulse_error = read_PulseInputDevice(&runtime->rds_device, rds_in, sizeof(float) * BUFFER_SIZE * config.rds_streams))) {
fprintf(stderr, "Error reading from RDS95 device: %s\n", pa_strerror(pulse_error)); fprintf(stderr, "Error reading from RDS95 device: %s\nDisabling RDS.\n", pa_strerror(pulse_error));
fprintf(stderr, "Disabling RDS.\n");
rds_on = 0; rds_on = 0;
} }
} }
@@ -209,7 +206,7 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) {
mpx = stereo_encode(&stencode, config.stereo, ready_l, ready_r); mpx = stereo_encode(&stencode, config.stereo, ready_l, ready_r);
if(rds_on && !config.polar_stereo) { if(rds_on && !(config.stereo == 2)) {
for(uint8_t stream = 0; stream < config.rds_streams; stream++) { for(uint8_t stream = 0; stream < config.rds_streams; stream++) {
uint8_t osc_stream = 12+stream; // If the osc is a 4750 sine wave, then doing this would mean that stream 0 is 12, so 57 khz uint8_t osc_stream = 12+stream; // If the osc is a 4750 sine wave, then doing this would mean that stream 0 is 12, so 57 khz
if(osc_stream == 13) osc_stream++; // 61.75 KHz is not used, idk why but would be cool if it was if(osc_stream == 13) osc_stream++; // 61.75 KHz is not used, idk why but would be cool if it was
@@ -229,7 +226,7 @@ int run_fm95(const FM95_Config config, FM95_Runtime* runtime) {
bs412_audio_gain = 0.8f * bs412_audio_gain + 0.2f * target_gain; bs412_audio_gain = 0.8f * bs412_audio_gain + 0.2f * target_gain;
} }
} else bs412_audio_gain = fminf(1.5f, bs412_audio_gain + 0.001f); } else bs412_audio_gain = fminf(3.5f, bs412_audio_gain + 0.001f);
mpx *= bs412_audio_gain; mpx *= bs412_audio_gain;
@@ -304,8 +301,6 @@ static int config_handler(void* user, const char* section, const char* name, con
} }
} else if (MATCH("fm95", "clipper_threshold")) { } else if (MATCH("fm95", "clipper_threshold")) {
pconfig->clipper_threshold = strtof(value, NULL); pconfig->clipper_threshold = strtof(value, NULL);
} else if (MATCH("fm95", "polar_stereo")) {
pconfig->polar_stereo = atoi(value);
} else if (MATCH("fm95", "preemphasis")) { } else if (MATCH("fm95", "preemphasis")) {
pconfig->preemphasis = strtof(value, NULL) * 1.0e-6f; pconfig->preemphasis = strtof(value, NULL) * 1.0e-6f;
} else if (MATCH("fm95", "calibration")) { } else if (MATCH("fm95", "calibration")) {
@@ -320,6 +315,14 @@ static int config_handler(void* user, const char* section, const char* name, con
pconfig->audio_volume = strtof(value, NULL); pconfig->audio_volume = strtof(value, NULL);
} else if (MATCH("fm95", "deviation")) { } else if (MATCH("fm95", "deviation")) {
pconfig->master_volume *= (strtof(value, NULL) / 75000.0f); pconfig->master_volume *= (strtof(value, NULL) / 75000.0f);
} else if(MATCH("advanced", "lpf_order")) {
pconfig->lpf_order = atoi(value);
} else if(MATCH("advanced", "preemp_unity")) {
pconfig->preemp_unity_freq = strtof(value, NULL);
} else if(MATCH("advanced", "sample_rate")) {
pconfig->sample_rate = atoi(value);
} else if(MATCH("advanced", "agc_target")) {
pconfig->agc_target = strtof(value, NULL);
} else { } else {
return 0; // Unknown section/name return 0; // Unknown section/name
} }
@@ -391,11 +394,10 @@ int setup_audio(FM95_Runtime* runtime, const FM95_DeviceNames dv_names, const FM
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
printf("fm95 (an FM Processor by radio95) version 2.1\n"); printf("fm95 (an FM Processor by radio95) version 2.2\n");
FM95_Config config = { FM95_Config config = {
.stereo = DEFAULT_STEREO, .stereo = DEFAULT_STEREO,
.polar_stereo = DEFAULT_STEREO_POLAR,
.rds_streams = DEFAULT_RDS_STREAMS, .rds_streams = DEFAULT_RDS_STREAMS,
@@ -409,7 +411,11 @@ int main(int argc, char **argv) {
.sample_rate = DEFAULT_SAMPLE_RATE, .sample_rate = DEFAULT_SAMPLE_RATE,
.ini_config_path = DEFAULT_INI_PATH .ini_config_path = DEFAULT_INI_PATH,
.lpf_order = 17,
.preemp_unity_freq = 15250.0f,
.agc_target = 0.625f
}; };
FM95_DeviceNames dv_names = { FM95_DeviceNames dv_names = {