mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 19:23:51 +01:00
add delay
This commit is contained in:
@@ -13,6 +13,9 @@ Also nearly no latency, not like Stereo Tool (or mpxgen which doesn't even work)
|
||||
|
||||
As far as i've tested it (29-31 december) it's been fine but after a fix it was great, so i'd redecommend you
|
||||
|
||||
# SSB-STCode
|
||||
This is a version of the stereo code but instead of DSB-SC it transmits some kind of VSG (mostly USB with a bit of LSB)
|
||||
|
||||
# SCAMod
|
||||
SCAMod is a simple FM modulator which can be used to modulate a secondary audio stream, has similiar cpu usage and latency as STCode
|
||||
|
||||
|
||||
@@ -38,4 +38,44 @@ float apply_low_pass_filter(LowPassFilter *lp, float sample) {
|
||||
index = (index + 1) % FIR_TAPS;
|
||||
}
|
||||
return result*6;
|
||||
}
|
||||
|
||||
void init_delay_line(DelayLine *delay_line, int max_delay) {
|
||||
delay_line->buffer = (float *)calloc(max_delay, sizeof(float));
|
||||
delay_line->size = max_delay;
|
||||
delay_line->write_idx = 0;
|
||||
delay_line->read_idx = 0;
|
||||
delay_line->delay = 0;
|
||||
}
|
||||
|
||||
void set_delay_line(DelayLine *delay_line, int new_delay) {
|
||||
if (new_delay >= delay_line->size) {
|
||||
new_delay = delay_line->size - 1;
|
||||
}
|
||||
if (new_delay < 0) {
|
||||
new_delay = 0;
|
||||
}
|
||||
|
||||
delay_line->delay = new_delay;
|
||||
delay_line->read_idx = (delay_line->write_idx - new_delay + delay_line->size) % delay_line->size;
|
||||
}
|
||||
|
||||
float delay_line(DelayLine *delay_line, float in) {
|
||||
float out;
|
||||
|
||||
// Read the delayed sample
|
||||
out = delay_line->buffer[delay_line->read_idx];
|
||||
|
||||
// Write the new sample
|
||||
delay_line->buffer[delay_line->write_idx] = in;
|
||||
|
||||
// Update indices
|
||||
delay_line->write_idx = (delay_line->write_idx + 1) % delay_line->size;
|
||||
delay_line->read_idx = (delay_line->read_idx + 1) % delay_line->size;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void exit_delay_line(DelayLine *delay_line) {
|
||||
free(delay_line->buffer);
|
||||
}
|
||||
@@ -20,4 +20,18 @@ typedef struct {
|
||||
} LowPassFilter;
|
||||
|
||||
void init_low_pass_filter(LowPassFilter *lp, float cutoff_frequency, float sample_rate);
|
||||
float apply_low_pass_filter(LowPassFilter *lp, float sample);
|
||||
float apply_low_pass_filter(LowPassFilter *lp, float sample);
|
||||
|
||||
|
||||
typedef struct {
|
||||
float *buffer;
|
||||
int write_idx; // Write position
|
||||
int read_idx; // Read position
|
||||
int size; // Total buffer size
|
||||
int delay; // Delay in samples
|
||||
} DelayLine;
|
||||
|
||||
void init_delay_line(DelayLine *delay_line, int max_delay);
|
||||
void set_delay_line(DelayLine *delay_line, int new_delay);
|
||||
float delay_line(DelayLine *delay_line, float in);
|
||||
void exit_delay_line(DelayLine *delay_line);
|
||||
@@ -60,7 +60,7 @@ static void stop(int signum) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("STCode : Stereo encoder made by radio95 (with help of ChatGPT and Claude, thanks!)\n");
|
||||
printf("SSB-STCode : Stereo encoder made by radio95 (with help of ChatGPT and Claude, thanks!)\n");
|
||||
// Define formats and buffer atributes
|
||||
pa_sample_spec stereo_format = {
|
||||
.format = PA_SAMPLE_FLOAT32NE, //Float32 NE, or Float32 Native Endian, the float in c uses the endianess of your pc, or native endian, and float is float32, and double is float64
|
||||
@@ -124,6 +124,8 @@ int main() {
|
||||
init_oscillator(&pilot_osc, 19000.0, SAMPLE_RATE); // Pilot, it's there to indicate stereo and as a refrence signal with the stereo carrier
|
||||
HilbertTransformer hilbert;
|
||||
init_hilbert(&hilbert);
|
||||
DelayLine monoDelay;
|
||||
init_delay_line(&monoDelay, 99);
|
||||
#ifdef PREEMPHASIS
|
||||
Emphasis preemp_l, preemp_r;
|
||||
init_emphasis(&preemp_l, PREEMPHASIS_TAU, SAMPLE_RATE);
|
||||
@@ -149,7 +151,7 @@ int main() {
|
||||
uninterleave(input, left, right, BUFFER_SIZE*2);
|
||||
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
float sin38 = sinf(pilot_osc.phase*2); // Stereo carrier should be a harmonic of the pilot which is in phase, best way to generate the harmonic is to multiply the pilot's phase by two, so it is mathematically impossible for them to not be in phase
|
||||
float sin38 = sinf(pilot_osc.phase*2);
|
||||
float cos38 = cosf(pilot_osc.phase*2); // Stereo carrier should be a harmonic of the pilot which is in phase, best way to generate the harmonic is to multiply the pilot's phase by two, so it is mathematically impossible for them to not be in phase
|
||||
float pilot = get_oscillator_sin_sample(&pilot_osc); // This is after because if it was before then the stereo would be out of phase by one increment, so [GET STEREO] ([GET PILOT] [INCREMENT PHASE])
|
||||
float l_in = left[i];
|
||||
@@ -186,9 +188,9 @@ int main() {
|
||||
float stereo = (current_left_input - current_right_input) / 2.0f; // Also Stereo to Mono but a bit diffrent
|
||||
float stereo_i, stereo_q;
|
||||
apply_hilbert(&hilbert, stereo, &stereo_i, &stereo_q);
|
||||
float lsb = (stereo_i*cos38-stereo_q*(sin38*0.75f));
|
||||
float lsb = (stereo_i*cos38-stereo_q*(sin38*0.7f));
|
||||
|
||||
mpx[i] = mono * MONO_VOLUME +
|
||||
mpx[i] = delay_line(&monoDelay, mono) * MONO_VOLUME +
|
||||
pilot * PILOT_VOLUME +
|
||||
lsb*STEREO_VOLUME;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user