Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per channel EQ and time alignment #187

Open
Switchleg1 opened this issue Nov 13, 2023 · 8 comments
Open

Per channel EQ and time alignment #187

Switchleg1 opened this issue Nov 13, 2023 · 8 comments

Comments

@Switchleg1
Copy link

Hello,

First of all thank you for taking the time to develop this application, much appreciated! I was hoping to implement an EQ per channel for ppl that want to EQ a car for off axis response and time alignment. Taken care of the GUI and string encoding/decoding and working through the library now. In the meantime I have been using this dsp script if anyone is interested:

desc: My EQ

//delay
slider1:0<0,3,0.1>Left Delay (ms)
slider2:0<0,3,0.1>Right Delay (ms)

//eq
slider10:0<-18,3,0.5>Left 250hz
slider11:0<-18,3,0.5>Left 450hz
slider12:0<-18,3,0.5>Left 900hz
slider13:0<-18,3,0.5>Left 1500hz
slider14:0<-18,3,0.5>Left 2000hz
slider15:0<-18,3,0.5>Left 3000hz
slider16:0<-18,3,0.5>Left 6000hz
slider17:0<-18,3,0.5>Left 12000hz

slider20:0<-18,3,0.5>Right 250hz
slider21:0<-18,3,0.5>Right 450hz
slider22:0<-18,3,0.5>Right 900hz
slider23:0<-18,3,0.5>Right 1500hz
slider24:0<-18,3,0.5>Right 2000hz
slider25:0<-18,3,0.5>Right 3000hz
slider26:0<-18,3,0.5>Right 6000hz
slider27:0<-18,3,0.5>Right 12000hz

@init
//delay
slider1 = 0;
slider2 = 0;

delaylen_l = (slider1 * srate * 0.001 * 2)|0;
delaylen_r = (slider2 * srate * 0.001 * 2)|0;

bpos = 0;
bufsize = srate*0.1;

//eq
slider10 = 0;
slider11 = 0;
slider12 = 0;
slider13 = 0;
slider14 = 0;
slider15 = 0;
slider16 = 0;
slider17 = 0;

slider20 = 0;
slider21 = 0;
slider22 = 0;
slider23 = 0;
slider24 = 0;
slider25 = 0;
slider26 = 0;
slider27 = 0;

iirBPSL = bufsize;
reqSize = IIRBandSplitterInit(iirBPSL, srate, 350, 675, 1200, 1750, 2500, 4500, 9000);
iirBPSR = iirBPSL + reqSize; // Shift the pointer
reqSize = IIRBandSplitterInit(iirBPSR, srate, 350, 675, 1200, 1750, 2500, 4500, 9000);

eqL = iirBPSR + reqSize;
eqL[0] = pow(10, slider10 / 20);
eqL[1] = pow(10, slider11 / 20);
eqL[2] = pow(10, slider12 / 20);
eqL[3] = pow(10, slider13 / 20);
eqL[4] = pow(10, slider14 / 20);
eqL[5] = pow(10, slider15 / 20);
eqL[6] = pow(10, slider16 / 20);
eqL[7] = pow(10, slider17 / 20);

eqR = eqL + 8;
eqR[0] = pow(10, slider20 / 20);
eqR[1] = pow(10, slider21 / 20);
eqR[2] = pow(10, slider22 / 20);
eqR[3] = pow(10, slider23 / 20);
eqR[4] = pow(10, slider24 / 20);
eqR[5] = pow(10, slider25 / 20);
eqR[6] = pow(10, slider26 / 20);
eqR[7] = pow(10, slider27 / 20);

@sample
//eq
IIRBandSplitterProcess(iirBPSL, spl0, l0, l1, l2, l3, l4, l5, l6, l7);
IIRBandSplitterProcess(iirBPSR, spl1, r0, r1, r2, r3, r4, r5, r6, r7);

l0 *= eqL[0];
l1 *= eqL[1];
l2 *= eqL[2];
l3 *= eqL[3];
l4 *= eqL[4];
l5 *= eqL[5];
l6 *= eqL[6];
l7 *= eqL[7];

