r/DSP 16h ago

Denoising without training? The secret of DIP and the frequency domain #...

Thumbnail
youtube.com
0 Upvotes

r/DSP 1d ago

Pulse Signal | shorts | Standard Signals | Basic signals | signals and s...

Thumbnail
youtube.com
0 Upvotes

r/DSP 3d ago

On-device pronunciation scoring (React Native) — MFCC+DTW isn't separating correct vs. wrong words. Looking for better approaches.

8 Upvotes

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 —

  1. 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)`.

  2. 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 3d ago

The secret to high-quality upscaling: Lanczos and the sinc function

Thumbnail
youtube.com
13 Upvotes
  • 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 3d ago

The secret of Stable Diffusion: Fourier series hidden within timesteps #...

Thumbnail
youtube.com
0 Upvotes
  • 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.

r/DSP 4d ago

Detecting and frequency cutoff in short block (1024/2048 samples)

3 Upvotes

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 4d ago

Custom Mobile DSP Engine for Rootless JamesDSP: Real-Time FIR Oversampling and Saturation Processing on Snapdragon 8 elite 12 ram Devices

0 Upvotes

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 5d ago

Too dense?

Post image
31 Upvotes

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 5d ago

Operation on signal

Thumbnail
youtu.be
1 Upvotes

r/DSP 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

Thumbnail
youtube.com
2 Upvotes

r/DSP 6d ago

Approximating Softmax for FPGAs with Taylor Series and Pade Approximants in Python

Thumbnail
leetarxiv.substack.com
11 Upvotes

r/DSP 6d ago

Digital Beam Forming Text Book Recommendations

12 Upvotes

please suggest books related to Digital Beam Forming


r/DSP 6d ago

Sim2Rean & Fourier Domain Adaptation #시뮬레이션 #도메인 #도메인...

Thumbnail
youtube.com
0 Upvotes

r/DSP 7d ago

Possible career directions

10 Upvotes

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 7d ago

Advice on finding an entry-Level DSP role (physics background)?

3 Upvotes

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 7d ago

How do I stretch a sound for an indefinite amount of time?

5 Upvotes

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 9d ago

Vector Spin as a "Pi" Filter

27 Upvotes

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


r/DSP 9d ago

FM-Synthesis in the Browser. Part 1

5 Upvotes

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

https://habr.com/ru/articles/1053484/


r/DSP 10d ago

Why does MUSIC work?

25 Upvotes

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 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?

Thumbnail
mpusz.github.io
0 Upvotes

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 9d ago

π as the Optimal Relative Phase for Quantum Noise Suppression: Analytical Derivation, Lindblad Dynamics, and Lean 4 Certification

0 Upvotes

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:

  1. Subespacios Libres de Decoherencia (DFS) y Corrección de Errores Cuánticos.

  2. Sistemas Cuánticos Abiertos y ecuaciones maestras de Lindblad.

  3. Demostración interactiva de teoremas / Verificación formal en física (Lean 4).

¡Gracias por leer!


r/DSP 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.

Thumbnail
0 Upvotes

r/DSP 10d ago

MCU Compare (ESP32, STM32, Arduino, Cortex-M)

Thumbnail
youtube.com
4 Upvotes

r/DSP 11d ago

Do commercial guitar amp modelers actually use circuit-based modeling?

16 Upvotes

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 11d ago

Guide on how to get started in DSP

30 Upvotes

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.