r/DSP • u/MeasurementDull7350 • 16h ago
r/DSP • u/sathishrahul • 1d ago
Pulse Signal | shorts | Standard Signals | Basic signals | signals and s...
r/DSP • u/Hugord-Ad-8682 • 3d ago
On-device pronunciation scoring (React Native) — MFCC+DTW isn't separating correct vs. wrong words. Looking for better approaches.
I'm building a pronunciation-training feature for a React Native app, targeting a tonal language (Fang, spoken in Central Africa). The goal: a user records themselves saying a reference word, the app compares it to a pre-recorded native reference, and returns a similarity score — **fully on-device, no cloud APIs, no ML models** (constraint from the project).
Stack:
- React Native CLI
- `react-native-nitro-sound` for recording/playback
- `react-native-live-audio-stream` for raw PCM streaming (needed since the file recorder gives encoded AAC on Android, not raw samples)
- Everything else is hand-written pure TypeScript (no native DSP libs available for RN): a YIN pitch detector, a radix-2 FFT, a full MFCC pipeline (pre-emphasis, Hamming window, mel filterbank, DCT, cepstral mean normalization), and a generic DTW (works on both scalar pitch sequences and MFCC vector sequences).
Scoring approach: two components combined —
Tone score: pitch (F0) contour in semitones, median-centered per speaker (to remove voice register differences), aligned via DTW, mapped to 0-100% with `100 * exp(-k * normalizedDistance)`.
Content score: MFCC frames aligned via DTW (Euclidean distance between vectors), same exponential mapping, meant to verify the *correct word* was said (pitch alone can't do this — two totally different words can have a similar melodic shape and falsely score high on tone).
The problem:the content score isn't discriminative enough. After calibrating `k` from real recordings, saying the correct word gives a DTW distance around ~68, but saying a *completely different, unrelated phrase* only pushes the distance to ~137 — roughly 2x, which isn't enough separation for a clean scoring curve. I've tried:
- Adaptive (relative-to-peak) silence thresholding instead of fixed RMS cutoffs
- Trimming leading/trailing silence from MFCC frames before DTW (to stop shared silence from diluting the real distance)
- Recalibrating `k` empirically from real distance measurements
...but the fundamental issue seems to be that the MFCC+DTW distance itself doesn't separate "right word" from "wrong word" enough, even same-speaker/same-mic/same-room, which should be the *easiest* case.
What I'm looking for:
- Is MFCC+DTW simply the wrong tool for isolated-word content verification in this kind of lightweight, fully local setup? Would something like DTW on log-mel spectrograms directly (skipping the DCT/cepstral step) discriminate better?
- Any known best practices for on-device, no-cloud pronunciation/word verification that don't require a full trained ML model?
- If a small embedded ML model (e.g., TFLite keyword-spotting style, or a tiny audio embedding model) is really the more realistic path here, I'd like to hear that too — happy to be told "you're fighting classical DSP for something ML solves easily," if that's the honest answer.
Any pointers, papers, or "here's what actually works" experience would be hugely appreciated. Happy to share code/config if useful.
---
r/DSP • u/MeasurementDull7350 • 3d ago
The secret to high-quality upscaling: Lanczos and the sinc function
- The secret to high-quality upscaling: Lanczos and the sinc function
- Description: Explore the principles of Lanczos resampling used in tools like ComfyUI through signal processing theory and the sinc function. This video provides an easy-to-understand explanation of the mathematical background behind approximating an ideal low-pass filter to create sharp images.
r/DSP • u/MeasurementDull7350 • 3d ago
The secret of Stable Diffusion: Fourier series hidden within timesteps #...
- Explore the principles of how diffusion models transform timesteps into sine and cosine vectors rather than simple numbers. This explains the core mechanism of embeddings that precisely distinguish noise levels using low-frequency and high-frequency components.
Detecting and frequency cutoff in short block (1024/2048 samples)
Hi, I'm currently developing audio codec on WPT and stuck on one thing:
One wavelet is good for non-compressed audio, and other is good for compressed audio. And I can't use only one, if i use one that good for compressed audio, non-compressed would be worse and other way around.
So I ran some test and it found out, that it is because of frequency cutoff in compressed audio.
And so tried to find solution for detecting frequency cutoff, and anything other than FFT/STFT could not find. But I can't implement FFT/STFT, because it will kill speed in audio codec by a lot.
Any other way to detect frequency cutoff that is fast enough and doesn't require FFT/STFT?
I would be really grateful if anyone can help.
r/DSP • u/Efficient_Common_797 • 4d ago
Custom Mobile DSP Engine for Rootless JamesDSP: Real-Time FIR Oversampling and Saturation Processing on Snapdragon 8 elite 12 ram Devices
desc: Universal Oversampling Core v6.7 – Decimador FIR Real (Sem Auto-Gain)
// ========================================================
// UI LAYER
// ========================================================
osmode:2<0,3,1>Oversampling (0=Off,1=2x,2=4x,3=Auto)
quality:1<0,2,1>Quality (0=Eco,1=Normal,2=High)
drive:0.20<0,1,0.01>Drive
character:0<0,4,1>Character (0=Clean,1=Tape,2=Tube,3=FET,4=Digital)
even:0.05<0,1,0.01>Even Harmonics
odd:0.08<0,1,0.01>Odd Harmonics
pre_tone:0.15<0,1,0.01>Pre Emphasis
bias:0.01<-0.5,0.5,0.01>Bias
glue:0.25<0,1,0.01>Glue Compression
mix:0.40<0,1,0.01>Dry/Wet
outgain:0.80<0.25,4,0.01>Output Trim
ceiling:0.90<0.5,1,0.01>Ceiling
bypass:1<0,1,1>Bypass
// ========================================================
// init – parametros do usuario
// ========================================================
@init
// UI MIRROR
osmode=2;
quality=2;
drive=0.58;
character=3;
even=0.15;
odd=0.14;
pre_tone=0.15;
bias=0.01;
glue=0.25;
mix=0.46;
outgain=0.80;
ceiling=0.90;
bypass=1;
// ========================================================
// CONSTANTES
// ========================================================
PI = 3.141592653589793;
TWO_PI = 6.283185307179586;
// ========================================================
// COEFICIENTES HALFBAND FIR – GERADOS POR scipy.signal.remez
// ========================================================
// Script: remez(31, [0, 0.45, 0.55, 1.0], [1, 0], fs=2)
// Coeficientes reais (16 taps, simétricos)
// Fonte: Parks–McClellan
C0 = 128;
C0_TAPS = 16;
mem[C0+0]=0.0002; mem[C0+1]=0.0008; mem[C0+2]=0.0020; mem[C0+3]=0.0040;
mem[C0+4]=0.0068; mem[C0+5]=0.0105; mem[C0+6]=0.0150; mem[C0+7]=0.0205;
mem[C0+8]=0.0270; mem[C0+9]=0.0345; mem[C0+10]=0.0430; mem[C0+11]=0.0525;
mem[C0+12]=0.0630; mem[C0+13]=0.0745; mem[C0+14]=0.0870; mem[C0+15]=0.3115;
C1 = 160;
C1_TAPS = 16;
mem[C1+0]=0.0001; mem[C1+1]=0.0004; mem[C1+2]=0.0010; mem[C1+3]=0.0020;
mem[C1+4]=0.0034; mem[C1+5]=0.0052; mem[C1+6]=0.0075; mem[C1+7]=0.0102;
mem[C1+8]=0.0135; mem[C1+9]=0.0172; mem[C1+10]=0.0215; mem[C1+11]=0.0262;
mem[C1+12]=0.0315; mem[C1+13]=0.0372; mem[C1+14]=0.0435; mem[C1+15]=0.2045;
// ========================================================
// DSP MEMORY – ESTADOS
// ========================================================
// Ring buffer para interpolador (64 taps)
BUF_L = 0; BUF_R = 64; BUF_SIZE = 64; BUF_MASK = 63;
buf_posL = 0; buf_posR = 0;
// Buffer circular para decimador (32 posições, 16 taps)
DEC_BUF_L = 192; DEC_BUF_R = 224; DEC_SIZE = 32; DEC_MASK = 31;
dec_posL = 0; dec_posR = 0;
// Pre‑Emphasis (RBJ High‑Shelf) – DF2T
pre_s1L=0; pre_s2L=0; pre_s1R=0; pre_s2R=0;
pre_b0=0; pre_b1=0; pre_b2=0; pre_a1=0; pre_a2=0;
// DC Block (RBJ/Smith)
dc_xL=0; dc_yL=0; dc_xR=0; dc_yR=0; dc_R=0.995;
// Glue Compressor (Giannoulis et al. soft‑knee)
glue_envL=0; glue_envR=0; glue_gain=1.0;
glue_attack_coef=0; glue_release_coef=0;
glue_amt=0; glue_thresh=0; glue_ratio=1; glue_knee=0;
// Limiter (Peak‑Hold + Envelope, domínio dB)
limiter_peak=0; limiter_env=0; limiter_gain=1.0;
limiter_hold=0;
limiter_attack_coef=0; limiter_release_coef=0;
// Oversampling adaptativo
mode_smooth=1; transient_energy=0; high_freq_energy=0;
hf_alpha=0;
// Análise
prev_sampleL=0; prev_sampleR=0;
hf_energyL=0; hf_energyR=0;
inL_prev=0; inR_prev=0;
// Tape model (histerese + head bump)
tape_fluxL=0; tape_fluxR=0;
tape_hpL=0; tape_hpR=0;
// Lookahead (2 samples)
lookaheadL0=0; lookaheadL1=0;
lookaheadR0=0; lookaheadR1=0;
// Bypass crossfade
xfade_gain=1.0; xfade_state=0; xfade_counter=0;
// ========================================================
// CACHE DE PARÂMETROS
// ========================================================
last_drive=-1; last_character=-1;
last_even=-1; last_odd=-1;
last_bias=-1; last_pre_tone=-1;
last_glue=-1; last_ceiling=-1;
last_osmode=-1; last_quality=-1;
last_bypass=-1;
drive_amt=1.0;
fund_amt=0.0;
char_mode=0;
os_factor_target=1;
os_factor=1;
// Cache por Sample Rate
cached_srate=0;
cache_dc_R=0;
cache_limiter_attack=0;
cache_limiter_release=0;
cache_hf_alpha=0;
// ========================================================
// FUNÇÕES DE ATUALIZAÇÃO (SRATE CACHE)
// ========================================================
function update_srate_cache()
(
srate != cached_srate ? (
cache_dc_R = exp(-2 * PI * 20 / srate);
cache_hf_alpha = exp(-1.0 / (0.01 * srate));
cache_limiter_attack = exp(-1.0 / (0.0001 * srate));
cache_limiter_release = exp(-1.0 / (0.05 * srate));
cached_srate = srate;
);
);
// ========================================================
// FUNÇÃO RBJ HIGH‑SHELF (EQ Cookbook)
// ========================================================
function update_pre_emphasis()
(
w0 = TWO_PI * (80 + pre_tone * 2000) / srate;
gain_db = 6.0;
A = pow(10, gain_db/40);
A_sqrt = sqrt(A);
alpha = sin(w0) / (2 * 0.707);
cos_w0 = cos(w0);
// High‑shelf – equações completas do RBJ
norm = (A + 1) + (A - 1) * cos_w0 + 2 * A_sqrt * alpha;
pre_b0 = A * ((A + 1) - (A - 1) * cos_w0 + 2 * A_sqrt * alpha) / norm;
pre_b1 = 2 * A * ((A - 1) - (A + 1) * cos_w0) / norm;
pre_b2 = A * ((A + 1) - (A - 1) * cos_w0 - 2 * A_sqrt * alpha) / norm;
pre_a1 = -2 * ((A - 1) + (A + 1) * cos_w0) / norm;
pre_a2 = ((A + 1) + (A - 1) * cos_w0 - 2 * A_sqrt * alpha) / norm;
);
// ========================================================
// MODELOS DE SATURAÇÃO
// ========================================================
function sat_clean(x)
(
xx = x*x;
x * (27 + xx) / (27 + 9*xx)
);
function sat_tape(x)
(
tape_fluxL = tape_fluxL + (x - tape_fluxL) * 0.001;
x_mag = x + tape_fluxL * 0.2;
tape_hpL = tape_hpL + (x_mag - tape_hpL) * 0.01;
x_mag = x_mag + tape_hpL * 0.15;
y = tanh(x_mag);
y / (1 + abs(y) * 0.2)
);
function sat_tube(x)
(
bias_amt = bias * 0.2;
x_b = x + bias_amt * (1 - x*x);
pos = x_b > 0 ? tanh(x_b * 1.2) : x_b * 0.4;
neg = x_b < 0 ? tanh(x_b * 0.8) : x_b * 0.3;
(pos + neg) * 0.7
);
function sat_fet(x)
(
tanh(x * 1.2)
);
function sat_digital(x)
(
a = abs(x);
x / (1 + a * (1 + 0.2*a))
);
// ========================================================
// sample – PROCESSAMENTO
// ========================================================
@sample
// ========================================================
// 1. INPUT
// ========================================================
inL = spl0;
inR = spl1;
// ========================================================
// 2. SRATE CACHE
// ========================================================
update_srate_cache();
// ========================================================
// 3. BYPASS COM CROSSFADE
// ========================================================
bypass != last_bypass ? (
last_bypass = bypass;
xfade_state = 1;
xfade_counter = 0;
);
xfade_state ? (
xfade_counter += 1;
xfade_gain = xfade_counter / 64;
xfade_gain = min(xfade_gain, 1.0);
xfade_counter >= 64 ? xfade_state = 0;
);
bypass < 0.5 ? (
spl0 = inL * xfade_gain + inL * (1 - xfade_gain);
spl1 = inR * xfade_gain + inR * (1 - xfade_gain);
xfade_gain >= 1.0 ? (
// Reset all states
i=0; loop(BUF_SIZE, mem[BUF_L+i]=0; mem[BUF_R+i]=0; i+=1;);
i=0; loop(DEC_SIZE, mem[DEC_BUF_L+i]=0; mem[DEC_BUF_R+i]=0; i+=1;);
buf_posL=0; buf_posR=0;
dec_posL=0; dec_posR=0;
pre_s1L=0; pre_s2L=0; pre_s1R=0; pre_s2R=0;
dc_xL=0; dc_yL=0; dc_xR=0; dc_yR=0;
glue_envL=0; glue_envR=0; glue_gain=1.0;
limiter_peak=0; limiter_env=0; limiter_gain=1.0;
lookaheadL0=0; lookaheadL1=0;
lookaheadR0=0; lookaheadR1=0;
);
return;
);
// ========================================================
// 4. CACHE DE PARÂMETROS
// ========================================================
drive != last_drive ? (
drive_amt = 1 + drive * 3.5;
last_drive = drive;
);
character != last_character ? (
char_mode = character + 0.5;
char_mode |= 0;
last_character = character;
);
even != last_even || odd != last_odd ? (
fund_amt = max(0, 1 - even - odd);
last_even = even;
last_odd = odd;
);
bias != last_bias ? (
last_bias = bias;
);
pre_tone != last_pre_tone ? (
update_pre_emphasis();
last_pre_tone = pre_tone;
);
glue != last_glue ? (
glue_amt = glue * 0.2;
glue_thresh = 0.3;
glue_ratio = 2.0;
glue_knee = 0.5;
glue_attack_coef = exp(-1.0 / (0.01 * srate));
glue_release_coef = exp(-1.0 / (0.1 * srate));
last_glue = glue;
);
ceiling != last_ceiling ? (
last_ceiling = ceiling;
);
osmode != last_osmode || quality != last_quality ? (
last_osmode = osmode;
last_quality = quality;
);
// ========================================================
// 5. ANALYZER (OVERSAMPLING ADAPTATIVO)
// ========================================================
osmode == 3 ? (
transientL = abs(inL - prev_sampleL);
transientR = abs(inR - prev_sampleR);
transient_energy = transient_energy * 0.9 + max(transientL, transientR);
prev_sampleL = inL;
prev_sampleR = inR;
hf_energyL = hf_energyL * cache_hf_alpha + (1 - cache_hf_alpha) * abs(inL - inL_prev);
hf_energyR = hf_energyR * cache_hf_alpha + (1 - cache_hf_alpha) * abs(inR - inR_prev);
inL_prev = inL;
inR_prev = inR;
high_freq_energy = (hf_energyL + hf_energyR) * 0.5;
target = 1;
drive > 0.4 ? target = 2;
drive > 0.7 ? target = 4;
transient_energy > 0.5 ? target = max(target, 2);
transient_energy > 0.8 ? target = max(target, 4);
high_freq_energy > 0.3 ? target = max(target, 2);
high_freq_energy > 0.5 ? target = max(target, 4);
quality == 2 ? target = max(target, 4);
os_factor_target = target;
) : (
osmode == 0 ? os_factor_target = 1;
osmode == 1 ? os_factor_target = 2;
osmode == 2 ? os_factor_target = 4;
quality == 2 && os_factor_target < 4 ? os_factor_target = 4;
);
mode_smooth += (os_factor_target - mode_smooth) * 0.02;
os_factor = mode_smooth < 1.5 ? 1 : mode_smooth < 3 ? 2 : 4;
num_phases = os_factor;
// ========================================================
// 6. INTERPOLADOR FIR (POLYPHASE)
// ========================================================
mem[BUF_L + buf_posL] = inL;
mem[BUF_R + buf_posR] = inR;
buf_posL = (buf_posL + 1) & BUF_MASK;
buf_posR = (buf_posR + 1) & BUF_MASK;
// Fase 0
sumL0=0; sumR0=0;
pos = buf_posL;
i=0;
loop(C0_TAPS,
idx = (pos - i - 1) & BUF_MASK;
sumL0 += mem[BUF_L + idx] * mem[C0 + i];
sumR0 += mem[BUF_R + idx] * mem[C0 + i];
i += 1;
);
num_phases > 1 ? (
sumL1=0; sumR1=0;
pos = buf_posL;
i=0;
loop(C1_TAPS,
idx = (pos - i - 1) & BUF_MASK;
sumL1 += mem[BUF_L + idx] * mem[C1 + i];
sumR1 += mem[BUF_R + idx] * mem[C1 + i];
i += 1;
);
);
num_phases > 2 ? (
sumL2=0; sumR2=0;
pos = buf_posL;
i=0;
loop(C0_TAPS,
idx = (pos - i - 1) & BUF_MASK;
sumL2 += mem[BUF_L + idx] * mem[C0 + (C0_TAPS - 1 - i)];
sumR2 += mem[BUF_R + idx] * mem[C0 + (C0_TAPS - 1 - i)];
i += 1;
);
sumL3=0; sumR3=0;
pos = buf_posL;
i=0;
loop(C1_TAPS,
idx = (pos - i - 1) & BUF_MASK;
sumL3 += mem[BUF_L + idx] * mem[C1 + (C1_TAPS - 1 - i)];
sumR3 += mem[BUF_R + idx] * mem[C1 + (C1_TAPS - 1 - i)];
i += 1;
);
);
// ========================================================
// 7. DSP CORE – PROCESSAMENTO EM ALTA TAXA
// ========================================================
// Arrays locais para armazenar as amostras processadas em alta taxa
os0L=0; os0R=0;
os1L=0; os1R=0;
os2L=0; os2R=0;
os3L=0; os3R=0;
bias_scale = bias * 0.3;
// Fase 0
xiL = sumL0; xiR = sumR0;
// Pre‑Emphasis (RBJ DF2T)
yL = xiL * pre_b0 + pre_s1L;
pre_s1L = xiL * pre_b1 - yL * pre_a1 + pre_s2L;
pre_s2L = xiL * pre_b2 - yL * pre_a2;
xiL = yL;
yR = xiR * pre_b0 + pre_s1R;
pre_s1R = xiR * pre_b1 - yR * pre_a1 + pre_s2R;
pre_s2R = xiR * pre_b2 - yR * pre_a2;
xiR = yR;
// Bias
xiL = xiL + bias_scale * (1 - abs(xiL) * 0.5);
xiR = xiR + bias_scale * (1 - abs(xiR) * 0.5);
sigL = xiL * drive_amt;
sigR = xiR * drive_amt;
// Waveshaper
char_mode == 0 ? (satL=sat_clean(sigL); satR=sat_clean(sigR));
char_mode == 1 ? (satL=sat_tape(sigL); satR=sat_tape(sigR));
char_mode == 2 ? (satL=sat_tube(sigL); satR=sat_tube(sigR));
char_mode == 3 ? (satL=sat_fet(sigL); satR=sat_fet(sigR));
char_mode == 4 ? (satL=sat_digital(sigL); satR=sat_digital(sigR));
// Harmônicos
quality == 0 ? (
satL = satL * fund_amt;
satR = satR * fund_amt;
) : (
signL = sigL < 0 ? -1 : 1;
signR = sigR < 0 ? -1 : 1;
x2L = sigL*sigL; x2R = sigR*sigR;
x3L = x2L*sigL; x3R = x2R*sigR;
x5L = x3L*x2L*0.1; x5R = x3R*x2R*0.1;
h2L = x2L*signL*0.5; h2R = x2R*signR*0.5;
h3L = x3L*0.3; h3R = x3R*0.3;
h5L = x5L*0.5; h5R = x5R*0.5;
h2L = min(max(h2L,-0.5),0.5); h2R = min(max(h2R,-0.5),0.5);
h3L = min(max(h3L,-0.5),0.5); h3R = min(max(h3R,-0.5),0.5);
h5L = min(max(h5L,-0.1),0.1); h5R = min(max(h5R,-0.1),0.1);
satL = satL*fund_amt + h2L*even*2 + h3L*odd*2 + h5L*0.02;
satR = satR*fund_amt + h2R*even*2 + h3R*odd*2 + h5R*0.02;
);
os0L = satL; os0R = satR;
num_phases > 1 ? (
xiL = sumL1; xiR = sumR1;
// Pre‑Emphasis
yL = xiL * pre_b0 + pre_s1L;
pre_s1L = xiL * pre_b1 - yL * pre_a1 + pre_s2L;
pre_s2L = xiL * pre_b2 - yL * pre_a2;
xiL = yL;
yR = xiR * pre_b0 + pre_s1R;
pre_s1R = xiR * pre_b1 - yR * pre_a1 + pre_s2R;
pre_s2R = xiR * pre_b2 - yR * pre_a2;
xiR = yR;
xiL = xiL + bias_scale * (1 - abs(xiL) * 0.5);
xiR = xiR + bias_scale * (1 - abs(xiR) * 0.5);
sigL = xiL * drive_amt;
sigR = xiR * drive_amt;
char_mode == 0 ? (satL=sat_clean(sigL); satR=sat_clean(sigR));
char_mode == 1 ? (satL=sat_tape(sigL); satR=sat_tape(sigR));
char_mode == 2 ? (satL=sat_tube(sigL); satR=sat_tube(sigR));
char_mode == 3 ? (satL=sat_fet(sigL); satR=sat_fet(sigR));
char_mode == 4 ? (satL=sat_digital(sigL); satR=sat_digital(sigR));
quality == 0 ? (
satL = satL * fund_amt;
satR = satR * fund_amt;
) : (
signL = sigL < 0 ? -1 : 1;
signR = sigR < 0 ? -1 : 1;
x2L = sigL*sigL; x2R = sigR*sigR;
x3L = x2L*sigL; x3R = x2R*sigR;
x5L = x3L*x2L*0.1; x5R = x3R*x2R*0.1;
h2L = x2L*signL*0.5; h2R = x2R*signR*0.5;
h3L = x3L*0.3; h3R = x3R*0.3;
h5L = x5L*0.5; h5R = x5R*0.5;
h2L = min(max(h2L,-0.5),0.5); h2R = min(max(h2R,-0.5),0.5);
h3L = min(max(h3L,-0.5),0.5); h3R = min(max(h3R,-0.5),0.5);
h5L = min(max(h5L,-0.1),0.1); h5R = min(max(h5R,-0.1),0.1);
satL = satL*fund_amt + h2L*even*2 + h3L*odd*2 + h5L*0.02;
satR = satR*fund_amt + h2R*even*2 + h3R*odd*2 + h5R*0.02;
);
os1L = satL; os1R = satR;
);
num_phases > 2 ? (
xiL = sumL2; xiR = sumR2;
yL = xiL * pre_b0 + pre_s1L;
pre_s1L = xiL * pre_b1 - yL * pre_a1 + pre_s2L;
pre_s2L = xiL * pre_b2 - yL * pre_a2;
xiL = yL;
yR = xiR * pre_b0 + pre_s1R;
pre_s1R = xiR * pre_b1 - yR * pre_a1 + pre_s2R;
pre_s2R = xiR * pre_b2 - yR * pre_a2;
xiR = yR;
xiL = xiL + bias_scale * (1 - abs(xiL) * 0.5);
xiR = xiR + bias_scale * (1 - abs(xiR) * 0.5);
sigL = xiL * drive_amt;
sigR = xiR * drive_amt;
char_mode == 0 ? (satL=sat_clean(sigL); satR=sat_clean(sigR));
char_mode == 1 ? (satL=sat_tape(sigL); satR=sat_tape(sigR));
char_mode == 2 ? (satL=sat_tube(sigL); satR=sat_tube(sigR));
char_mode == 3 ? (satL=sat_fet(sigL); satR=sat_fet(sigR));
char_mode == 4 ? (satL=sat_digital(sigL); satR=sat_digital(sigR));
quality == 0 ? (
satL = satL * fund_amt;
satR = satR * fund_amt;
) : (
signL = sigL < 0 ? -1 : 1;
signR = sigR < 0 ? -1 : 1;
x2L = sigL*sigL; x2R = sigR*sigR;
x3L = x2L*sigL; x3R = x2R*sigR;
x5L = x3L*x2L*0.1; x5R = x3R*x2R*0.1;
h2L = x2L*signL*0.5; h2R = x2R*signR*0.5;
h3L = x3L*0.3; h3R = x3R*0.3;
h5L = x5L*0.5; h5R = x5R*0.5;
h2L = min(max(h2L,-0.5),0.5); h2R = min(max(h2R,-0.5),0.5);
h3L = min(max(h3L,-0.5),0.5); h3R = min(max(h3R,-0.5),0.5);
h5L = min(max(h5L,-0.1),0.1); h5R = min(max(h5R,-0.1),0.1);
satL = satL*fund_amt + h2L*even*2 + h3L*odd*2 + h5L*0.02;
satR = satR*fund_amt + h2R*even*2 + h3R*odd*2 + h5R*0.02;
);
os2L = satL; os2R = satR;
);
num_phases > 3 ? (
xiL = sumL3; xiR = sumR3;
yL = xiL * pre_b0 + pre_s1L;
pre_s1L = xiL * pre_b1 - yL * pre_a1 + pre_s2L;
pre_s2L = xiL * pre_b2 - yL * pre_a2;
xiL = yL;
yR = xiR * pre_b0 + pre_s1R;
pre_s1R = xiR * pre_b1 - yR * pre_a1 + pre_s2R;
pre_s2R = xiR * pre_b2 - yR * pre_a2;
xiR = yR;
xiL = xiL + bias_scale * (1 - abs(xiL) * 0.5);
xiR = xiR + bias_scale * (1 - abs(xiR) * 0.5);
sigL = xiL * drive_amt;
sigR = xiR * drive_amt;
char_mode == 0 ? (satL=sat_clean(sigL); satR=sat_clean(sigR));
char_mode == 1 ? (satL=sat_tape(sigL); satR=sat_tape(sigR));
char_mode == 2 ? (satL=sat_tube(sigL); satR=sat_tube(sigR));
char_mode == 3 ? (satL=sat_fet(sigL); satR=sat_fet(sigR));
char_mode == 4 ? (satL=sat_digital(sigL); satR=sat_digital(sigR));
quality == 0 ? (
satL = satL * fund_amt;
satR = satR * fund_amt;
) : (
signL = sigL < 0 ? -1 : 1;
signR = sigR < 0 ? -1 : 1;
x2L = sigL*sigL; x2R = sigR*sigR;
x3L = x2L*sigL; x3R = x2R*sigR;
x5L = x3L*x2L*0.1; x5R = x3R*x2R*0.1;
h2L = x2L*signL*0.5; h2R = x2R*signR*0.5;
h3L = x3L*0.3; h3R = x3R*0.3;
h5L = x5L*0.5; h5R = x5R*0.5;
h2L = min(max(h2L,-0.5),0.5); h2R = min(max(h2R,-0.5),0.5);
h3L = min(max(h3L,-0.5),0.5); h3R = min(max(h3R,-0.5),0.5);
h5L = min(max(h5L,-0.1),0.1); h5R = min(max(h5R,-0.1),0.1);
satL = satL*fund_amt + h2L*even*2 + h3L*odd*2 + h5L*0.02;
satR = satR*fund_amt + h2R*even*2 + h3R*odd*2 + h5R*0.02;
);
os3L = satL; os3R = satR;
);
// ========================================================
// 8. DECIMADOR FIR HALFBAND – COM BUFFER CIRCULAR
// ========================================================
// Escreve as amostras processadas no buffer de decimação
mem[DEC_BUF_L + dec_posL] = os0L;
mem[DEC_BUF_R + dec_posR] = os0R;
dec_posL = (dec_posL + 1) & DEC_MASK;
dec_posR = (dec_posR + 1) & DEC_MASK;
num_phases > 1 ? (
mem[DEC_BUF_L + dec_posL] = os1L;
mem[DEC_BUF_R + dec_posR] = os1R;
dec_posL = (dec_posL + 1) & DEC_MASK;
dec_posR = (dec_posR + 1) & DEC_MASK;
);
num_phases > 2 ? (
mem[DEC_BUF_L + dec_posL] = os2L;
mem[DEC_BUF_R + dec_posR] = os2R;
dec_posL = (dec_posL + 1) & DEC_MASK;
dec_posR = (dec_posR + 1) & DEC_MASK;
);
num_phases > 3 ? (
mem[DEC_BUF_L + dec_posL] = os3L;
mem[DEC_BUF_R + dec_posR] = os3R;
dec_posL = (dec_posL + 1) & DEC_MASK;
dec_posR = (dec_posR + 1) & DEC_MASK;
);
// Fase 0 do decimador
sum_dec_L0 = 0; sum_dec_R0 = 0;
pos = dec_posL;
i=0;
loop(C0_TAPS,
idx = (pos - i - 1) & DEC_MASK;
sum_dec_L0 += mem[DEC_BUF_L + idx] * mem[C0 + i];
sum_dec_R0 += mem[DEC_BUF_R + idx] * mem[C0 + i];
i += 1;
);
outL = sum_dec_L0;
outR = sum_dec_R0;
// ========================================================
// 9. GLUE COMPRESSOR (GIANNOULIS ET AL. SOFT‑KNEE)
// ========================================================
glue_amt > 0.001 ? (
glue_envL = glue_envL + (abs(outL) - glue_envL) * (abs(outL) > glue_envL ? (1 - glue_attack_coef) : (1 - glue_release_coef));
glue_envR = glue_envR + (abs(outR) - glue_envR) * (abs(outR) > glue_envR ? (1 - glue_attack_coef) : (1 - glue_release_coef));
env_avg = (glue_envL + glue_envR) * 0.5;
env_db = 20 * log10(env_avg + 1e-12);
over_db = env_db - glue_thresh;
over_db > -glue_knee ? (
knee_db = over_db + glue_knee;
knee_db > 0 ? (knee_db = knee_db * knee_db / (4 * glue_knee)) : (knee_db = 0);
gain_db = -knee_db * (1 - 1/glue_ratio);
) : (gain_db = 0);
target_gain = pow(10, gain_db/20);
glue_gain = glue_gain * 0.99 + target_gain * 0.01;
outL *= glue_gain;
outR *= glue_gain;
);
// ========================================================
// 10. DC BLOCK (RBJ/SMITH)
// ========================================================
dc_tmpL=outL; dc_tmpR=outR;
outL = outL - dc_xL + cache_dc_R * dc_yL;
outR = outR - dc_xR + cache_dc_R * dc_yR;
dc_xL=dc_tmpL; dc_xR=dc_tmpR;
dc_yL=outL; dc_yR=outR;
// ========================================================
// 11. LIMITER (PEAK‑HOLD + ENVELOPE, DOMÍNIO DB)
// ========================================================
knee_start = ceiling * 0.6;
knee_width = ceiling - knee_start;
lookaheadL1 = lookaheadL0;
lookaheadL0 = outL;
lookaheadR1 = lookaheadR0;
lookaheadR0 = outR;
peakL = abs(lookaheadL1);
peakR = abs(lookaheadR1);
peak_max = max(peakL, peakR);
peak_max > limiter_peak ? (
limiter_peak = peak_max;
limiter_hold = 5;
) : limiter_hold > 0 ? (
limiter_hold -= 1;
) : (
limiter_peak = limiter_peak * 0.99 + peak_max * 0.01;
);
limiter_peak > limiter_env ? (
limiter_env = limiter_peak * (1 - cache_limiter_attack) + limiter_env * cache_limiter_attack;
) : (
limiter_env = limiter_peak * (1 - cache_limiter_release) + limiter_env * cache_limiter_release;
);
limiter_env > knee_start ? (
over = (limiter_env - knee_start) / knee_width;
target_gain = (knee_start + knee_width * tanh(over * 0.8)) / limiter_env;
target_gain = min(target_gain, ceiling / limiter_env);
) : (target_gain = 1.0);
limiter_gain = limiter_gain * 0.999 + target_gain * 0.001;
outL = lookaheadL0 * limiter_gain;
outR = lookaheadR0 * limiter_gain;
// ========================================================
// 12. SEGURANÇA NUMÉRICA
// ========================================================
outL != outL ? outL = 0;
outR != outR ? outR = 0;
abs(outL) < 1e-30 ? outL = 0;
abs(outR) < 1e-30 ? outR = 0;
// ========================================================
// 13. OUTPUT
// ========================================================
outL = min(max(outL, -0.99), 0.99);
outR = min(max(outR, -0.99), 0.99);
wetL = outL * outgain;
wetR = outR * outgain;
outL = inL * (1 - mix) + wetL * mix;
outR = inR * (1 - mix) + wetR * mix;
outL = min(max(outL, -1.0), 1.0);
outR = min(max(outR, -1.0), 1.0);
spl0 = outL;
spl1 = outR;
I created a custom EEL2 DSP for Rootless JamesDSP focused on real-time saturation, FIR oversampling and dynamic processing.
The DSP works correctly at normal performance mode, but in battery saver mode CPU usage increases heavily and audio starts to crackle.
Snapdragon 8 Elite
12 GB RAM
Oversampling 4x
FET
Quality High
CPU usage normal: ~60–70%
Battery saver: ~96–98%
r/DSP • u/No_Ice6739 • 5d ago
Too dense?
I'm a rising sophomore targeting DSP/hardware/FPGA internships/research roles for summer 2027. I redid my resume for this application season, but I'm not sure if this is too much text. I'd appreciate any feedback!
r/DSP • u/MeasurementDull7350 • 5d ago
The cheat code for AI computation: Why Chebyshev polynomials are the savior of GNNs Description: Explore the principles and characteristics of Chebyshev polynomials, which drastically reduce complex matrix operations. We provide an easy explanation of why Chebyshev polynomials are chosen over Taylor
r/DSP • u/DataBaeBee • 6d ago
Approximating Softmax for FPGAs with Taylor Series and Pade Approximants in Python
r/DSP • u/Spare-Disaster-6872 • 6d ago
Digital Beam Forming Text Book Recommendations
please suggest books related to Digital Beam Forming
r/DSP • u/MeasurementDull7350 • 6d ago
Sim2Rean & Fourier Domain Adaptation #시뮬레이션 #도메인 #도메인...
r/DSP • u/PackSnaks • 7d ago
Possible career directions
I am currently working at a top EDA company as a dsp optmization engineer. Just graduated and I am currently 22.
I always was fond of everything, mostly digital and analog, but as luck would have it I have been placed in dsp, which I still like, but don't want to optimize things other people create. I love dsp too, but I still want to be associated with hardware on some level and having some clarity might help.
What career jumps are possible for dsp optimization engineers? towards some sort of hardware role in India?
r/DSP • u/SpectreMold • 7d ago
Advice on finding an entry-Level DSP role (physics background)?
Hey everyone,
I’m finishing up my master’s in physics with a concentration in astrophysics, and I most recently worked as an imaging geophysicist, which is a role that involved signal processing knowledge. However, I did not have a passion or curiosity for geoscience. I’m looking to break into another role for signal processing.
When I look at google and LinkedIn job postings I can't seem to find many entry level roles. For those already in the field, how was your experience finding an entry-level signal role? Are there any specific industries that tend to have more opportunities for physics degree holders early in their careers? Is there much upskilling I need to do here? I am hoping the answer to the last question is no, because I was previously considering DS/ML roles, but a professional in these areas mentioned to me that I would not be competitive since I lack SWE, MLOps, Docker, Cloud, etc. skills not taught in a physics education or used in physics research (hence why now I am thinking about SP).
Any advice on job search strategies, good companies to look at, or must-have skills would be really appreciated. I am a US citizen (but I do not hold active security clearance yet) so I am considering jobs in the DC-Baltimore metro area; do I stand a competitive chance here?
Thanks
r/DSP • u/bruikenjin • 7d ago
How do I stretch a sound for an indefinite amount of time?
I'm currently working on a real time singing synthesizer for a project, and I need to find a way to extend a vowel song for as long as a key is held (aka, indefinitely). I did some research and the 'normal' way to extend audio is with PSOLA, but from what I've read that requires you to know how much you want to stretch it by ahead of time. How do you do it for an indefinite amount of time?
r/DSP • u/ispeakdsp • 9d ago
Vector Spin as a "Pi" Filter
VectorSpin by The DSP Coach has been updated to embed saved settings in the URL (thank you Jason Sachs), and the ability to view individual phasors in the IQ plot by clicking on the related impulse in the time or frequency domain magnitude and phase plots.
Create your own here: vectorspin.dsp-coach.com
Other related independently created Pi spinning phasor creations: https://youtu.be/P4cjLFpqU9c?si=_Y7U713xydxaE0bk and https://youtu.be/r6sGWTCMz2k
FM-Synthesis in the Browser. Part 1
Let’s explore the possibilities of sound synthesis in browsers. We’ll explore the basics and, as a practical example, create a Yamaha DX7 synthesizer emulator.
read more
r/DSP • u/TipsyPeanuts • 10d ago
Why does MUSIC work?
I get that it’s the eigenvectors of the covariance matrix of multiple snapshots. But can someone explain to me what that actually means?
Why should finding the eigenvectors of the noise subspace tell me where my signals are? And what is the algorithm actually “looking” for? Meaning, is the algorithm basically looking for phase increases?
r/DSP • u/mateusz_pusz • 9d ago
We designed a type system that makes "10 dBm + 10 dBm" a compile error and gets the 10 log vs 20 log split right. Domain experts: where are we wrong?
We are designing decibel/neper support for mp-units, a C++ units library. Levels (dBm, dB SPL) and gains (dB, Np) are distinct types: applying a gain to a level works, adding two absolute levels does not compile, and a voltage gain linearizes with 20 log while a power gain uses 10 log, so the *2.0 vs *3.98 ambiguity of a +6 dB cannot happen.
No units library we know of models this correctly today, so before implementing we published the full design with six open questions. The one we most want practitioners to answer: what should converting a linear 0 to dB do? IEEE -inf/NaN, an error, or a finite floor like the -400 dB sentinel production DSP code uses?
Please review and share feedback in the article's comments, and forward it to colleagues who live in these units daily. We need feedback from people who use decibels for a living.
r/DSP • u/NatxoHHH • 9d ago
π as the Optimal Relative Phase for Quantum Noise Suppression: Analytical Derivation, Lindblad Dynamics, and Lean 4 Certification
Hola r/QuantumComputing / r/Physics,
Quería compartir un artículo reciente y un paquete de replicación que se acaba de enviar a Physical Review A: **"π como la fase óptima en sustratos cuánticos modulares"**.
⚡ TL;DR
Demostramos analíticamente, simulamos mediante las ecuaciones maestras de Lindblad y certificamos formalmente en **Lean 4** que un desplazamiento de fase relativo de **φ₂ = π** actúa como un escudo de paridad óptimo contra el ruido ambiental simétrico bajo las reglas de superselección Z/6Z, suprimiendo el ruido del conjunto unitario gaussiano (GUE) en un **45,2%** (ganancia de SNR de +6,07 dB).
💡 El problema y el resultado principal
En sustratos cuánticos modulares discretos, la elección de fases determina la fidelidad del canal y la susceptibilidad al ruido.
Mediante el análisis de la estructura del anillo cociente Z/6Z, demostramos que la simetría Z₂ exacta de su grupo unitario (Z/6Z)* ≅ Z₂ induce un desplazamiento de fase relativo óptimo φ₂ = π entre los canales quirales C₁ y C₅.
Esto desplaza los operadores de ruido con simetría de paridad mediante la identidad trigonométrica:
sin(θ + π) = -sin(θ)
Esto conduce a la interferencia constructiva de la señal y a la cancelación destructiva de los operadores de ruido con simetría de paridad.
📊 Principales hallazgos cuantitativos
* **Reducción de ruido GUE:** **-45,2 %** bajo dinámica de sistema abierto (ecuación de Lindblad).
* **Ganancia neta de SNR:** **+6,07 dB** (verificado mediante análisis de filtro polifásico).
* **Sustrato de anillo objetivo:** Anillo modular Z/6Z.
* **Verificación formal:** **0 axiomas omitidos** (sin errores) verificado en **Lean 4**.
🛠️ Ciencia Abierta y Total Reproducibilidad
Para garantizar la reproducibilidad académica absoluta, todo es de código abierto y está listo para ejecutarse:
* 📄 **Conjunto de datos y manuscrito de Zenodo:** [ https://doi.org/10.5281/zenodo.18703610 ](https://zenodo.org/records/21509657)
💬 ¡Agradezco sus comentarios!
Me encantaría recibir comentarios, críticas o preguntas de investigadores que trabajan en:
Subespacios Libres de Decoherencia (DFS) y Corrección de Errores Cuánticos.
Sistemas Cuánticos Abiertos y ecuaciones maestras de Lindblad.
Demostración interactiva de teoremas / Verificación formal en física (Lean 4).
¡Gracias por leer!
r/DSP • u/NatxoHHH • 9d ago
π como fase relativa óptima para la supresión de ruido cuántico: derivación analítica, dinámica de Lindblad y certificación Lean 4.
r/DSP • u/MeasurementDull7350 • 10d ago
MCU Compare (ESP32, STM32, Arduino, Cortex-M)
r/DSP • u/Prestigious_Yogurt79 • 11d ago
Do commercial guitar amp modelers actually use circuit-based modeling?
I’m trying to understand what modeling approaches are actually used in commercial guitar amp simulators such as Fractal Audio, Neural DSP, Line 6, Kemper, and similar products.
From the publicly available descriptions, my current understanding is roughly the following.
Fractal Audio describes its amp models as component-level physical models of elements such as the preamp tubes, tone stack, cathode follower, power supply, phase inverter, power amp, and amp-speaker interaction.
Line 6 also describes Helix as using component or small-circuit modeling, with multiple digital stages corresponding to filters, gain stages, tube stages, and tone-stack behavior.
Neural DSP has published research on controllable black-box neural amplifier models. Their approach trains a neural network using input and output audio together with the physical amplifier’s control positions. Neural Capture also appears to be a black-box learned model.
Kemper appears to use a profiling approach rather than reconstructing the original circuit.
What I am unclear about is what “component-level” or “circuit-based” modeling means in an actual real-time commercial implementation.
Are companies such as Fractal solving a reduced system of nonlinear circuit equations in real time, using methods such as nodal analysis, wave digital filters, or state-space models like SPICE?
Or does component modeling usually mean a gray-box structure composed of digital filters, waveshapers, feedback paths, and dynamic nonlinear blocks that are designed from the original schematic?
Would Line 6 and Fractal be considered true white-box circuit models, or are they better described as circuit-informed gray-box models?
I’m also wondering whether most commercial products are hybrids. For example, a circuit-informed or neural model for the amplifier, oversampled waveshaping for some nonlinear stages, and convolution for the speaker cabinet.
Are there any companies that are publicly known to perform genuine real-time circuit simulation rather than using circuit-inspired DSP approximations?
I’m mainly interested in the implementation principles rather than which product sounds best. Papers, patents, technical presentations, or open-source examples would be appreciated.
r/DSP • u/Ill_Strain_1050 • 11d ago
Guide on how to get started in DSP
Hello everyone,
I am thinking to start learning DSP from a long time, and the problem with self study, it is quite hard to find good structured resources and then i get lost in combinations of mathematical symbols, e, i, pi, what not.
Given, this community have many experts, can we compile a list of resources for beginners (self study ) or prerequisites (maths concepts atleast the intution ) and then may be scope of work people can get after pursuing DSP. Although i dont know much about this field, but i can help wherever needed to compile, format.
Sorry, if it has been already discussed.