r0 *= eqR[0];
r1 *= eqR[1];
r2 *= eqR[2];
r3 *= eqR[3];
r4 *= eqR[4];
r5 *= eqR[5];
r6 *= eqR[6];
r7 *= eqR[7];

spl0 = l0 + l1 + l2 + l3 + l4 + l5 + l6 + l7;
spl1 = r0 + r1 + r2 + r3 + r4 + r5 + r6 + r7;

//delay
bpos[0] = spl0;
bpos[1] = spl1;

rdpos_l = bpos - delaylen_l;
rdpos_r = bpos - delaylen_r;
rdpos_l<0 ? rdpos_l += bufsize;
rdpos_r<0 ? rdpos_r += bufsize;
spl0 = rdpos_l[0];
spl1 = rdpos_r[1];

bpos += 2;
bpos >= bufsize ? bpos -= bufsize;

@abdessalaam
Copy link

I would love separate L-R EQ (though for hearing loss compensation rather than in car listening).
Where to put / how to implement this script, in the meantime?
Thank you!

@Switchleg1
Copy link
Author

Switchleg1 commented Jan 8, 2024 via email

@abdessalaam
Copy link

Amazing, thank you. I have saved your example as a separate script (Pawel_EQ_LR.eel) and imported it — now just need to tweak it. It's so helpful :)

@Switchleg1
Copy link
Author

Switchleg1 commented Jan 8, 2024 via email

@abdessalaam
Copy link

abdessalaam commented Jan 8, 2024

I did. Here is my script, in case it's helpful for anyone (and may I suggest that equalization / compensation for hearing loss is added to the app description in Play Store? I spent ages looking for one, and this one is just amazing!).

desc: Hearing Loss Compensation
//Get the values from your audiogram

//Swap channels
swapChannels:0<0,1,1>Swap Channels

//Pre gain
leftPreGain:0<-3,0,0.1>Left Pre Gain (db)
rightPreGain:0<-3,0,0.1>Right Pre Gain (db)

//Delay
leftDelay:0<0,3,0.1>Left Delay (ms)
rightDelay:0<0,3,0.1>Right Delay (ms)

//Allpass
leftAllPassFreq:0<0,7000,50>Left All Pass Freq
rightAllPassFreq:0<0,7000,50>Right All Pass Freq

//EQ
left1Freq:1000<10,15000,50>Left 1 Freq
left1Gain:0<-18,6,1>Left 1 Gain
left1Q:1<0.1,6,0.1>Left 1 Q

left2Freq:1000<10,15000,50>Left 2 Freq
left2Gain:0<-18,6,1>Left 2 Gain
left2Q:1<0.1,6,0.1>Left 2 Q

left3Freq:1000<10,15000,50>Left 3 Freq
left3Gain:0<-18,6,1>Left 3 Gain
left3Q:1<0.1,6,0.1>Left 3 Q

left4Freq:1000<10,15000,50>Left 4 Freq
left4Gain:0<-18,6,1>Left 4 Gain
left4Q:1<0.1,6,0.1>Left 4 Q

left5Freq:1000<10,15000,50>Left 5 Freq
left5Gain:0<-18,6,1>Left 5 Gain
left5Q:1<0.1,6,0.1>Left 5 Q

left6Freq:1000<10,15000,50>Left 6 Freq
left6Gain:0<-18,6,1>Left 6 Gain
left6Q:1<0.1,6,0.1>Left 6 Q

left7Freq:1000<10,15000,50>Left 7 Freq
left7Gain:0<-18,6,1>Left 7 Gain
left7Q:1<0.1,6,0.1>Left 7 Q

left8Freq:1000<10,15000,50>Left 8 Freq
left8Gain:0<-18,6,1>Left 8 Gain
left8Q:1<0.1,6,0.1>Left 8 Q

left9Freq:1000<10,15000,50>Left 9 Freq
left9Gain:0<-19,6,1>Left 9 Gain
left9Q:1<0.1,6,0.1>Left 9 Q

left10Freq:1000<10,15000,50>Left 10 Freq
left10Gain:0<-110,6,1>Left 10 Gain
left10Q:1<0.1,6,0.1>Left 10 Q

left11Freq:1100<11,15000,50>Left 11 Freq
left11Gain:0<-111,6,1>Left 11 Gain
left11Q:1<0.1,6,0.1>Left 11 Q

