mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 19:23:51 +01:00
nug fixes and small tweaks
This commit is contained in:
2
.vscode/.server-controller-port.log
vendored
2
.vscode/.server-controller-port.log
vendored
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"port": 13452,
|
"port": 13452,
|
||||||
"time": 1737972017853,
|
"time": 1738158496504,
|
||||||
"version": "0.0.3"
|
"version": "0.0.3"
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifndef PI
|
#ifndef M_PI
|
||||||
#define PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
#endif
|
#endif
|
||||||
#ifndef M_2PI
|
#ifndef M_2PI
|
||||||
#define M_2PI (3.14159265358979323846 * 2.0)
|
#define M_2PI (M_PI * 2.0)
|
||||||
#endif
|
#endif
|
||||||
@@ -25,11 +25,11 @@ void init_lpf(FrequencyFilter* filter, float cutoffFreq, float sampleRate) {
|
|||||||
float m = n - (FILTER_TAPS - 1.0f) / 2.0f;
|
float m = n - (FILTER_TAPS - 1.0f) / 2.0f;
|
||||||
|
|
||||||
// Sinc function
|
// Sinc function
|
||||||
float sinc = (m == 0) ? 1.0f : sinf(PI * m * fc) / (PI * m);
|
float sinc = (m == 0) ? 1.0f : sinf(M_PI * m * fc) / (M_PI * m);
|
||||||
|
|
||||||
// Blackman window
|
// Blackman window
|
||||||
float window = 0.42f - 0.5f * cosf(2.0f * PI * n / (FILTER_TAPS - 1))
|
float window = 0.42f - 0.5f * cosf(2.0f * M_PI * n / (FILTER_TAPS - 1))
|
||||||
+ 0.08f * cosf(4.0f * PI * n / (FILTER_TAPS - 1));
|
+ 0.08f * cosf(4.0f * M_PI * n / (FILTER_TAPS - 1));
|
||||||
|
|
||||||
filter->coeffs[n] = sinc * window;
|
filter->coeffs[n] = sinc * window;
|
||||||
}
|
}
|
||||||
@@ -53,11 +53,11 @@ void init_hpf(FrequencyFilter* filter, float cutoffFreq, float sampleRate) {
|
|||||||
float m = n - (FILTER_TAPS - 1.0f) / 2.0f;
|
float m = n - (FILTER_TAPS - 1.0f) / 2.0f;
|
||||||
|
|
||||||
// Sinc function
|
// Sinc function
|
||||||
float sinc = (m == 0) ? -1.0f : sinf(PI * m * fc) / (PI * m);
|
float sinc = (m == 0) ? 1.0f : -sinf(M_PI * m * fc) / (M_PI * m);
|
||||||
|
|
||||||
// Blackman window
|
// Blackman window
|
||||||
float window = 0.42f - 0.5f * cosf(2.0f * PI * n / (FILTER_TAPS - 1))
|
float window = 0.42f - 0.5f * cosf(2.0f * M_PI * n / (FILTER_TAPS - 1))
|
||||||
+ 0.08f * cosf(4.0f * PI * n / (FILTER_TAPS - 1));
|
+ 0.08f * cosf(4.0f * M_PI * n / (FILTER_TAPS - 1));
|
||||||
|
|
||||||
filter->coeffs[n] = sinc * window;
|
filter->coeffs[n] = sinc * window;
|
||||||
}
|
}
|
||||||
@@ -148,4 +148,5 @@ float delay_line(DelayLine *delay_line, float in) {
|
|||||||
|
|
||||||
void exit_delay_line(DelayLine *delay_line) {
|
void exit_delay_line(DelayLine *delay_line) {
|
||||||
free(delay_line->buffer);
|
free(delay_line->buffer);
|
||||||
|
delay_line->buffer = NULL;
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ void init_fm_modulator(FMModulator *fm, float frequency, float deviation, float
|
|||||||
|
|
||||||
float modulate_fm(FMModulator *fm, float sample) {
|
float modulate_fm(FMModulator *fm, float sample) {
|
||||||
float inst_freq = fm->frequency+(sample*fm->deviation);
|
float inst_freq = fm->frequency+(sample*fm->deviation);
|
||||||
|
if (inst_freq < 0.0f) inst_freq = 0.0f;
|
||||||
change_oscillator_frequency(&fm->osc, inst_freq);
|
change_oscillator_frequency(&fm->osc, inst_freq);
|
||||||
return get_oscillator_sin_sample(&fm->osc);
|
return get_oscillator_sin_sample(&fm->osc);
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ void compute_hilbert_coeffs(float* coeffs, int taps) {
|
|||||||
if ((i - mid) % 2 == 0) {
|
if ((i - mid) % 2 == 0) {
|
||||||
coeffs[i] = 0.0f;
|
coeffs[i] = 0.0f;
|
||||||
} else {
|
} else {
|
||||||
coeffs[i] = 2.0f / (PI * (i - mid));
|
coeffs[i] = 2.0f / (M_PI * (i - mid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,25 +12,23 @@ void change_oscillator_frequency(Oscillator *osc, float frequency) {
|
|||||||
|
|
||||||
float get_oscillator_sin_sample(Oscillator *osc) {
|
float get_oscillator_sin_sample(Oscillator *osc) {
|
||||||
float sample = sinf(osc->phase);
|
float sample = sinf(osc->phase);
|
||||||
osc->phase += osc->phase_increment;
|
advance_oscillator(osc);
|
||||||
if (osc->phase >= M_2PI) {
|
|
||||||
osc->phase -= M_2PI;
|
|
||||||
}
|
|
||||||
return sample;
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_oscillator_cos_sample(Oscillator *osc) {
|
float get_oscillator_cos_sample(Oscillator *osc) {
|
||||||
float sample = cosf(osc->phase);
|
float sample = cosf(osc->phase);
|
||||||
osc->phase += osc->phase_increment;
|
advance_oscillator(osc);
|
||||||
if (osc->phase >= M_2PI) {
|
|
||||||
osc->phase -= M_2PI;
|
|
||||||
}
|
|
||||||
return sample;
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_oscillator_sin_multiplier_ni(Oscillator *osc, float multiplier) {
|
float get_oscillator_sin_multiplier_ni(Oscillator *osc, float multiplier) { // ni = No Increment
|
||||||
return sinf(osc->phase*multiplier);
|
return sinf(osc->phase*multiplier);
|
||||||
}
|
}
|
||||||
float get_oscillator_cos_multiplier_ni(Oscillator *osc, float multiplier) {
|
float get_oscillator_cos_multiplier_ni(Oscillator *osc, float multiplier) {
|
||||||
return cosf(osc->phase*multiplier);
|
return cosf(osc->phase*multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void advance_oscillator(Oscillator *osc) {
|
||||||
|
osc->phase = fmodf(osc->phase + osc->phase_increment, M_2PI);
|
||||||
}
|
}
|
||||||
@@ -14,4 +14,5 @@ void change_oscillator_frequency(Oscillator *osc, float frequency);
|
|||||||
float get_oscillator_sin_sample(Oscillator *osc);
|
float get_oscillator_sin_sample(Oscillator *osc);
|
||||||
float get_oscillator_cos_sample(Oscillator *osc);
|
float get_oscillator_cos_sample(Oscillator *osc);
|
||||||
float get_oscillator_sin_multiplier_ni(Oscillator *osc, float multiplier);
|
float get_oscillator_sin_multiplier_ni(Oscillator *osc, float multiplier);
|
||||||
float get_oscillator_cos_multiplier_ni(Oscillator *osc, float multiplier);
|
float get_oscillator_cos_multiplier_ni(Oscillator *osc, float multiplier);
|
||||||
|
void advance_oscillator(Oscillator *osc);
|
||||||
65
src/fm95.c
65
src/fm95.c
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#define buffer_maxlength 12288
|
#define buffer_maxlength 12288
|
||||||
#define buffer_tlength_fragsize 12288
|
#define buffer_tlength_fragsize 12288
|
||||||
#define buffer_prebuf 16
|
#define buffer_prebuf 32
|
||||||
|
|
||||||
#define DEFAULT_STEREO 1
|
#define DEFAULT_STEREO 1
|
||||||
#define DEFAULT_STEREO_POLAR 0
|
#define DEFAULT_STEREO_POLAR 0
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
#define DEFAULT_ALSA_OUTPUT 1
|
#define DEFAULT_ALSA_OUTPUT 1
|
||||||
#define DEFAULT_SCA_FREQUENCY 67000.0f
|
#define DEFAULT_SCA_FREQUENCY 67000.0f
|
||||||
#define DEFAULT_SCA_DEVIATION 7000.0f
|
#define DEFAULT_SCA_DEVIATION 7000.0f
|
||||||
#define DEFAULT_SCA_CLIPPER_THRESHOLD 1.0f // Full deviation
|
#define DEFAULT_SCA_CLIPPER_THRESHOLD 1.0f // Full deviation, if you set this to 0.5 then you may as well set the deviation to 3.5k
|
||||||
#define DEFAULT_PREEMPHASIS_TAU 50e-6 // Europe
|
#define DEFAULT_PREEMPHASIS_TAU 50e-6 // Europe, the freedomers use 75µs
|
||||||
|
|
||||||
//#define USB
|
//#define USB
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
#include "../lib/hilbert.h"
|
#include "../lib/hilbert.h"
|
||||||
#include "../lib/fm_modulator.h"
|
#include "../lib/fm_modulator.h"
|
||||||
|
|
||||||
#define SAMPLE_RATE 192000 // Don't go lower than 108 KHz, becuase it (53000*2) and (38000+15000)
|
#define SAMPLE_RATE 192000
|
||||||
|
|
||||||
#define INPUT_DEVICE "FM_Audio.monitor"
|
#define INPUT_DEVICE "FM_Audio.monitor"
|
||||||
#define OUTPUT_DEVICE "plughw:1,0"
|
#define OUTPUT_DEVICE "plughw:1,0"
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
|
|
||||||
#define LPF_CUTOFF 15000 // Should't need to be changed
|
#define LPF_CUTOFF 15000 // Should't need to be changed
|
||||||
#define HPF_CUTOFF 30 // Unless you wanna have SOME bass then leave this alone
|
#define HPF_CUTOFF 30 // Unless you wanna have SOME bass then leave this alone
|
||||||
|
#define CENTER_BASS 50 // Bass upto this will be mono
|
||||||
|
|
||||||
volatile sig_atomic_t to_run = 1;
|
volatile sig_atomic_t to_run = 1;
|
||||||
|
|
||||||
@@ -398,7 +399,7 @@ int main(int argc, char **argv) {
|
|||||||
// #endregion
|
// #endregion
|
||||||
// #region Setup Filters/Modulaltors/Oscillators
|
// #region Setup Filters/Modulaltors/Oscillators
|
||||||
Oscillator osc;
|
Oscillator osc;
|
||||||
if(polar_stereo == 1) {
|
if(polar_stereo) {
|
||||||
init_oscillator(&osc, 31250.0, SAMPLE_RATE); // The stereo carrier itself, the stereo carrier in polar is modulated directly on 31.25 khz with a bit of a carrier
|
init_oscillator(&osc, 31250.0, SAMPLE_RATE); // The stereo carrier itself, the stereo carrier in polar is modulated directly on 31.25 khz with a bit of a carrier
|
||||||
} else {
|
} else {
|
||||||
init_oscillator(&osc, 19000.0, SAMPLE_RATE); // Pilot, it's there to indicate stereo and as a refrence signal with the stereo carrier
|
init_oscillator(&osc, 19000.0, SAMPLE_RATE); // Pilot, it's there to indicate stereo and as a refrence signal with the stereo carrier
|
||||||
@@ -423,6 +424,9 @@ int main(int argc, char **argv) {
|
|||||||
FrequencyFilter hpf_l, hpf_r;
|
FrequencyFilter hpf_l, hpf_r;
|
||||||
init_hpf(&hpf_l, HPF_CUTOFF, SAMPLE_RATE);
|
init_hpf(&hpf_l, HPF_CUTOFF, SAMPLE_RATE);
|
||||||
init_hpf(&hpf_r, HPF_CUTOFF, SAMPLE_RATE);
|
init_hpf(&hpf_r, HPF_CUTOFF, SAMPLE_RATE);
|
||||||
|
|
||||||
|
FrequencyFilter bass_hpf;
|
||||||
|
init_hpf(&bass_hpf, CENTER_BASS, SAMPLE_RATE);
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
signal(SIGINT, stop);
|
signal(SIGINT, stop);
|
||||||
@@ -477,54 +481,47 @@ int main(int argc, char **argv) {
|
|||||||
float mono = (ready_l + ready_r) / 2.0f; // Stereo to Mono
|
float mono = (ready_l + ready_r) / 2.0f; // Stereo to Mono
|
||||||
if(stereo == 1) {
|
if(stereo == 1) {
|
||||||
float stereo = (ready_l - ready_r) / 2.0f; // Also Stereo to Mono but a bit diffrent
|
float stereo = (ready_l - ready_r) / 2.0f; // Also Stereo to Mono but a bit diffrent
|
||||||
if(polar_stereo == 1) {
|
if(CENTER_BASS != 0) stereo = apply_frequency_filter(&bass_hpf, stereo);
|
||||||
if(ssb) {
|
|
||||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&osc, 1); // Get stereo carrier via multiplication
|
|
||||||
float stereo_carrier_cos = get_oscillator_cos_sample(&osc); // Get Carrier Q of I/Q
|
|
||||||
|
|
||||||
float stereo_i, stereo_q;
|
float stereo_i, stereo_q;
|
||||||
stereo += 0.2;
|
if(ssb) {
|
||||||
apply_hilbert(&hilbert, stereo, &stereo_i, &stereo_q); // Compute I/Q
|
// Compute hilbert here
|
||||||
output[i] = delay_line(&monoDelay, mono)*MONO_VOLUME +
|
apply_hilbert(&hilbert, stereo, &stereo_i, &stereo_q);
|
||||||
(stereo_i*stereo_carrier_cos+stereo_q*(stereo_carrier))*STEREO_VOLUME;
|
mono = delay_line(&monoDelay, mono); // Delay Mono
|
||||||
if(strlen(audio_mpx_device) != 0) output[i] += current_mpx_in*MPX_VOLUME;
|
}
|
||||||
if(strlen(audio_sca_device) != 0) output[i] += modulate_fm(&sca_mod, hard_clip(current_sca_in, sca_clipper_threshold))*SCA_VOLUME;
|
|
||||||
|
if(polar_stereo) {
|
||||||
|
float stereo_carrier = get_oscillator_sin_multiplier_ni(&osc, 1);
|
||||||
|
if(ssb) {
|
||||||
|
float stereo_carrier_cos = get_oscillator_cos_multiplier_ni(&osc, 1); // Get Carrier Q of I/Q
|
||||||
|
|
||||||
|
output[i] = mono*MONO_VOLUME +
|
||||||
|
((stereo_i+0.2)*stereo_carrier_cos+(stereo_q+0.2)*stereo_carrier)*STEREO_VOLUME;
|
||||||
} else {
|
} else {
|
||||||
float stereo_carrier = get_oscillator_sin_sample(&osc);
|
float stereo_carrier = get_oscillator_sin_multiplier_ni(&osc, 1);
|
||||||
output[i] = mono*MONO_VOLUME +
|
output[i] = mono*MONO_VOLUME +
|
||||||
((stereo+0.2)*stereo_carrier)*STEREO_VOLUME;
|
((stereo+0.2)*stereo_carrier)*STEREO_VOLUME;
|
||||||
if(strlen(audio_mpx_device) != 0) output[i] += current_mpx_in*MPX_VOLUME;
|
|
||||||
if(strlen(audio_sca_device) != 0) output[i] += modulate_fm(&sca_mod, hard_clip(current_sca_in, sca_clipper_threshold))*SCA_VOLUME;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
float stereo_carrier = get_oscillator_sin_multiplier_ni(&osc, 2); // Get stereo carrier via multiplication
|
||||||
|
float pilot = get_oscillator_sin_multiplier_ni(&osc, 1);
|
||||||
if(ssb) {
|
if(ssb) {
|
||||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&osc, 2); // Get stereo carrier via multiplication
|
|
||||||
float stereo_carrier_cos = get_oscillator_cos_multiplier_ni(&osc, 2); // Get Carrier Q of I/Q
|
float stereo_carrier_cos = get_oscillator_cos_multiplier_ni(&osc, 2); // Get Carrier Q of I/Q
|
||||||
float pilot = get_oscillator_sin_sample(&osc);
|
output[i] = mono*MONO_VOLUME +
|
||||||
|
|
||||||
float stereo_i, stereo_q;
|
|
||||||
apply_hilbert(&hilbert, stereo, &stereo_i, &stereo_q); // Compute I/Q
|
|
||||||
|
|
||||||
output[i] = delay_line(&monoDelay, mono)*MONO_VOLUME +
|
|
||||||
pilot*PILOT_VOLUME +
|
pilot*PILOT_VOLUME +
|
||||||
(stereo_i*stereo_carrier_cos+stereo_q*stereo_carrier)*STEREO_VOLUME;
|
(stereo_i*stereo_carrier_cos+stereo_q*stereo_carrier)*STEREO_VOLUME;
|
||||||
if(strlen(audio_mpx_device) != 0) output[i] += current_mpx_in*MPX_VOLUME;
|
|
||||||
if(strlen(audio_sca_device) != 0) output[i] += modulate_fm(&sca_mod, hard_clip(current_sca_in, sca_clipper_threshold))*SCA_VOLUME;
|
|
||||||
} else {
|
} else {
|
||||||
float stereo_carrier = get_oscillator_sin_multiplier_ni(&osc,2);
|
|
||||||
float pilot = get_oscillator_sin_sample(&osc);
|
|
||||||
output[i] = mono*MONO_VOLUME +
|
output[i] = mono*MONO_VOLUME +
|
||||||
pilot*PILOT_VOLUME +
|
pilot*PILOT_VOLUME +
|
||||||
(stereo*stereo_carrier)*STEREO_VOLUME;
|
(stereo*stereo_carrier)*STEREO_VOLUME;
|
||||||
if(strlen(audio_mpx_device) != 0) output[i] += current_mpx_in*MPX_VOLUME;
|
|
||||||
if(strlen(audio_sca_device) != 0) output[i] += modulate_fm(&sca_mod, hard_clip(current_sca_in, sca_clipper_threshold))*SCA_VOLUME;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
advance_oscillator(&osc);
|
||||||
} else {
|
} else {
|
||||||
output[i] = mono*MONO_VOLUME; // Only Mono
|
output[i] = mono*MONO_VOLUME; // Only Mono
|
||||||
if(strlen(audio_mpx_device) != 0) output[i] += current_mpx_in*MPX_VOLUME;
|
|
||||||
if(strlen(audio_sca_device) != 0) output[i] += modulate_fm(&sca_mod, hard_clip(current_sca_in, sca_clipper_threshold))*SCA_VOLUME;
|
|
||||||
}
|
}
|
||||||
|
if(strlen(audio_mpx_device) != 0) output[i] += current_mpx_in*MPX_VOLUME;
|
||||||
|
if(strlen(audio_sca_device) != 0) output[i] += modulate_fm(&sca_mod, hard_clip(current_sca_in, sca_clipper_threshold))*SCA_VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(alsa_output == 0) {
|
if(alsa_output == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user