mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 11:22:00 +01:00
start modularization
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -35,7 +35,8 @@
|
||||
"cdecl.h": "c",
|
||||
"algorithm": "c",
|
||||
"socket.h": "c",
|
||||
"time.h": "c"
|
||||
"time.h": "c",
|
||||
"vban.h": "c"
|
||||
},
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
}
|
||||
@@ -12,13 +12,19 @@ endif()
|
||||
|
||||
file(GLOB SRC_FILES "src/*.c")
|
||||
|
||||
file(GLOB DSP_FILES "dsp/*.c")
|
||||
# file(GLOB LIB_FILES "lib/*.c")
|
||||
|
||||
file(GLOB LIB_FILES "lib/*.c")
|
||||
file(GLOB FILTER_FILES "filter/*.c")
|
||||
file(GLOB MODULATION_FILES "modulation/*.c")
|
||||
|
||||
file(GLOB DSP_FILES "dsp/*.c")
|
||||
|
||||
file(GLOB IO_FILES "io/*.c")
|
||||
|
||||
add_library(libfm OBJECT ${LIB_FILES})
|
||||
# add_library(libfm OBJECT ${LIB_FILES})
|
||||
|
||||
add_library(libfmfilter OBJECT ${FILTER_FILES})
|
||||
add_library(libfmmodulation OBJECT ${MODULATION_FILES})
|
||||
|
||||
add_library(libfmdsp OBJECT ${DSP_FILES})
|
||||
|
||||
@@ -26,12 +32,14 @@ add_library(libfmio OBJECT ${IO_FILES})
|
||||
|
||||
# Define DEBUG macro for Debug builds on libraries
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_definitions(libfm PRIVATE DEBUG=1)
|
||||
# target_compile_definitions(libfm PRIVATE DEBUG=1)
|
||||
target_compile_definitions(libfmfilter PRIVATE DEBUG=1)
|
||||
target_compile_definitions(libfmmodulation PRIVATE DEBUG=1)
|
||||
target_compile_definitions(libfmdsp PRIVATE DEBUG=1)
|
||||
target_compile_definitions(libfmio PRIVATE DEBUG=1)
|
||||
endif()
|
||||
|
||||
set(FM_LIBS libfm libfmio libfmdsp pulse pulse-simple m liquid)
|
||||
set(FM_LIBS libfmfilter libfmmodulation libfmio libfmdsp pulse pulse-simple m liquid)
|
||||
|
||||
foreach(SRC_FILE ${SRC_FILES})
|
||||
get_filename_component(EXEC_NAME ${SRC_FILE} NAME_WE)
|
||||
|
||||
@@ -13,8 +13,7 @@ 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)
|
||||
- RDS (via Pulse, expects unmodulated RDS, stereo, left channel on 57 KHz, right on 66.5, rds95 is recommended here, in modulation this is inphase to the pilot)
|
||||
- RDS2 (via Pulse, expects unmodulated RDS, stereo, left channel on 71.25 KHz, rigth on 76 KHz)
|
||||
- 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)
|
||||
- SCA (via Pulse, by default on 67 khz with a 7 khz deviation)
|
||||
|
||||
and one output:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "constants.h"
|
||||
#include "../lib/constants.h"
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "filters.h"
|
||||
#include "iir.h"
|
||||
|
||||
void init_preemphasis(ResistorCapacitor *filter, float tau, float sample_rate, float ref_freq) {
|
||||
float dt = 1.0f / sample_rate;
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
#include "../lib/optimization.h"
|
||||
#include "../lib/constants.h"
|
||||
|
||||
typedef struct
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../lib/oscillator.h"
|
||||
#include "../dsp/oscillator.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
26
modulation/stereo_encoder.c
Normal file
26
modulation/stereo_encoder.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "stereo_encoder.h"
|
||||
|
||||
// Multiplier is the multiplier to get to 19 khz, or 31.25 if polar
|
||||
void init_stereo_encoder(StereoEncoder* st, uint8_t multiplier, Oscillator* osc, uint8_t polar, float mono_volume, float pilot_volume, float stereo_volume) {
|
||||
st->multiplier = multiplier;
|
||||
st->osc = osc;
|
||||
st->polar = polar;
|
||||
st->mono_volume = mono_volume;
|
||||
st->pilot_volume = pilot_volume;
|
||||
st->stereo_volume = stereo_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;
|
||||
float side = (left-right) * 0.5f;
|
||||
|
||||
if(!st->polar) {
|
||||
float pilot = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier);
|
||||
float carrier = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier * 2.0f);
|
||||
return (mid*st->mono_volume) + (pilot*st->pilot_volume) + ((side*carrier) * st->stereo_volume);
|
||||
} else {
|
||||
float carrier = get_oscillator_sin_multiplier_ni(st->osc, st->multiplier);
|
||||
return (mid*st->mono_volume) + (((side+0.2f)*carrier) * st->stereo_volume); // Polar stereo does not contain a pilot, but it contains a -14 db carrier wave on the stereo subcarrier
|
||||
}
|
||||
}
|
||||
18
modulation/stereo_encoder.h
Normal file
18
modulation/stereo_encoder.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../dsp/oscillator.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t multiplier;
|
||||
Oscillator* osc;
|
||||
uint8_t polar;
|
||||
float mono_volume;
|
||||
float pilot_volume;
|
||||
float stereo_volume;
|
||||
} StereoEncoder;
|
||||
|
||||
void init_stereo_encoder(StereoEncoder *st, uint8_t multiplier, Oscillator *osc, uint8_t polar, float mono_volume, float pilot_volume, float stereo_volume);
|
||||
|
||||
float stereo_encode(StereoEncoder* st, uint8_t enabled, float left, float right);
|
||||
@@ -8,7 +8,7 @@
|
||||
#define buffer_tlength_fragsize 1024
|
||||
#define buffer_prebuf 0
|
||||
|
||||
#include "../lib/oscillator.h"
|
||||
#include "../dsp/oscillator.h"
|
||||
#include "../lib/optimization.h"
|
||||
|
||||
#define DEFAULT_FREQ 1000.0f
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
// #define DEBUG
|
||||
|
||||
#include "../lib/oscillator.h"
|
||||
#include "../dsp/oscillator.h"
|
||||
|
||||
#define DEFAULT_FREQ 77500.0f
|
||||
#define DEFAULT_SAMPLE_RATE 192000
|
||||
|
||||
43
src/fm95.c
43
src/fm95.c
@@ -19,12 +19,13 @@
|
||||
#define DEFAULT_MPX_DEVIATION 75000.0f // for BS412
|
||||
#define DEFAULT_DEVIATION 75000.0f // another way to set the volume
|
||||
|
||||
#include "../lib/oscillator.h"
|
||||
#include "../dsp/filters.h"
|
||||
#include "../dsp/fm_modulator.h"
|
||||
#include "../dsp/oscillator.h"
|
||||
#include "../filter/iir.h"
|
||||
#include "../modulation/fm_modulator.h"
|
||||
#include "../modulation/stereo_encoder.h"
|
||||
#include "../lib/optimization.h"
|
||||
#include "../dsp/bs412.h"
|
||||
#include "../dsp/gain_control.h"
|
||||
#include "../filter/bs412.h"
|
||||
#include "../filter/gain_control.h"
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 192000
|
||||
|
||||
@@ -343,18 +344,19 @@ int main(int argc, char **argv) {
|
||||
FMModulator sca_mod;
|
||||
init_fm_modulator(&sca_mod, sca_frequency, sca_deviation, sample_rate);
|
||||
|
||||
iirfilt_rrrf lpf_l, lpf_r, mpx_lpf;
|
||||
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/sample_rate), 0.0f, 1.0f, 40.0f);
|
||||
lpf_r = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, LPF_ORDER, (15000.0f/sample_rate), 0.0f, 1.0f, 40.0f);
|
||||
mpx_lpf = iirfilt_rrrf_create_prototype(LIQUID_IIRDES_BUTTER, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, 1, (polar_stereo ? (46250.0f/sample_rate) : (53000.0f/sample_rate)), 0.0f, 1.0f, 1.0f);
|
||||
|
||||
ResistorCapacitor preemp_l, preemp_r;
|
||||
init_preemphasis(&preemp_l, preemphasis_tau, sample_rate, 15250.0f);
|
||||
init_preemphasis(&preemp_r, preemphasis_tau, sample_rate, 15250.0f);
|
||||
|
||||
MPXPowerMeasurement power, mpx_only_power;
|
||||
MPXPowerMeasurement power;
|
||||
init_modulation_power_measure(&power, sample_rate);
|
||||
init_modulation_power_measure(&mpx_only_power, sample_rate);
|
||||
|
||||
StereoEncoder stencode;
|
||||
init_stereo_encoder(&stencode, 4.0f, &osc, polar_stereo, MONO_VOLUME, PILOT_VOLUME, STEREO_VOLUME);
|
||||
|
||||
float bs412_audio_gain = 1.0f;
|
||||
|
||||
@@ -410,7 +412,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
for (uint16_t i = 0; i < BUFFER_SIZE; i++) {
|
||||
float mpx = 0.0f;
|
||||
float audio = 0.0f;
|
||||
|
||||
float ready_l = apply_preemphasis(&preemp_l, audio_stereo_input[2*i+0]);
|
||||
float ready_r = apply_preemphasis(&preemp_r, audio_stereo_input[2*i+1]);
|
||||
@@ -424,20 +425,8 @@ int main(int argc, char **argv) {
|
||||
ready_l = hard_clip(ready_l*audio_volume, clipper_threshold);
|
||||
ready_r = hard_clip(ready_r*audio_volume, clipper_threshold);
|
||||
|
||||
float mid = (ready_l + ready_r) * 0.5f;
|
||||
float side = (ready_l - ready_r) * 0.5f;
|
||||
mpx = stereo_encode(&stencode, stereo, ready_l, ready_r);
|
||||
|
||||
audio = mid*MONO_VOLUME;
|
||||
if(stereo) {
|
||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&osc, 8); // 31.25 or 38 KHz
|
||||
|
||||
if(polar_stereo) audio += ((side+0.2)*stereo_carrier)*STEREO_VOLUME; // 0.2 in polar stereo because it also includes a carrier wave, so we add a carrier wave via DC
|
||||
else {
|
||||
float pilot = get_oscillator_sin_multiplier_ni(&osc, 4); // 19 KHz
|
||||
mpx += pilot*PILOT_VOLUME;
|
||||
audio += (side*stereo_carrier)*STEREO_VOLUME;
|
||||
}
|
||||
}
|
||||
if(rds_on && !polar_stereo) {
|
||||
for(uint8_t stream = 0; stream < rds_streams; stream++) {
|
||||
uint8_t osc_stream = 12+stream;
|
||||
@@ -448,11 +437,9 @@ int main(int argc, char **argv) {
|
||||
if(mpx_on) mpx += mpx_in[i];
|
||||
if(sca_on) mpx += modulate_fm(&sca_mod, hard_clip(sca_in[i], sca_clipper_threshold))*SCA_VOLUME;
|
||||
|
||||
float mpxonly_power = measure_mpx(&mpx_only_power, mpx * mpx_deviation);
|
||||
float mpx_power = measure_mpx(&power, (audio+mpx) * mpx_deviation); // Standard requires that the output is measured specifically
|
||||
float mpx_power = measure_mpx(&power, mpx * mpx_deviation);
|
||||
if (mpx_power > max_mpx_power) {
|
||||
float excess_power = mpx_power - max_mpx_power;
|
||||
excess_power = deviation_to_dbr(dbr_to_deviation(excess_power) - dbr_to_deviation(mpxonly_power));
|
||||
|
||||
if (excess_power > 0.0f && excess_power < 10.0f) {
|
||||
float target_gain = dbr_to_deviation(-excess_power) / mpx_deviation;
|
||||
@@ -466,9 +453,8 @@ int main(int argc, char **argv) {
|
||||
bs412_audio_gain = fminf(1.0f, bs412_audio_gain + 0.001f);
|
||||
}
|
||||
|
||||
audio *= bs412_audio_gain;
|
||||
mpx *= bs412_audio_gain;
|
||||
|
||||
iirfilt_rrrf_execute(mpx_lpf, audio, &audio); // Should have no effect, as audio should be 0-15, and 23-53, this is a filter for 53, assuming the filter is good, this is precaution and recomendation
|
||||
audio = hard_clip(audio, 1.0f-mpx); // Prevent clipping, via clipping the audio signal with relation to the mpx signal
|
||||
|
||||
output[i] = hard_clip((audio+mpx), 1.0f)*master_volume; // Ensure peak deviation of 75 khz, assuming we're calibrated correctly
|
||||
@@ -485,7 +471,6 @@ int main(int argc, char **argv) {
|
||||
printf("Cleaning up...\n");
|
||||
iirfilt_rrrf_destroy(lpf_l);
|
||||
iirfilt_rrrf_destroy(lpf_r);
|
||||
iirfilt_rrrf_destroy(mpx_lpf);
|
||||
|
||||
free_PulseInputDevice(&input_device);
|
||||
if(mpx_on) free_PulseInputDevice(&mpx_device);
|
||||
|
||||
Reference in New Issue
Block a user