From c111e8e6d6d33bc8c2d4dc5cdd4b21012c10d1fe Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Tue, 31 Dec 2024 22:41:32 +0100 Subject: [PATCH] add delay --- README.md | 3 +++ lib/filters.c | 40 ++++++++++++++++++++++++++++++++++++++++ lib/filters.h | 16 +++++++++++++++- src/ssb_stereo_coder.c | 10 ++++++---- 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c81703e..13300d2 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/lib/filters.c b/lib/filters.c index b5d0670..c32558d 100644 --- a/lib/filters.c +++ b/lib/filters.c @@ -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); } \ No newline at end of file diff --git a/lib/filters.h b/lib/filters.h index 853cb96..20f236e 100644 --- a/lib/filters.h +++ b/lib/filters.h @@ -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); \ No newline at end of file +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); \ No newline at end of file diff --git a/src/ssb_stereo_coder.c b/src/ssb_stereo_coder.c index 53cecb5..9e47a24 100644 --- a/src/ssb_stereo_coder.c +++ b/src/ssb_stereo_coder.c @@ -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; }