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;
}