/* * Envelope Output (dB) */ float Envelope::envout_dB() { float out; if(linearenvelope != 0) return envout(); if((currentpoint == 1) && (!keyreleased || (forcedrelase == 0))) { //first point is always lineary interpolated float v1 = dB2rap(envval[0]); float v2 = dB2rap(envval[1]); out = v1 + (v2 - v1) * t; t += inct; if(t >= 1.0f) { t = 0.0f; inct = envdt[2]; currentpoint++; out = v2; } if(out > 0.001f) envoutval = rap2dB(out); else envoutval = MIN_ENVELOPE_DB; } else out = dB2rap(envout()); return out; }
float EQ::getfreqresponse(float freq) { float resp = 1.0f; for(int i = 0; i < MAX_EQ_BANDS; ++i) { if(filter[i].Ptype == 0) continue; resp *= filter[i].l->H(freq); } return rap2dB(resp * outvolume); }
void out_smb (holharm_t * s, float *smpsl, float *smpsr, unsigned long sample_count) { int i; float elratiol, elratior; float i_sum = 1e-12; float temp_sum, val_i_sum; float tmp; for (i = 0; i < sample_count; i++) { s->outil[i] = smpsl[i]; s->outir[i] = smpsr[i]; tmp = fabsf (smpsr[i] + smpsl[i]); if (tmp > i_sum) i_sum = tmp; } temp_sum = CLAMP (rap2dB (i_sum), -48.0, 15.0); val_i_sum = .6 * s->val_sum + .4 * temp_sum; s->val_sum = val_i_sum; if (*(s->PSELECT) == 1) { elratiol = s->ratiol; elratior = s->ratior; } else { elratiol = powf (2, *(s->intervall) / 12.0); elratior = powf (2, *(s->intervalr) / 12.0); } smbPitchShiftL (s, elratiol, sample_count, 2048, s->hq, (float) s->SAMPLE_RATE, s->outil, s->outol); smbPitchShiftR (s, elratior, sample_count, 2048, s->hq, (float) s->SAMPLE_RATE, s->outir, s->outor); }
void FormantFilterGraph::draw() { int maxdB=30; int ox=x(),oy=y(),lx=w(),ly=h(),i,oiy; REALTYPE freqx; fl_color(FL_BLACK); fl_rectf(ox,oy,lx,ly); //draw the lines fl_color(FL_GRAY); fl_line_style(FL_SOLID); //fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); freqx=pars->getfreqpos(1000.0); if ((freqx>0.0)&&(freqx<1.0)) fl_line(ox+(int) (freqx*lx),oy, ox+(int) (freqx*lx),oy+ly); for (i=1;i<10;i++){ if(i==1){ draw_freq_line(i*100.0,0); draw_freq_line(i*1000.0,0); }else if (i==5){ draw_freq_line(i*100.0,2); draw_freq_line(i*1000.0,2); }else{ draw_freq_line(i*100.0,1); draw_freq_line(i*1000.0,1); }; }; draw_freq_line(10000.0,0); draw_freq_line(20000.0,1); fl_line_style(FL_DOT); int GY=10;if (ly<GY*3) GY=-1; for (i=1;i<GY;i++){ int tmp=(int)(ly/(REALTYPE)GY*i); fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp); }; fl_color(FL_YELLOW); fl_font(FL_HELVETICA,10); if (*nformant<pars->Pnumformants){ draw_freq_line(pars->getformantfreq(pars->Pvowels[*nvowel].formants[*nformant].freq),2); //show some information (like current formant frequency,amplitude) char tmpstr[20]; snprintf(tmpstr,20,"%.2f kHz",pars->getformantfreq(pars->Pvowels[*nvowel].formants[*nformant].freq)*0.001); fl_draw(tmpstr,ox+1,oy+1,40,12,FL_ALIGN_LEFT,NULL,0); snprintf(tmpstr,20,"%d dB",(int)( rap2dB(1e-9 + pars->getformantamp(pars->Pvowels[*nvowel].formants[*nformant].amp)) + pars->getgain() )); fl_draw(tmpstr,ox+1,oy+15,40,12,FL_ALIGN_LEFT,NULL,0); }; //draw the data fl_color(FL_RED); fl_line_style(FL_SOLID); pars->formantfilterH(*nvowel,lx,graphpoints); oiy=(int) ((graphpoints[0]/maxdB+1.0)*ly/2.0); for (i=1;i<lx;i++){ int iy=(int) ((graphpoints[i]/maxdB+1.0)*ly/2.0); if ((iy>=0)&&(oiy>=0)&&(iy<ly)&&(oiy<lx)) fl_line(ox+i-1,oy+ly-oiy,ox+i,oy+ly-iy); oiy=iy; }; }
/* * Get the freq. response of the formant filter */ void FilterParams::formantfilterH(int nvowel, int nfreqs, REALTYPE *freqs) { REALTYPE c[3], d[3]; REALTYPE filter_freq, filter_q, filter_amp; REALTYPE omega, sn, cs, alpha; for(int i = 0; i < nfreqs; i++) freqs[i] = 0.0; //for each formant... for(int nformant = 0; nformant < Pnumformants; nformant++) { //compute formant parameters(frequency,amplitude,etc.) filter_freq = getformantfreq(Pvowels[nvowel].formants[nformant].freq); filter_q = getformantq(Pvowels[nvowel].formants[nformant].q) * getq(); if(Pstages > 0) filter_q = (filter_q > 1.0 ? POW(filter_q, 1.0 / (Pstages + 1)) : filter_q); filter_amp = getformantamp(Pvowels[nvowel].formants[nformant].amp); if(filter_freq <= (SAMPLE_RATE / 2 - 100.0)) { omega = 2 * PI * filter_freq / SAMPLE_RATE; sn = sin(omega); cs = cos(omega); alpha = sn / (2 * filter_q); REALTYPE tmp = 1 + alpha; c[0] = alpha / tmp *sqrt(filter_q + 1); c[1] = 0; c[2] = -alpha / tmp *sqrt(filter_q + 1); d[1] = -2 * cs / tmp * (-1); d[2] = (1 - alpha) / tmp * (-1); } else continue; for(int i = 0; i < nfreqs; i++) { REALTYPE freq = getfreqx(i / (REALTYPE) nfreqs); if(freq > SAMPLE_RATE / 2) { for(int tmp = i; tmp < nfreqs; tmp++) freqs[tmp] = 0.0; break; } REALTYPE fr = freq / SAMPLE_RATE * PI * 2.0; REALTYPE x = c[0], y = 0.0; for(int n = 1; n < 3; n++) { x += cos(n * fr) * c[n]; y -= sin(n * fr) * c[n]; } REALTYPE h = x * x + y * y; x = 1.0; y = 0.0; for(int n = 1; n < 3; n++) { x -= cos(n * fr) * d[n]; y += sin(n * fr) * d[n]; } h = h / (x * x + y * y); freqs[i] += POW(h, (Pstages + 1.0) / 2.0) * filter_amp; } } for(int i = 0; i < nfreqs; i++) { if(freqs[i] > 0.000000001) freqs[i] = rap2dB(freqs[i]) + getgain(); else freqs[i] = -90.0; } }
void Compressor::out (float *efxoutl, float *efxoutr) { int i; for (i = 0; i < PERIOD; i++) { float rdelta = 0.0f; float ldelta = 0.0f; //Right Channel if(peak) { if (rtimer > hold) { rpeak *= 0.9998f; //The magic number corresponds to ~0.1s based on T/(RC + T), rtimer--; } if (ltimer > hold) { lpeak *= 0.9998f; //leaky peak detector. ltimer --; //keeps the timer from eventually exceeding max int & rolling over } ltimer++; rtimer++; if(rpeak<fabs(efxoutr[i])) { rpeak = fabs(efxoutr[i]); rtimer = 0; } if(lpeak<fabs(efxoutl[i])) { lpeak = fabs(efxoutl[i]); ltimer = 0; } if(lpeak>20.0f) lpeak = 20.0f; if(rpeak>20.0f) rpeak = 20.0f; //keeps limiter from getting locked up when signal levels go way out of bounds (like hundreds) } else { rpeak = efxoutr[i]; lpeak = efxoutl[i]; } if(stereo) { rdelta = fabsf (rpeak); if(rvolume < 0.9f) { attr = att; relr = rel; } else if (rvolume < 1.0f) { attr = att + ((1.0f - att)*(rvolume - 0.9f)*10.0f); //dynamically change attack time for limiting mode relr = rel/(1.0f + (rvolume - 0.9f)*9.0f); //release time gets longer when signal is above limiting } else { attr = 1.0f; relr = rel*0.1f; } if (rdelta > rvolume) rvolume = attr * rdelta + (1.0f - attr)*rvolume; else rvolume = relr * rdelta + (1.0f - relr)*rvolume; rvolume_db = rap2dB (rvolume); if (rvolume_db < thres_db) { rgain = outlevel; } else if (rvolume_db < thres_mx) { //Dynamic ratio that depends on volume. As can be seen, ratio starts //at something negligibly larger than 1 once volume exceeds thres, and increases toward selected // ratio by the time it has reached thres_mx. --Transmogrifox eratio = 1.0f + (kratio-1.0f)*(rvolume_db-thres_db)* coeff_knee; rgain = outlevel*dB2rap(thres_db + (rvolume_db-thres_db)/eratio - rvolume_db); } else { rgain = outlevel*dB2rap(thres_db + coeff_kk + (rvolume_db-thres_mx)*coeff_ratio - rvolume_db); limit = 1; } if ( rgain < MIN_GAIN) rgain = MIN_GAIN; rgain_t = .4f * rgain + .6f * rgain_old; }; //Left Channel if(stereo) { ldelta = fabsf (lpeak); } else { ldelta = 0.5f*(fabsf (lpeak) + fabsf (rpeak)); }; //It's not as efficient to check twice, but it's small expense worth code clarity if(lvolume < 0.9f) { attl = att; rell = rel; } else if (lvolume < 1.0f) { attl = att + ((1.0f - att)*(lvolume - 0.9f)*10.0f); //dynamically change attack time for limiting mode rell = rel/(1.0f + (lvolume - 0.9f)*9.0f); //release time gets longer when signal is above limiting } else { attl = 1.0f; rell = rel*0.1f; } if (ldelta > lvolume) lvolume = attl * ldelta + (1.0f - attl)*lvolume; else lvolume = rell*ldelta + (1.0f - rell)*lvolume; lvolume_db = rap2dB (lvolume); if (lvolume_db < thres_db) { lgain = outlevel; } else if (lvolume_db < thres_mx) { //knee region eratio = 1.0f + (kratio-1.0f)*(lvolume_db-thres_db)* coeff_knee; lgain = outlevel*dB2rap(thres_db + (lvolume_db-thres_db)/eratio - lvolume_db); } else { lgain = outlevel*dB2rap(thres_db + coeff_kk + (lvolume_db-thres_mx)*coeff_ratio - lvolume_db); limit = 1; } if ( lgain < MIN_GAIN) lgain = MIN_GAIN; lgain_t = .4f * lgain + .6f * lgain_old; if (stereo) { efxoutl[i] *= lgain_t; efxoutr[i] *= rgain_t; rgain_old = rgain; lgain_old = lgain; } else { efxoutl[i] *= lgain_t; efxoutr[i] *= lgain_t; lgain_old = lgain; } if(peak) { if(efxoutl[i]>0.999f) { //output hard limiting efxoutl[i] = 0.999f; clipping = 1; } if(efxoutl[i]<-0.999f) { efxoutl[i] = -0.999f; clipping = 1; } if(efxoutr[i]>0.999f) { efxoutr[i] = 0.999f; clipping = 1; } if(efxoutr[i]<-0.999f) { efxoutr[i] = -0.999f; clipping = 1; } //highly probably there is a more elegant way to do that, but what the hey... } } }
/* * Effect output */ void Vocoder::out (float * smpsl, float * smpsr) { int i, j; float tempgain; float maxgain=0.0f; float auxtemp, tmpgain; if(DS_state != 0) { A_Resample->mono_out(auxresampled,tmpaux,PERIOD,u_up,nPERIOD); } else memcpy(tmpaux,auxresampled,sizeof(float)*nPERIOD); for (i = 0; i<nPERIOD; i++) //apply compression to auxresampled { auxtemp = input * tmpaux[i]; if(fabs(auxtemp > compeak)) compeak = fabs(auxtemp); //First do peak detection on the signal compeak *= prls; compenv = cbeta * oldcompenv + calpha * compeak; //Next average into envelope follower oldcompenv = compenv; if(compenv > cpthresh) //if envelope of signal exceeds thresh, then compress { compg = cpthresh + cpthresh*(compenv - cpthresh)/compenv; cpthresh = cthresh + cratio*(compg - cpthresh); //cpthresh changes dynamically tmpgain = compg/compenv; } else { tmpgain = 1.0f; } if(compenv < cpthresh) cpthresh = compenv; if(cpthresh < cthresh) cpthresh = cthresh; tmpaux[i] = auxtemp * tmpgain; tmpaux[i]=vlp->filterout_s(tmpaux[i]); tmpaux[i]=vhp->filterout_s(tmpaux[i]); }; //End compression auxtemp = 0.0f; if(DS_state != 0) { U_Resample->out(smpsl,smpsr,tsmpsl,tsmpsr,PERIOD,u_up); } else { memcpy(tsmpsl,smpsl,sizeof(float)*nPERIOD); memcpy(tsmpsr,smpsr,sizeof(float)*nPERIOD); } memset(tmpl,0,sizeof(float)*nPERIOD); memset(tmpr,0,sizeof(float)*nPERIOD); for (j = 0; j < VOC_BANDS; j++) { for (i = 0; i<nPERIOD; i++) { auxtemp = tmpaux[i]; if(filterbank[j].speak < gate) filterbank[j].speak = 0.0f; //gate if(auxtemp>maxgain) maxgain = auxtemp; //vu meter level. auxtemp = filterbank[j].aux->filterout_s(auxtemp); if(fabs(auxtemp) > filterbank[j].speak) filterbank[j].speak = fabs(auxtemp); //Leaky Peak detector filterbank[j].speak*=prls; filterbank[j].gain = beta * filterbank[j].oldgain + alpha * filterbank[j].speak; filterbank[j].oldgain = filterbank[j].gain; tempgain = (1.0f-ringworm)*filterbank[j].oldgain+ringworm*auxtemp; tmpl[i] +=filterbank[j].l->filterout_s(tsmpsl[i])*tempgain; tmpr[i] +=filterbank[j].r->filterout_s(tsmpsr[i])*tempgain; }; }; for (i = 0; i<nPERIOD; i++) { tmpl[i]*=lpanning*level; tmpr[i]*=rpanning*level; }; if(DS_state != 0) { D_Resample->out(tmpl,tmpr,efxoutl,efxoutr,nPERIOD,u_down); } else { memcpy(efxoutl,tmpl,sizeof(float)*nPERIOD); memcpy(efxoutr,tmpr,sizeof(float)*nPERIOD); } vulevel = (float)CLAMP(rap2dB(maxgain), -48.0, 15.0); };