ref: 0df3039072e1eb47d710348117063fa45cfaf2dd
dir: /modules/verbity.c/
/* * Verbity * * This is a self-contained ANSI-C soundpipe port of the * Verbity * VST plugin by Chris Johnson of AirWindows: * * http://www.airwindows.com/verbity/ * * In addition to the C++->C rewrites, a few notable * adjustments have been made to the * algorithm. Wet/Dry control has been removed in favor * of 100% wet (balance can be done externally). * The dithering has been taken out as well (empirically, * this seemed to be a CPU hog). * * The original C++ code is under an MIT license * (same license as Soundpipe), Copyright 2021 Chris * Johnson. * * If you like this plugin, please please please consider * supporting Chris and AirWindows via Patreon: * https://www.patreon.com/airwindows * */ #include <stdint.h> #include <stdlib.h> #include <math.h> #include "soundpipe.h" int sp_verbity_create(sp_verbity **p) { *p = malloc(sizeof(sp_verbity)); return SP_OK; } int sp_verbity_destroy(sp_verbity **p) { free(*p); return SP_OK; } void sp_verbity_reset(sp_verbity *v, int sr) { int count; v->sr = sr; v->bigness = 0.25; v->longness = 0.0; v->darkness = 0.25; v->iirAL = 0.0; v->iirAR = 0.0; v->iirBL = 0.0; v->iirBR = 0.0; for (count = 0; count < 6479; count++) { v->aIL[count] = 0.0; v->aIR[count] = 0.0; } for (count = 0; count < 3659; count++) { v->aJL[count] = 0.0; v->aJR[count] = 0.0; } for (count = 0; count < 1719; count++) { v->aKL[count] = 0.0; v->aKR[count] = 0.0; } for (count = 0; count < 679; count++) { v->aLL[count] = 0.0; v->aLR[count] = 0.0; } for (count = 0; count < 9699; count++) { v->aAL[count] = 0.0; v->aAR[count] = 0.0; } for (count = 0; count < 5999; count++) { v->aBL[count] = 0.0; v->aBR[count] = 0.0; } for (count = 0; count < 2319; count++) { v->aCL[count] = 0.0; v->aCR[count] = 0.0; } for (count = 0; count < 939; count++) { v->aDL[count] = 0.0; v->aDR[count] = 0.0; } for (count = 0; count < 15219; count++) { v->aEL[count] = 0.0; v->aER[count] = 0.0; } for (count = 0; count < 8459; count++) { v->aFL[count] = 0.0; v->aFR[count] = 0.0; } for (count = 0; count < 4539; count++) { v->aGL[count] = 0.0; v->aGR[count] = 0.0; } for (count = 0; count < 3199; count++) { v->aHL[count] = 0.0; v->aHR[count] = 0.0; } v->feedbackAL = 0.0; v->feedbackAR = 0.0; v->feedbackBL = 0.0; v->feedbackBR = 0.0; v->feedbackCL = 0.0; v->feedbackCR = 0.0; v->feedbackDL = 0.0; v->feedbackDR = 0.0; v->previousAL = 0.0; v->previousAR = 0.0; v->previousBL = 0.0; v->previousBR = 0.0; v->previousCL = 0.0; v->previousCR = 0.0; v->previousDL = 0.0; v->previousDR = 0.0; for (count = 0; count < 6; count++) { v->lastRefL[count] = 0.0; v->lastRefR[count] = 0.0; } v->thunderL = 0; v->thunderR = 0; v->countI = 1; v->countJ = 1; v->countK = 1; v->countL = 1; v->countA = 1; v->countB = 1; v->countC = 1; v->countD = 1; v->countE = 1; v->countF = 1; v->countG = 1; v->countH = 1; v->cycle = 0; v->psize = -1; v->onedsr = 1.0 / sr; } int sp_verbity_init(sp_data *sp, sp_verbity *v) { sp_verbity_reset(v, sp->sr); return SP_OK; } int sp_verbity_compute(sp_data *sp, sp_verbity *v, SPFLOAT *inL, SPFLOAT *inR, SPFLOAT *outL, SPFLOAT *outR) { USED(sp); SPFLOAT overallscale; int cycleEnd; SPFLOAT size; SPFLOAT regen; SPFLOAT lowpass; SPFLOAT interpolate; SPFLOAT thunderAmount; SPFLOAT inputSampleL; SPFLOAT inputSampleR; overallscale = 1.0; overallscale *= v->onedsr; overallscale *= v->sr; cycleEnd = floor(overallscale); if (cycleEnd < 1) cycleEnd = 1; if (cycleEnd > 4) cycleEnd = 4; /* this is going to be 2 for 88.1 or 96k, * 3 for silly people, 4 for 176 or 192k */ /* sanity check */ if (v->cycle > cycleEnd-1) v->cycle = cycleEnd-1; size = (v->bigness*1.77)+0.1; regen = 0.0625+(v->longness*0.03125); /* 0.09375 max; */ lowpass = (1.0-pow(v->darkness,2.0))/sqrt(overallscale); interpolate = pow(v->darkness,2.0)*0.618033988749894848204586; /* has IIRlike qualities */ thunderAmount = (0.3-(v->longness*0.22))*v->darkness*0.1; if (size != v->psize) { v->psize = size; v->delayI = 3407.0*size; v->delayJ = 1823.0*size; v->delayK = 859.0*size; v->delayL = 331.0*size; v->delayA = 4801.0*size; v->delayB = 2909.0*size; v->delayC = 1153.0*size; v->delayD = 461.0*size; v->delayE = 7607.0*size; v->delayF = 4217.0*size; v->delayG = 2269.0*size; v->delayH = 1597.0*size; } inputSampleL = *inL; inputSampleR = *inR; if (fabs(v->iirAL)<1.18e-37) v->iirAL = 0.0; v->iirAL = (v->iirAL*(1.0-lowpass)) + (inputSampleL*lowpass); inputSampleL = v->iirAL; if (fabs(v->iirAR)<1.18e-37) v->iirAR = 0.0; v->iirAR = (v->iirAR*(1.0-lowpass))+ (inputSampleR*lowpass); inputSampleR = v->iirAR; /* initial filter */ v->cycle++; if (v->cycle == cycleEnd) { /* hit the end point and we do a reverb sample */ SPFLOAT ainterp = 1.0 - interpolate; v->feedbackAL = (v->feedbackAL*(ainterp))+ (v->previousAL*interpolate); v->previousAL = v->feedbackAL; v->feedbackBL = (v->feedbackBL*(ainterp))+ (v->previousBL*interpolate); v->previousBL = v->feedbackBL; v->feedbackCL = (v->feedbackCL*(ainterp))+ (v->previousCL*interpolate); v->previousCL = v->feedbackCL; v->feedbackDL = (v->feedbackDL*(ainterp))+ (v->previousDL*interpolate); v->previousDL = v->feedbackDL; v->feedbackAR = (v->feedbackAR*(ainterp))+ (v->previousAR*interpolate); v->previousAR = v->feedbackAR; v->feedbackBR = (v->feedbackBR*(ainterp))+ (v->previousBR*interpolate); v->previousBR = v->feedbackBR; v->feedbackCR = (v->feedbackCR*(ainterp))+ (v->previousCR*interpolate); v->previousCR = v->feedbackCR; v->feedbackDR = (v->feedbackDR*(ainterp))+ (v->previousDR*interpolate); v->previousDR = v->feedbackDR; v->thunderL = (v->thunderL*0.99)-(v->feedbackAL*thunderAmount); v->thunderR = (v->thunderR*0.99)-(v->feedbackAR*thunderAmount); v->aIL[v->countI] = inputSampleL + ((v->feedbackAL+v->thunderL) * regen); v->aJL[v->countJ] = inputSampleL + (v->feedbackBL * regen); v->aKL[v->countK] = inputSampleL + (v->feedbackCL * regen); v->aLL[v->countL] = inputSampleL + (v->feedbackDL * regen); v->aIR[v->countI] = inputSampleR + ((v->feedbackAR+v->thunderR) * regen); v->aJR[v->countJ] = inputSampleR + (v->feedbackBR * regen); v->aKR[v->countK] = inputSampleR + (v->feedbackCR * regen); v->aLR[v->countL] = inputSampleR + (v->feedbackDR * regen); v->countI++; if (v->countI < 0 || v->countI > v->delayI) v->countI = 0; v->countJ++; if (v->countJ < 0 || v->countJ > v->delayJ) v->countJ = 0; v->countK++; if (v->countK < 0 || v->countK > v->delayK) v->countK = 0; v->countL++; if (v->countL < 0 || v->countL > v->delayL) v->countL = 0; { SPFLOAT outIL = v->aIL[v->countI-((v->countI > v->delayI)?v->delayI+1:0)]; SPFLOAT outJL = v->aJL[v->countJ-((v->countJ > v->delayJ)?v->delayJ+1:0)]; SPFLOAT outKL = v->aKL[v->countK-((v->countK > v->delayK)?v->delayK+1:0)]; SPFLOAT outLL = v->aLL[v->countL-((v->countL > v->delayL)?v->delayL+1:0)]; SPFLOAT outIR = v->aIR[v->countI-((v->countI > v->delayI)?v->delayI+1:0)]; SPFLOAT outJR = v->aJR[v->countJ-((v->countJ > v->delayJ)?v->delayJ+1:0)]; SPFLOAT outKR = v->aKR[v->countK-((v->countK > v->delayK)?v->delayK+1:0)]; SPFLOAT outLR = v->aLR[v->countL-((v->countL > v->delayL)?v->delayL+1:0)]; /* first block: now we have four outputs */ v->aAL[v->countA] = (outIL - (outJL + outKL + outLL)); v->aBL[v->countB] = (outJL - (outIL + outKL + outLL)); v->aCL[v->countC] = (outKL - (outIL + outJL + outLL)); v->aDL[v->countD] = (outLL - (outIL + outJL + outKL)); v->aAR[v->countA] = (outIR - (outJR + outKR + outLR)); v->aBR[v->countB] = (outJR - (outIR + outKR + outLR)); v->aCR[v->countC] = (outKR - (outIR + outJR + outLR)); v->aDR[v->countD] = (outLR - (outIR + outJR + outKR)); } v->countA++; if (v->countA < 0 || v->countA > v->delayA) v->countA = 0; v->countB++; if (v->countB < 0 || v->countB > v->delayB) v->countB = 0; v->countC++; if (v->countC < 0 || v->countC > v->delayC) v->countC = 0; v->countD++; if (v->countD < 0 || v->countD > v->delayD) v->countD = 0; { SPFLOAT outAL = v->aAL[v->countA-((v->countA > v->delayA)?v->delayA+1:0)]; SPFLOAT outBL = v->aBL[v->countB-((v->countB > v->delayB)?v->delayB+1:0)]; SPFLOAT outCL = v->aCL[v->countC-((v->countC > v->delayC)?v->delayC+1:0)]; SPFLOAT outDL = v->aDL[v->countD-((v->countD > v->delayD)?v->delayD+1:0)]; SPFLOAT outAR = v->aAR[v->countA-((v->countA > v->delayA)?v->delayA+1:0)]; SPFLOAT outBR = v->aBR[v->countB-((v->countB > v->delayB)?v->delayB+1:0)]; SPFLOAT outCR = v->aCR[v->countC-((v->countC > v->delayC)?v->delayC+1:0)]; SPFLOAT outDR = v->aDR[v->countD-((v->countD > v->delayD)?v->delayD+1:0)]; /* second block: four more outputs */ v->aEL[v->countE] = (outAL - (outBL + outCL + outDL)); v->aFL[v->countF] = (outBL - (outAL + outCL + outDL)); v->aGL[v->countG] = (outCL - (outAL + outBL + outDL)); v->aHL[v->countH] = (outDL - (outAL + outBL + outCL)); v->aER[v->countE] = (outAR - (outBR + outCR + outDR)); v->aFR[v->countF] = (outBR - (outAR + outCR + outDR)); v->aGR[v->countG] = (outCR - (outAR + outBR + outDR)); v->aHR[v->countH] = (outDR - (outAR + outBR + outCR)); } v->countE++; if (v->countE < 0 || v->countE > v->delayE) v->countE = 0; v->countF++; if (v->countF < 0 || v->countF > v->delayF) v->countF = 0; v->countG++; if (v->countG < 0 || v->countG > v->delayG) v->countG = 0; v->countH++; if (v->countH < 0 || v->countH > v->delayH) v->countH = 0; { SPFLOAT outEL = v->aEL[v->countE-((v->countE > v->delayE)?v->delayE+1:0)]; SPFLOAT outFL = v->aFL[v->countF-((v->countF > v->delayF)?v->delayF+1:0)]; SPFLOAT outGL = v->aGL[v->countG-((v->countG > v->delayG)?v->delayG+1:0)]; SPFLOAT outHL = v->aHL[v->countH-((v->countH > v->delayH)?v->delayH+1:0)]; SPFLOAT outER = v->aER[v->countE-((v->countE > v->delayE)?v->delayE+1:0)]; SPFLOAT outFR = v->aFR[v->countF-((v->countF > v->delayF)?v->delayF+1:0)]; SPFLOAT outGR = v->aGR[v->countG-((v->countG > v->delayG)?v->delayG+1:0)]; SPFLOAT outHR = v->aHR[v->countH-((v->countH > v->delayH)?v->delayH+1:0)]; /* third block: final outputs */ v->feedbackAL = (outEL - (outFL + outGL + outHL)); v->feedbackBL = (outFL - (outEL + outGL + outHL)); v->feedbackCL = (outGL - (outEL + outFL + outHL)); v->feedbackDL = (outHL - (outEL + outFL + outGL)); v->feedbackAR = (outER - (outFR + outGR + outHR)); v->feedbackBR = (outFR - (outER + outGR + outHR)); v->feedbackCR = (outGR - (outER + outFR + outHR)); v->feedbackDR = (outHR - (outER + outFR + outGR)); /* which we need to feed back into the input again, a bit */ inputSampleL = (outEL + outFL + outGL + outHL) * 0.125; inputSampleR = (outER + outFR + outGR + outHR) * 0.125; } /* and take the final combined sum of outputs */ if (cycleEnd == 4) { /* start from previous last */ v->lastRefL[0] = v->lastRefL[4]; /* half */ v->lastRefL[2] = (v->lastRefL[0] + inputSampleL) * 0.5; /* one quarter */ v->lastRefL[1] = (v->lastRefL[0] + v->lastRefL[2]) * 0.5; /* three quarters */ v->lastRefL[3] = (v->lastRefL[2] + inputSampleL) * 0.5; /* full */ v->lastRefL[4] = inputSampleL; /* start from previous last */ v->lastRefR[0] = v->lastRefR[4]; /* half */ v->lastRefR[2] = (v->lastRefR[0] + inputSampleR) * 0.5; /* one quarter */ v->lastRefR[1] = (v->lastRefR[0] + v->lastRefR[2]) * 0.5; /* three quarters */ v->lastRefR[3] = (v->lastRefR[2] + inputSampleR) * 0.5; /* full */ v->lastRefR[4] = inputSampleR; } if (cycleEnd == 3) { /* start from previous last */ v->lastRefL[0] = v->lastRefL[3]; /* third */ v->lastRefL[2] = (v->lastRefL[0]+v->lastRefL[0]+inputSampleL) * 0.33333; /* two thirds */ v->lastRefL[1] = (v->lastRefL[0]+inputSampleL+inputSampleL) * 0.33333; /* full */ v->lastRefL[3] = inputSampleL; /* start from previous last */ v->lastRefR[0] = v->lastRefR[3]; /* third */ v->lastRefR[2] = (v->lastRefR[0]+v->lastRefR[0]+inputSampleR) * 0.33333; /* two thirds */ v->lastRefR[1] = (v->lastRefR[0]+inputSampleR+inputSampleR) * 0.33333; /* full */ v->lastRefR[3] = inputSampleR; } if (cycleEnd == 2) { /* start from previous last */ v->lastRefL[0] = v->lastRefL[2]; /* half */ v->lastRefL[1] = (v->lastRefL[0] + inputSampleL) * 0.5; /* full */ v->lastRefL[2] = inputSampleL; /* start from previous last */ v->lastRefR[0] = v->lastRefR[2]; /* half */ v->lastRefR[1] = (v->lastRefR[0] + inputSampleR) * 0.5; /* full */ v->lastRefR[2] = inputSampleR; } v->cycle = 0; /* reset */ } else { inputSampleL = v->lastRefL[v->cycle]; inputSampleR = v->lastRefR[v->cycle]; /* we are going through our references now */ } if (fabs(v->iirBL)<1.18e-37) v->iirBL = 0.0; v->iirBL = (v->iirBL*(1.0-lowpass))+(inputSampleL*lowpass); inputSampleL = v->iirBL; if (fabs(v->iirBR)<1.18e-37) v->iirBR = 0.0; v->iirBR = (v->iirBR*(1.0-lowpass))+(inputSampleR*lowpass); inputSampleR = v->iirBR; *outL = inputSampleL; *outR = inputSampleR; return SP_OK; } void sp_verbity_bigness(sp_verbity *c, SPFLOAT bigness) { c->bigness = bigness; } void sp_verbity_longness(sp_verbity *c, SPFLOAT longness) { c->longness = longness; } void sp_verbity_darkness(sp_verbity *c, SPFLOAT darkness) { c->darkness = darkness; }