aboutsummaryrefslogblamecommitdiffstats
path: root/plugins/WinVST/TapeDelay/TapeDelayProc.cpp
blob: e2f1ade22e5726696ef3d764a26944333d9855ca (plain) (tree)





























































































































































                                                                                                                              







                                                                                               








                                     





















































































































































                                                                                                                              









                                                                                               








                                     
 
/* ========================================
 *  TapeDelay - TapeDelay.h
 *  Copyright (c) 2016 airwindows, All rights reserved
 * ======================================== */

#ifndef __TapeDelay_H
#include "TapeDelay.h"
#endif

void TapeDelay::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames) 
{
    float* in1  =  inputs[0];
    float* in2  =  inputs[1];
    float* out1 = outputs[0];
    float* out2 = outputs[1];

	double dry = pow(A,2);
	double wet = pow(B,2);
	int targetdelay = (int)(44000*C);
	double feedback = (D*1.3);
	double leanfat = ((E*2.0)-1.0);
	double fatwet = fabs(leanfat);
	int fatness = (int)floor((F*29.0)+3.0);
	int count;
	
	double storedelayL;
	double storedelayR;
	double sumL = 0.0;
	double sumR = 0.0;
	double floattotalL = 0.0;
	double floattotalR = 0.0;
	int sumtotalL = 0;
	int sumtotalR = 0;
	
    
    while (--sampleFrames >= 0)
    {
		long double inputSampleL = *in1;
		long double inputSampleR = *in2;

		static int noisesourceL = 0;
		static int noisesourceR = 850010;
		int residue;
		double applyresidue;
		
		noisesourceL = noisesourceL % 1700021; noisesourceL++;
		residue = noisesourceL * noisesourceL;
		residue = residue % 170003; residue *= residue;
		residue = residue % 17011; residue *= residue;
		residue = residue % 1709; residue *= residue;
		residue = residue % 173; residue *= residue;
		residue = residue % 17;
		applyresidue = residue;
		applyresidue *= 0.00000001;
		applyresidue *= 0.00000001;
		inputSampleL += applyresidue;
		if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
			inputSampleL -= applyresidue;
		}
		
		noisesourceR = noisesourceR % 1700021; noisesourceR++;
		residue = noisesourceR * noisesourceR;
		residue = residue % 170003; residue *= residue;
		residue = residue % 17011; residue *= residue;
		residue = residue % 1709; residue *= residue;
		residue = residue % 173; residue *= residue;
		residue = residue % 17;
		applyresidue = residue;
		applyresidue *= 0.00000001;
		applyresidue *= 0.00000001;
		inputSampleR += applyresidue;
		if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
			inputSampleR -= applyresidue;
		}
		//for live air, we always apply the dither noise. Then, if our result is 
		//effectively digital black, we'll subtract it again. We want a 'air' hiss
		
		if (gcount < 0 || gcount > 128) {gcount = 128;}
		count = gcount;
		if (delay < 0 || delay > maxdelay) {delay = maxdelay;}
		
		sumL = inputSampleL + (dL[delay]*feedback);
		sumR = inputSampleR + (dR[delay]*feedback);
		pL[count+128] = pL[count] = sumtotalL = (int)(sumL*8388608.0);
		pR[count+128] = pR[count] = sumtotalR = (int)(sumR*8388608.0);
		
		switch (fatness)
		{
			case 32: sumtotalL += pL[count+127]; sumtotalR += pR[count+127]; //note NO break statement.
			case 31: sumtotalL += pL[count+113]; sumtotalR += pR[count+113]; //This jumps to the relevant tap
			case 30: sumtotalL += pL[count+109]; sumtotalR += pR[count+109]; //and then includes all smaller taps.
			case 29: sumtotalL += pL[count+107]; sumtotalR += pR[count+107];
			case 28: sumtotalL += pL[count+103]; sumtotalR += pR[count+103];
			case 27: sumtotalL += pL[count+101]; sumtotalR += pR[count+101];
			case 26: sumtotalL += pL[count+97]; sumtotalR += pR[count+97];
			case 25: sumtotalL += pL[count+89]; sumtotalR += pR[count+89];
			case 24: sumtotalL += pL[count+83]; sumtotalR += pR[count+83];
			case 23: sumtotalL += pL[count+79]; sumtotalR += pR[count+79];
			case 22: sumtotalL += pL[count+73]; sumtotalR += pR[count+73];
			case 21: sumtotalL += pL[count+71]; sumtotalR += pR[count+71];
			case 20: sumtotalL += pL[count+67]; sumtotalR += pR[count+67];
			case 19: sumtotalL += pL[count+61]; sumtotalR += pR[count+61];
			case 18: sumtotalL += pL[count+59]; sumtotalR += pR[count+59];
			case 17: sumtotalL += pL[count+53]; sumtotalR += pR[count+53];
			case 16: sumtotalL += pL[count+47]; sumtotalR += pR[count+47];
			case 15: sumtotalL += pL[count+43]; sumtotalR += pR[count+43];
			case 14: sumtotalL += pL[count+41]; sumtotalR += pR[count+41];
			case 13: sumtotalL += pL[count+37]; sumtotalR += pR[count+37];
			case 12: sumtotalL += pL[count+31]; sumtotalR += pR[count+31];
			case 11: sumtotalL += pL[count+29]; sumtotalR += pR[count+29];
			case 10: sumtotalL += pL[count+23]; sumtotalR += pR[count+23];
			case 9: sumtotalL += pL[count+19]; sumtotalR += pR[count+19];
			case 8: sumtotalL += pL[count+17]; sumtotalR += pR[count+17];
			case 7: sumtotalL += pL[count+13]; sumtotalR += pR[count+13];
			case 6: sumtotalL += pL[count+11]; sumtotalR += pR[count+11];
			case 5: sumtotalL += pL[count+7]; sumtotalR += pR[count+7];
			case 4: sumtotalL += pL[count+5]; sumtotalR += pR[count+5];
			case 3: sumtotalL += pL[count+3]; sumtotalR += pR[count+3];
			case 2: sumtotalL += pL[count+2]; sumtotalR += pR[count+2];
			case 1: sumtotalL += pL[count+1]; sumtotalR += pR[count+1];
		}
		
		floattotalL = (double)(sumtotalL/fatness+1);
		floattotalR = (double)(sumtotalR/fatness+1);
		floattotalL /= 8388608.0;
		floattotalR /= 8388608.0;
		floattotalL *= fatwet;
		floattotalR *= fatwet;
		if (leanfat < 0) {storedelayL = sumL-floattotalL; storedelayR = sumR-floattotalR;}
		else {storedelayL = (sumL * (1-fatwet))+floattotalL; storedelayR = (sumR * (1-fatwet))+floattotalR;}
		
		chase += abs(maxdelay - targetdelay);
		if (chase > 9000)
		{
			if (maxdelay > targetdelay) {
				dL[delay] = storedelayL; dR[delay] = storedelayR;
				maxdelay -= 1; delay -= 1; if (delay < 0) {delay = maxdelay;}
				dL[delay] = storedelayL; dR[delay] = storedelayR;
			}
			if (maxdelay < targetdelay) {
				maxdelay += 1; delay += 1; if (delay > maxdelay) {delay = 0;}
				dL[delay] = storedelayL; dR[delay] = storedelayR;
			}
			chase = 0;
		}
		else
		{
			dL[delay] = storedelayL; dR[delay] = storedelayR;
		}
		
		gcount--;
		delay--;
		if (delay < 0 || delay > maxdelay) {delay = maxdelay;}
		//yes this is a second bounds check. it's cheap, check EVERY time
		
		inputSampleL = (inputSampleL * dry) + (dL[delay] * wet);		
		inputSampleR = (inputSampleR * dry) + (dR[delay] * wet);				
		
		//stereo 32 bit dither, made small and tidy.
		int expon; frexpf((float)inputSampleL, &expon);
		long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
		inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
		frexpf((float)inputSampleR, &expon);
		dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
		inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
		//end 32 bit dither
		
		*out1 = inputSampleL;
		*out2 = inputSampleR;

		*in1++;
		*in2++;
		*out1++;
		*out2++;
    }
}