right1Freq:1000<10,15000,50>Right 1 Freq
right1Gain:0<-18,6,1>Right 1 Gain
right1Q:1<0.1,6,0.1>Right 1 Q

right2Freq:1000<10,15000,50>Right 2 Freq
right2Gain:0<-18,6,1>Right 2 Gain
right2Q:1<0.1,6,0.1>Right 2 Q

right3Freq:1000<10,15000,50>Right 3 Freq
right3Gain:0<-18,6,1>Right 3 Gain
right3Q:1<0.1,6,0.1>Right 3 Q

right4Freq:1000<10,15000,50>Right 4 Freq
right4Gain:0<-18,6,1>Right 4 Gain
right4Q:1<0.1,6,0.1>Right 4 Q

right5Freq:1000<10,15000,50>Right 5 Freq
right5Gain:0<-18,6,1>Right 5 Gain
right5Q:1<0.1,6,0.1>Right 5 Q

right6Freq:1000<10,15000,50>Right 6 Freq
right6Gain:0<-18,6,1>Right 6 Gain
right6Q:1<0.1,6,0.1>Right 6 Q

right7Freq:1000<10,15000,50>Right 7 Freq
right7Gain:0<-18,6,1>Right 7 Gain
right7Q:1<0.1,6,0.1>Right 7 Q

right8Freq:1000<10,15000,50>Right 8 Freq
right8Gain:0<-18,6,1>Right 8 Gain
right8Q:1<0.1,6,0.1>Right 8 Q

right9Freq:1000<10,15000,50>right 9 Freq
right9Gain:0<-19,6,1>right 9 Gain
right9Q:1<0.1,6,0.1>right 9 Q

right10Freq:1000<10,15000,50>right 10 Freq
right10Gain:0<-110,6,1>right 10 Gain
right10Q:1<0.1,6,0.1>right 10 Q

right11Freq:1100<11,15000,50>right 11 Freq
right11Gain:0<-111,6,1>right 11 Gain
right11Q:1<0.1,6,0.1>right 11 Q

@init
//Swap channels slider
swapChannels = 0;

//Pre gain sliders
leftPreGain  = -3.00;
rightPreGain = -3.00;

//Delay sliders
leftDelay  = 0.00;
rightDelay = 0.00;

//Allpass sliders
leftAllPassFreq  = 0;
rightAllPassFreq = 0;

//EQ sliders
left1Freq = 125;
left1Gain = 0;
left1Q    = 3.00;

left2Freq = 250;
left2Gain = 2.00;
left2Q    = 3.00;

left3Freq = 500;
left3Gain = 1.8;
left3Q    = 4.00;

left4Freq = 800;
left4Gain = 1.8;
left4Q    = 2.5;

left5Freq = 1000;
left5Gain = 1.8;
left5Q    = 2.5;

left6Freq = 1650;
left6Gain = 3.0;
left6Q    = 2.0;

left7Freq = 2000;
left7Gain = 4.0;
left7Q    = 2.0;

left8Freq = 3400;
left8Gain = 4.5;
left8Q    = 1.00;

left9Freq = 4000;
left9Gain = 6.0;
left9Q    = 1.00;

left10Freq = 6700;
left10Gain = 8.5;
left10Q    = 1.00;

left11Freq = 8000;
left11Gain = 8.5;
left11Q    = 1.00;

right1Freq = 125;
right1Gain = 0;
right1Q    = 3.00;

right2Freq = 250;
right2Gain = 1.5;
right2Q    = 3.00;

right3Freq = 500;
right3Gain = 1.00;
right3Q    = 4.00;

right4Freq = 800;
right4Gain = 0.8;
right4Q    = 2.5;

right5Freq = 1000;
right5Gain = 0.5;
right5Q    = 2.5;

right6Freq = 1650;
right6Gain = 0.4;
right6Q    = 2.0;

right7Freq = 2000;
right7Gain = 0;
right7Q    = 2.0;

right8Freq = 3400;
right8Gain = 1.5;
right8Q    = 1.00;

right9Freq = 4000;
right9Gain = 2.00;
right9Q    = 1.00;

