/* Copyright 2008-2011 David Robillard Copyright 1999-2000 Paul Kellett (Maxim Digital Audio) This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this software. If not, see . */ #include "mdaTalkBox.h" #include #include #include #include #include AudioEffect *createEffectInstance(audioMasterCallback audioMaster) { return new mdaTalkBox(audioMaster); } mdaTalkBoxProgram::mdaTalkBoxProgram() ///default program settings { param[0] = 0.5f; //wet param[1] = 0.0f; //dry param[2] = 0.0f; //swap param[3] = 1.0f; //quality strcpy(name, "Talkbox"); } mdaTalkBox::mdaTalkBox(audioMasterCallback audioMaster): AudioEffectX(audioMaster, NPROGS, NPARAMS) { setNumInputs(2); setNumOutputs(2); setUniqueID("mdaTalkBox"); ///identify plug-in here //canMono(); canProcessReplacing(); ///initialise... buf0 = new float[BUF_MAX]; buf1 = new float[BUF_MAX]; window = new float[BUF_MAX]; car0 = new float[BUF_MAX]; car1 = new float[BUF_MAX]; N = 1; //trigger window recalc K = 0; programs = new mdaTalkBoxProgram[NPROGS]; if(programs) { ///differences from default program... //programs[1].param[0] = 0.1f; //strcpy(programs[1].name,"Another Program"); setProgram(0); } suspend(); } bool mdaTalkBox::getProductString(char* text) { strcpy(text, "MDA TalkBox"); return true; } bool mdaTalkBox::getVendorString(char* text) { strcpy(text, "mda"); return true; } bool mdaTalkBox::getEffectName(char* name) { strcpy(name, "TalkBox"); return true; } void mdaTalkBox::resume() ///update internal parameters... { float fs = getSampleRate(); float * param = programs[curProgram].param; if(fs < 8000.0f) fs = 8000.0f; if(fs > 96000.0f) fs = 96000.0f; swap = (param[2] > 0.5f)? 1 : 0; int32_t n = (int32_t)(0.01633f * fs); if(n > BUF_MAX) n = BUF_MAX; //O = (int32_t)(0.0005f * fs); O = (int32_t)((0.0001f + 0.0004f * param[3]) * fs); if(n != N) //recalc hanning window { N = n; float dp = TWO_PI / (float)N; float p = 0.0f; for(n=0; n= 0) { o = *++in1; x = *++in2; c = out1[1]; d = out2[1]; dr = o; p = d0 + h0 * x; d0 = d1; d1 = x - h0 * p; q = d2 + h1 * d4; d2 = d3; d3 = d4 - h1 * q; d4 = x; x = p + q; if(K++) { K = 0; car0[p0] = car1[p1] = x; //carrier input x = o - e; e = o; //6dB/oct pre-emphasis w = window[p0]; fx = buf0[p0] * w; buf0[p0] = x * w; //50% overlapping hanning windows if(++p0 >= N) { lpc(buf0, car0, N, O); p0 = 0; } w = 1.0f - w; fx += buf1[p1] * w; buf1[p1] = x * w; if(++p1 >= N) { lpc(buf1, car1, N, O); p1 = 0; } } p = u0 + h0 * fx; u0 = u1; u1 = fx - h0 * p; q = u2 + h1 * u4; u2 = u3; u3 = u4 - h1 * q; u4 = fx; x = p + q; o = wet * x + dry * dr; *++out1 = c + o; *++out2 = d + o; } emphasis = e; pos = p0; FX = fx; float den = 1.0e-10f; //(float)pow(10.0f, -10.0f * param[4]); if(fabs(d0) < den) d0 = 0.0f; //anti-denormal (doesn't seem necessary but P4?) if(fabs(d1) < den) d1 = 0.0f; if(fabs(d2) < den) d2 = 0.0f; if(fabs(d3) < den) d3 = 0.0f; if(fabs(u0) < den) u0 = 0.0f; if(fabs(u1) < den) u1 = 0.0f; if(fabs(u2) < den) u2 = 0.0f; if(fabs(u3) < den) u3 = 0.0f; } void mdaTalkBox::processReplacing(float **inputs, float **outputs, int32_t sampleFrames) { float *in1 = inputs[0]; float *in2 = inputs[1]; if(swap) { in1 = inputs[1]; in2 = inputs[0]; } float *out1 = outputs[0]; float *out2 = outputs[1]; int32_t p0=pos, p1 = (pos + N/2) % N; float e=emphasis, w, o, x, dr, fx=FX; float p, q, h0=0.3f, h1=0.77f; --in1; --in2; --out1; --out2; while(--sampleFrames >= 0) { o = *++in1; x = *++in2; dr = o; p = d0 + h0 * x; d0 = d1; d1 = x - h0 * p; q = d2 + h1 * d4; d2 = d3; d3 = d4 - h1 * q; d4 = x; x = p + q; if(K++) { K = 0; car0[p0] = car1[p1] = x; //carrier input x = o - e; e = o; //6dB/oct pre-emphasis w = window[p0]; fx = buf0[p0] * w; buf0[p0] = x * w; //50% overlapping hanning windows if(++p0 >= N) { lpc(buf0, car0, N, O); p0 = 0; } w = 1.0f - w; fx += buf1[p1] * w; buf1[p1] = x * w; if(++p1 >= N) { lpc(buf1, car1, N, O); p1 = 0; } } p = u0 + h0 * fx; u0 = u1; u1 = fx - h0 * p; q = u2 + h1 * u4; u2 = u3; u3 = u4 - h1 * q; u4 = fx; x = p + q; o = wet * x + dry * dr; *++out1 = o; *++out2 = o; } emphasis = e; pos = p0; FX = fx; float den = 1.0e-10f; //(float)pow(10.0f, -10.0f * param[4]); if(fabs(d0) < den) d0 = 0.0f; //anti-denormal (doesn't seem necessary but P4?) if(fabs(d1) < den) d1 = 0.0f; if(fabs(d2) < den) d2 = 0.0f; if(fabs(d3) < den) d3 = 0.0f; if(fabs(u0) < den) u0 = 0.0f; if(fabs(u1) < den) u1 = 0.0f; if(fabs(u2) < den) u2 = 0.0f; if(fabs(u3) < den) u3 = 0.0f; } void mdaTalkBox::lpc(float *buf, float *car, int32_t n, int32_t o) { assert(o >= 0); float z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x; int32_t i, j, nn=n; for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed { z[j] = r[j] = 0.0f; for(i=0; i 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f; } for(i=0; i0; j--) //lattice filter { x -= k[j] * z[j-1]; z[j] = z[j-1] + k[j] * x; } buf[i] = z[0] = x; //output buf[] will be windowed elsewhere } } void mdaTalkBox::lpc_durbin(float *r, int p, float *k, float *g) { int i, j; float a[ORD_MAX], at[ORD_MAX], e=r[0]; for(i=0; i<=p; i++) a[i] = at[i] = 0.0f; //probably don't need to clear at[] or k[] for(i=1; i<=p; i++) { k[i] = -r[i]; for(j=1; j