void TapeDelay::processDoubleReplacing(double **inputs, double **outputs, VstInt32 sampleFrames) 
{
    double* in1  =  inputs[0];
    double* in2  =  inputs[1];
    double* out1 = outputs[0];
    double* out2 = outputs[1];

	double dry = pow(A,2);
	double wet = pow(B,2);
	int targetdelay = (int)(44000*C);
	double feedback = (D*1.3);
	double leanfat = ((E*2.0)-1.0);
	double fatwet = fabs(leanfat);
	int fatness = (int)floor((F*29.0)+3.0);
	int count;
	
	double storedelayL;
	double storedelayR;
	double sumL = 0.0;
	double sumR = 0.0;
	double floattotalL = 0.0;
	double floattotalR = 0.0;
	int sumtotalL = 0;
	int sumtotalR = 0;
	
    while (--sampleFrames >= 0)
    {
		long double inputSampleL = *in1;
		long double inputSampleR = *in2;

		static int noisesourceL = 0;
		static int noisesourceR = 850010;
		int residue;
		double applyresidue;
		
		noisesourceL = noisesourceL % 1700021; noisesourceL++;
		residue = noisesourceL * noisesourceL;
		residue = residue % 170003; residue *= residue;
		residue = residue % 17011; residue *= residue;
		residue = residue % 1709; residue *= residue;
		residue = residue % 173; residue *= residue;
		residue = residue % 17;
		applyresidue = residue;
		applyresidue *= 0.00000001;
		applyresidue *= 0.00000001;
		inputSampleL += applyresidue;
		if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
			inputSampleL -= applyresidue;
		}
		
		noisesourceR = noisesourceR % 1700021; noisesourceR++;
		residue = noisesourceR * noisesourceR;
		residue = residue % 170003; residue *= residue;
		residue = residue % 17011; residue *= residue;
		residue = residue % 1709; residue *= residue;
		residue = residue % 173; residue *= residue;
		residue = residue % 17;
		applyresidue = residue;
		applyresidue *= 0.00000001;
		applyresidue *= 0.00000001;
		inputSampleR += applyresidue;
		if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
			inputSampleR -= applyresidue;
		}
		//for live air, we always apply the dither noise. Then, if our result is 
		//effectively digital black, we'll subtract it again. We want a 'air' hiss
		
		if (gcount < 0 || gcount > 128) {gcount = 128;}
		count = gcount;
		if (delay < 0 || delay > maxdelay) {delay = maxdelay;}
		
		sumL = inputSampleL + (dL[delay]*feedback);
		sumR = inputSampleR + (dR[delay]*feedback);
		pL[count+128] = pL[count] = sumtotalL = (int)(sumL*8388608.0);
		pR[count+128] = pR[count] = sumtotalR = (int)(sumR*8388608.0);
		
		switch (fatness)
		{
			case 32: sumtotalL += pL[count+127]; sumtotalR += pR[count+127]; //note NO break statement.
			case 31: sumtotalL += pL[count+113]; sumtotalR += pR[count+113]; //This jumps to the relevant tap
			case 30: sumtotalL += pL[count+109]; sumtotalR += pR[count+109]; //and then includes all smaller taps.
			case 29: sumtotalL += pL[count+107]; sumtotalR += pR[count+107];
			case 28: sumtotalL += pL[count+103]; sumtotalR += pR[count+103];
			case 27: sumtotalL += pL[count+101]; sumtotalR += pR[count+101];
			case 26: sumtotalL += pL[count+97]; sumtotalR += pR[count+97];
			case 25: sumtotalL += pL[count+89]; sumtotalR += pR[count+89];
			case 24: sumtotalL += pL[count+83]; sumtotalR += pR[count+83];
			case 23: sumtotalL += pL[count+79]; sumtotalR += pR[count+79];
			case 22: sumtotalL += pL[count+73]; sumtotalR += pR[count+73];
			case 21: sumtotalL += pL[count+71]; sumtotalR += pR[count+71];
			case 20: sumtotalL += pL[count+67]; sumtotalR += pR[count+67];
			case 19: sumtotalL += pL[count+61]; sumtotalR += pR[count+61];
			case 18: sumtotalL += pL[count+59]; sumtotalR += pR[count+59];
			case 17: sumtotalL += pL[count+53]; sumtotalR += pR[count+53];
			case 16: sumtotalL += pL[count+47]; sumtotalR += pR[count+47];
			case 15: sumtotalL += pL[count+43]; sumtotalR += pR[count+43];
			case 14: sumtotalL += pL[count+41]; sumtotalR += pR[count+41];
			case 13: sumtotalL += pL[count+37]; sumtotalR += pR[count+37];
			case 12: sumtotalL += pL[count+31]; sumtotalR += pR[count+31];
			case 11: sumtotalL += pL[count+29]; sumtotalR += pR[count+29];
			case 10: sumtotalL += pL[count+23]; sumtotalR += pR[count+23];
			case 9: sumtotalL += pL[count+19]; sumtotalR += pR[count+19];
			case 8: sumtotalL += pL[count+17]; sumtotalR += pR[count+17];
			case 7: sumtotalL += pL[count+13]; sumtotalR += pR[count+13];
			case 6: sumtotalL += pL[count+11]; sumtotalR += pR[count+11];
			case 5: sumtotalL += pL[count+7]; sumtotalR += pR[count+7];
			case 4: sumtotalL += pL[count+5]; sumtotalR += pR[count+5];
			case 3: sumtotalL += pL[count+3]; sumtotalR += pR[count+3];
			case 2: sumtotalL += pL[count+2]; sumtotalR += pR[count+2];
			case 1: sumtotalL += pL[count+1]; sumtotalR += pR[count+1];
		}
		
		floattotalL = (double)(sumtotalL/fatness+1);
		floattotalR = (double)(sumtotalR/fatness+1);
		floattotalL /= 8388608.0;
		floattotalR /= 8388608.0;
		floattotalL *= fatwet;
		floattotalR *= fatwet;
		if (leanfat < 0) {storedelayL = sumL-floattotalL; storedelayR = sumR-floattotalR;}
		else {storedelayL = (sumL * (1-fatwet))+floattotalL; storedelayR = (sumR * (1-fatwet))+floattotalR;}
		
		chase += abs(maxdelay - targetdelay);
		if (chase > 9000)
		{
			if (maxdelay > targetdelay) {
				dL[delay] = storedelayL; dR[delay] = storedelayR;
				maxdelay -= 1; delay -= 1; if (delay < 0) {delay = maxdelay;}
				dL[delay] = storedelayL; dR[delay] = storedelayR;
			}
			if (maxdelay < targetdelay) {
				maxdelay += 1; delay += 1; if (delay > maxdelay) {delay = 0;}
				dL[delay] = storedelayL; dR[delay] = storedelayR;
			}
			chase = 0;
		}
		else
		{
			dL[delay] = storedelayL; dR[delay] = storedelayR;
		}
		
		gcount--;
		delay--;
		if (delay < 0 || delay > maxdelay) {delay = maxdelay;}
		//yes this is a second bounds check. it's cheap, check EVERY time
		
		inputSampleL = (inputSampleL * dry) + (dL[delay] * wet);		
		inputSampleR = (inputSampleR * dry) + (dR[delay] * wet);				
		
		//stereo 64 bit dither, made small and tidy.
		int expon; frexp((double)inputSampleL, &expon);
		long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
		dither /= 536870912.0; //needs this to scale to 64 bit zone
		inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
		frexp((double)inputSampleR, &expon);
		dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
		dither /= 536870912.0; //needs this to scale to 64 bit zone
		inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
		//end 64 bit dither
		
		*out1 = inputSampleL;
		*out2 = inputSampleR;

		*in1++;
		*in2++;
		*out1++;
		*out2++;
    }
}