right10Freq = 6700;
right10Gain = 4.00;
right10Q    = 1.00;

right11Freq = 8000;
right11Gain = 4.00;
right11Q    = 1.00;

//Delay functions
function BuildDelay(lDelay, rDelay)(
    this.leftDelayLen  = round(leftDelay * srate * 0.001) * 2;
    this.rightDelayLen = round(rightDelay * srate * 0.001) * 2;

    this.bPos = 0;
    this.bufSize = srate * 0.1;
);

function ProcessDelay()(
    this.bPos[0] = spl0;
    this.bPos[1] = spl1;

    leftPos  = this.bPos - this.leftDelayLen;
    rightPos = this.bPos - this.rightDelayLen;

    leftPos  < 0 ? leftPos += this.bufSize;
    rightPos < 0 ? rightPos += this.bufSize;

    spl0 = leftPos[0];
    spl1 = rightPos[1];

    this.bPos += 2;
    this.bPos >= this.bufSize ? this.bPos -= this.bufSize;
);

//DSP functions
function BuildAllpass(frequency)(
    omega     = tan($PI * (frequency / srate));

    this.in0  = 0;
    this.in1  = 0;
    this.out0 = 0;
    this.out1 = 0;

    this.a1   = (omega - 1) / (omega + 1);
    this.a2   = 0;
    this.b0   = this.a1;
    this.b1   = 1;
    this.b2   = 0;
);

function BuildParametric(frequency, gain, q)(
    omega = (2.f * $PI * frequency) / srate;
    sn    = sin(omega);
    cs    = cos(omega);
    alpha = sn / (2 * q);
    ax    = pow(10, gain / 40);
    a0    = 1 + (alpha / ax);

    this.in0  = 0;
    this.in1  = 0;
    this.out0 = 0;
    this.out1 = 0;

    this.a1   = -(2 * cs) / a0;
    this.a2   = (1 - (alpha / ax)) / a0;
    this.b1   = -(2 * cs);
    this.b0   = (1 + (alpha * ax));
    this.b2   = (1 - (alpha * ax));
);

function ProcessIIRFilter(inSample)(
    outSample = this.b0 * inSample + this.b1 * this.in0 + this.b2 * this.in1
- this.a1 * this.out0 - this.a2 * this.out1;
    this.in1  = this.in0;
    this.in0  = inSample;
    this.out1 = this.out0;
    this.out0 = outSample;

    outSample;
);

//Pre gain init
leftPreGainValue  = pow(10, leftPreGain  / 20);
rightPreGainValue = pow(10, rightPreGain / 20);

//Delay init
mainDelay.BuildDelay(leftDelay, rightDelay);

//All pass init
leftAllPassFreq > 20 ? leftAllpassFilter.BuildAllpass(leftAllPassFreq);
rightAllPassFreq > 20 ? rightAllpassFilter.BuildAllpass(rightAllPassFreq);

//EQ init
left1Gain != 0 ? left1Parametric.BuildParametric(left1Freq, left1Gain,
left1Q);
left2Gain != 0 ? left2Parametric.BuildParametric(left2Freq, left2Gain,
left2Q);
left3Gain != 0 ? left3Parametric.BuildParametric(left3Freq, left3Gain,
left3Q);
left4Gain != 0 ? left4Parametric.BuildParametric(left4Freq, left4Gain,
left4Q);
left5Gain != 0 ? left5Parametric.BuildParametric(left5Freq, left5Gain,
left5Q);
left6Gain != 0 ? left6Parametric.BuildParametric(left6Freq, left6Gain,
left6Q);
left7Gain != 0 ? left7Parametric.BuildParametric(left7Freq, left7Gain,
left7Q);
left8Gain != 0 ? left8Parametric.BuildParametric(left8Freq, left8Gain,
left8Q);
left9Gain != 0 ? left9Parametric.BuildParametric(left9Freq, left9Gain,
left9Q);
left10Gain != 0 ? left10Parametric.BuildParametric(left10Freq, left10Gain,
left10Q);
left11Gain != 0 ? left11Parametric.BuildParametric(left11Freq, left11Gain,
left11Q);

