ref: db8bc76702cbd252d10f6f60bfae8cb9d167c38c
dir: /LEAF/Src/leaf-vocoder.c/
/* ============================================================================== LEAFInstrument.c Created: 20 Jan 2017 12:01:54pm Author: Michael R Mulshine ============================================================================== */ #if _WIN32 || _WIN64 #include "..\Inc\leaf-vocoder.h" #include "..\leaf.h" #else #include "../Inc/leaf-vocoder.h" #include "../leaf.h" #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void tTalkbox_init(tTalkbox* const v) { v->param[0] = 0.5f; //wet v->param[1] = 0.0f; //dry v->param[2] = 0; // Swap v->param[3] = 1.0f; //quality tTalkbox_update(v); } void tTalkbox_free(tTalkbox* const v) { leaf_free(v); } void tTalkbox_update(tTalkbox* const v) ///update internal parameters... { float fs = leaf.sampleRate; if(fs < 8000.0f) fs = 8000.0f; if(fs > 96000.0f) fs = 96000.0f; int32_t n = (int32_t)(0.01633f * fs); if(n > TALKBOX_BUFFER_LENGTH) n = TALKBOX_BUFFER_LENGTH; //O = (VstInt32)(0.0005f * fs); v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * fs); if(n != v->N) //recalc hanning window { v->N = n; float dp = TWO_PI / v->N; float p = 0.0f; for(n=0; n<v->N; n++) { v->window[n] = 0.5f - 0.5f * cosf(p); p += dp; } } v->wet = 0.5f * v->param[0] * v->param[0]; v->dry = 2.0f * v->param[1] * v->param[1]; } void tTalkbox_suspend(tTalkbox* const v) ///clear any buffers... { v->pos = v->K = 0; v->emphasis = 0.0f; v->FX = 0; v->u0 = v->u1 = v->u2 = v->u3 = v->u4 = 0.0f; v->d0 = v->d1 = v->d2 = v->d3 = v->d4 = 0.0f; for (int32_t i = 0; i < TALKBOX_BUFFER_LENGTH; i++) { v->buf0[i] = 0; v->buf1[i] = 0; v->car0[i] = 0; v->car1[i] = 0; } } #define ORD_MAX 100 // Was 50. Increasing this gets rid of glitchiness, lowering it breaks it; not sure how it affects performance void tTalkbox_lpc(float *buf, float *car, int32_t n, int32_t o) { 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<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation } r[0] *= 1.001f; //stability fix float min = 0.00001f; if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; } tTalkbox_lpcDurbin(r, o, k, &G); //calc reflection coeffs for(i=0; i<=o; i++) { if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f; } for(i=0; i<n; i++) { x = G * car[i]; for(j=o; j>0; 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 tTalkbox_lpcDurbin(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<i; j++) { at[j] = a[j]; k[i] -= a[j] * r[i-j]; } if(fabs(e) < 1.0e-20f) { e = 0.0f; break; } k[i] /= e; // This might be costing us a[i] = k[i]; for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j]; e *= 1.0f - k[i] * k[i]; } if(e < 1.0e-20f) e = 0.0f; *g = sqrtf(e); } float tTalkbox_tick(tTalkbox* const v, float synth, float voice) { int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N; float e=v->emphasis, w, o, x, dr, fx=v->FX; float p, q, h0=0.3f, h1=0.77f; o = voice; x = synth; dr = o; p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p; q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q; v->d4 = x; x = p + q; if(v->K++) { v->K = 0; v->car0[p0] = v->car1[p1] = x; //carrier input x = o - e; e = o; //6dB/oct pre-emphasis w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->N, v->O); p0 = 0; } w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w; if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->N, v->O); p1 = 0; } } p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p; q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q; v->u4 = fx; x = p + q; o = x; v->emphasis = e; v->pos = p0; v->FX = fx; float den = 1.0e-10f; //(float)pow(10.0f, -10.0f * param[4]); if(fabs(v->d0) < den) v->d0 = 0.0f; //anti-denormal (doesn't seem necessary but P4?) if(fabs(v->d1) < den) v->d1 = 0.0f; if(fabs(v->d2) < den) v->d2 = 0.0f; if(fabs(v->d3) < den) v->d3 = 0.0f; if(fabs(v->u0) < den) v->u0 = 0.0f; if(fabs(v->u1) < den) v->u1 = 0.0f; if(fabs(v->u2) < den) v->u2 = 0.0f; if(fabs(v->u3) < den) v->u3 = 0.0f; return o; } void tTalkbox_setQuality(tTalkbox* const v, float quality) { v->param[3] = quality; v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate); } void tVocoder_init (tVocoder* const v) { v->param[0] = 0.33f; //input select v->param[1] = 0.50f; //output dB v->param[2] = 0.40f; //hi thru v->param[3] = 0.40f; //hi band v->param[4] = 0.16f; //envelope v->param[5] = 0.55f; //filter q v->param[6] = 0.6667f;//freq range v->param[7] = 0.33f; //num bands tVocoder_update(v); } void tVocoder_update (tVocoder* const v) { float tpofs = 6.2831853f * leaf.invSampleRate; float rr, th, re; float sh; int32_t i; v->gain = (float)pow(10.0f, 2.0f * v->param[1] - 3.0f * v->param[5] - 2.0f); v->thru = (float)pow(10.0f, 0.5f + 2.0f * v->param[1]); v->high = v->param[3] * v->param[3] * v->param[3] * v->thru; v->thru *= v->param[2] * v->param[2] * v->param[2]; if(v->param[7]<0.5f) { v->nbnd=8; re=0.003f; v->f[1][2] = 3000.0f; v->f[2][2] = 2200.0f; v->f[3][2] = 1500.0f; v->f[4][2] = 1080.0f; v->f[5][2] = 700.0f; v->f[6][2] = 390.0f; v->f[7][2] = 190.0f; } else { v->nbnd=16; re=0.0015f; v->f[ 1][2] = 5000.0f; //+1000 v->f[ 2][2] = 4000.0f; //+750 v->f[ 3][2] = 3250.0f; //+500 v->f[ 4][2] = 2750.0f; //+450 v->f[ 5][2] = 2300.0f; //+300 v->f[ 6][2] = 2000.0f; //+250 v->f[ 7][2] = 1750.0f; //+250 v->f[ 8][2] = 1500.0f; //+250 v->f[ 9][2] = 1250.0f; //+250 v->f[10][2] = 1000.0f; //+250 v->f[11][2] = 750.0f; //+210 v->f[12][2] = 540.0f; //+190 v->f[13][2] = 350.0f; //+155 v->f[14][2] = 195.0f; //+100 v->f[15][2] = 95.0f; } if(v->param[4]<0.05f) //freeze { for(i=0;i<v->nbnd;i++) v->f[i][12]=0.0f; } else { v->f[0][12] = (float)pow(10.0, -1.7 - 2.7f * v->param[4]); //envelope speed rr = 0.022f / (float)v->nbnd; //minimum proportional to frequency to stop distortion for(i=1;i<v->nbnd;i++) { v->f[i][12] = (float)(0.025 - rr * (double)i); if(v->f[0][12] < v->f[i][12]) v->f[i][12] = v->f[0][12]; } v->f[0][12] = 0.5f * v->f[0][12]; //only top band is at full rate } rr = 1.0 - pow(10.0f, -1.0f - 1.2f * v->param[5]); sh = (float)pow(2.0f, 3.0f * v->param[6] - 1.0f); //filter bank range shift for(i=1;i<v->nbnd;i++) { v->f[i][2] *= sh; th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr)); v->f[i][0] = (float)(2.0 * rr * cos(th)); //a0 v->f[i][1] = (float)(-rr * rr); //a1 //was .98 v->f[i][2] *= 0.96f; //shift 2nd stage slightly to stop high resonance peaks th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr)); v->f[i][2] = (float)(2.0 * rr * cos(th)); } } float tVocoder_tick (tVocoder* const v, float synth, float voice) { float a, b, o=0.0f, aa, bb, oo = v->kout, g = v->gain, ht = v->thru, hh = v->high, tmp; uint32_t i, k = v->kval, nb = v->nbnd; a = voice; //speech b = synth; //synth tmp = a - v->f[0][7]; //integrate modulator for HF band and filter bank pre-emphasis v->f[0][7] = a; a = tmp; if(tmp<0.0f) tmp = -tmp; v->f[0][11] -= v->f[0][12] * (v->f[0][11] - tmp); //high band envelope o = v->f[0][11] * (ht * a + hh * (b - v->f[0][3])); //high band + high thru v->f[0][3] = b; //integrate carrier for HF band if(++k & 0x1) //this block runs at half sample rate { oo = 0.0f; aa = a + v->f[0][9] - v->f[0][8] - v->f[0][8]; //apply zeros here instead of in each reson v->f[0][9] = v->f[0][8]; v->f[0][8] = a; bb = b + v->f[0][5] - v->f[0][4] - v->f[0][4]; v->f[0][5] = v->f[0][4]; v->f[0][4] = b; for(i=1; i<nb; i++) //filter bank: 4th-order band pass { tmp = v->f[i][0] * v->f[i][3] + v->f[i][1] * v->f[i][4] + bb; v->f[i][4] = v->f[i][3]; v->f[i][3] = tmp; tmp += v->f[i][2] * v->f[i][5] + v->f[i][1] * v->f[i][6]; v->f[i][6] = v->f[i][5]; v->f[i][5] = tmp; tmp = v->f[i][0] * v->f[i][7] + v->f[i][1] * v->f[i][8] + aa; v->f[i][8] = v->f[i][7]; v->f[i][7] = tmp; tmp += v->f[i][2] * v->f[i][9] + v->f[i][1] * v->f[i][10]; v->f[i][10] = v->f[i][9]; v->f[i][9] = tmp; if(tmp<0.0f) tmp = -tmp; v->f[i][11] -= v->f[i][12] * (v->f[i][11] - tmp); oo += v->f[i][5] * v->f[i][11]; } } o += oo * g; //effect of interpolating back up to Fs would be minimal (aliasing >16kHz) v->kout = oo; v->kval = k & 0x1; if(fabs(v->f[0][11])<1.0e-10) v->f[0][11] = 0.0f; //catch HF envelope denormal for(i=1;i<nb;i++) if(fabs(v->f[i][3])<1.0e-10 || fabs(v->f[i][7])<1.0e-10) for(k=3; k<12; k++) v->f[i][k] = 0.0f; //catch reson & envelope denormals if(fabs(o)>10.0f) tVocoder_suspend(v); //catch instability return o; } void tVocoder_suspend (tVocoder* const v) { int32_t i, j; for(i=0; i<v->nbnd; i++) for(j=3; j<12; j++) v->f[i][j] = 0.0f; //zero band filters and envelopes v->kout = 0.0f; v->kval = 0; }