right1Gain != 0 ? right1Parametric.BuildParametric(right1Freq, right1Gain,
right1Q);
right2Gain != 0 ? right2Parametric.BuildParametric(right2Freq, right2Gain,
right2Q);
right3Gain != 0 ? right3Parametric.BuildParametric(right3Freq, right3Gain,
right3Q);
right4Gain != 0 ? right4Parametric.BuildParametric(right4Freq, right4Gain,
right4Q);
right5Gain != 0 ? right5Parametric.BuildParametric(right5Freq, right5Gain,
right5Q);
right6Gain != 0 ? right6Parametric.BuildParametric(right6Freq, right6Gain,
right6Q);
right7Gain != 0 ? right7Parametric.BuildParametric(right7Freq, right7Gain,
right7Q);
right8Gain != 0 ? right8Parametric.BuildParametric(right8Freq, right8Gain,
right8Q);
right9Gain != 0 ? right9Parametric.BuildParametric(right9Freq, right9Gain,
right9Q);
right10Gain != 0 ? right10Parametric.BuildParametric(right10Freq, right10Gain,
right10Q);
right11Gain != 0 ? right11Parametric.BuildParametric(right11Freq, right11Gain,
right11Q);

@sample
//Swap channels
swapChannels == 1 ? swapValue = spl0;
swapChannels == 1 ? spl0 = spl1;
swapChannels == 1 ? spl1 = swapValue;

//Pre gain
spl0 *= leftPreGainValue;
spl1 *= rightPreGainValue;

//Allpass
leftAllPassFreq  > 20 ? spl0 = leftAllpassFilter.ProcessIIRFilter(spl0);
rightAllPassFreq > 20 ? spl1 = rightAllpassFilter.ProcessIIRFilter(spl1);

//EQ
left1Gain != 0 ? spl0 = left1Parametric.ProcessIIRFilter(spl0);
left2Gain != 0 ? spl0 = left2Parametric.ProcessIIRFilter(spl0);
left3Gain != 0 ? spl0 = left3Parametric.ProcessIIRFilter(spl0);
left4Gain != 0 ? spl0 = left4Parametric.ProcessIIRFilter(spl0);
left5Gain != 0 ? spl0 = left5Parametric.ProcessIIRFilter(spl0);
left6Gain != 0 ? spl0 = left6Parametric.ProcessIIRFilter(spl0);
left7Gain != 0 ? spl0 = left7Parametric.ProcessIIRFilter(spl0);
left8Gain != 0 ? spl0 = left8Parametric.ProcessIIRFilter(spl0);
left9Gain != 0 ? spl0 = left9Parametric.ProcessIIRFilter(spl0);
left10Gain != 0 ? spl0 = left9Parametric.ProcessIIRFilter(spl0);
left11Gain != 0 ? spl0 = left9Parametric.ProcessIIRFilter(spl0);

right1Gain != 0 ? spl1 = right1Parametric.ProcessIIRFilter(spl1);
right2Gain != 0 ? spl1 = right2Parametric.ProcessIIRFilter(spl1);
right3Gain != 0 ? spl1 = right3Parametric.ProcessIIRFilter(spl1);
right4Gain != 0 ? spl1 = right4Parametric.ProcessIIRFilter(spl1);
right5Gain != 0 ? spl1 = right5Parametric.ProcessIIRFilter(spl1);
right6Gain != 0 ? spl1 = right6Parametric.ProcessIIRFilter(spl1);
right7Gain != 0 ? spl1 = right7Parametric.ProcessIIRFilter(spl1);
right8Gain != 0 ? spl1 = right8Parametric.ProcessIIRFilter(spl1);
right9Gain != 0 ? spl0 = right9Parametric.ProcessIIRFilter(spl0);
right10Gain != 0 ? spl0 = right9Parametric.ProcessIIRFilter(spl0);
right11Gain != 0 ? spl0 = right9Parametric.ProcessIIRFilter(spl0);

//Delay
mainDelay.ProcessDelay();

@FlavioPonte
Copy link

Hello... Very useful as I was looking for something like this. May I ask you what type of filter this uses, like peak filter, etc.

@Switchleg1
Copy link
Author

Switchleg1 commented Jan 29, 2024 via email

@FlavioPonte
Copy link

Thank you for your work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants