/* Copyright (C) 1999 Juhana Sadeharju kouhia at nic.funet.fi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef GVERB_H #define GVERB_H #include #include #include #include "gverbdsp.h" #include "gverb.h" #include "ladspa-util.h" namespace rack_plugin_rcm { #define FDNORDER 4 typedef struct { int rate; float inputbandwidth; float taillevel; float earlylevel; ty_damper *inputdamper; float maxroomsize; float roomsize; float revtime; float maxdelay; float largestdelay; ty_fixeddelay **fdndels; float *fdngains; int *fdnlens; ty_damper **fdndamps; float fdndamping; ty_diffuser **ldifs; ty_diffuser **rdifs; ty_fixeddelay *tapdelay; int *taps; float *tapgains; float *d; float *u; float *f; double alpha; } ty_gverb; ty_gverb *gverb_new(int, float, float, float, float, float, float, float, float); void gverb_free(ty_gverb *); void gverb_flush(ty_gverb *); static void gverb_do(ty_gverb *, float, float *, float *); static void gverb_set_roomsize(ty_gverb *, float); static void gverb_set_revtime(ty_gverb *, float); static void gverb_set_damping(ty_gverb *, float); static void gverb_set_inputbandwidth(ty_gverb *, float); static void gverb_set_earlylevel(ty_gverb *, float); static void gverb_set_taillevel(ty_gverb *, float); /* * This FDN reverb can be made smoother by setting matrix elements at the * diagonal and near of it to zero or nearly zero. By setting diagonals to zero * means we remove the effect of the parallel comb structure from the * reverberation. A comb generates uniform impulse stream to the reverberation * impulse response, and thus it is not good. By setting near diagonal elements * to zero means we remove delay sequences having consequtive delays of the * similar lenths, when the delays are in sorted in length with respect to * matrix element index. The matrix described here could be generated by * differencing Rocchesso's circulant matrix at max diffuse value and at low * diffuse value (approaching parallel combs). * * Example 1: * Set a(k,k), for all k, equal to 0. * * Example 2: * Set a(k,k), a(k,k-1) and a(k,k+1) equal to 0. * * Example 3: The transition to zero gains could be smooth as well. * a(k,k-1) and a(k,k+1) could be 0.3, and a(k,k-2) and a(k,k+2) could * be 0.5, say. */ static __inline void gverb_fdnmatrix(float *a, float *b) { const float dl0 = a[0], dl1 = a[1], dl2 = a[2], dl3 = a[3]; b[0] = 0.5f*(+dl0 + dl1 - dl2 - dl3); b[1] = 0.5f*(+dl0 - dl1 - dl2 + dl3); b[2] = 0.5f*(-dl0 + dl1 - dl2 + dl3); b[3] = 0.5f*(+dl0 + dl1 + dl2 + dl3); } static __inline void gverb_do(ty_gverb *p, float x, float *yl, float *yr) { float z; unsigned int i; float lsum,rsum,sum,sign; if ((x != x) || fabsf(x) > 100000.0f) { x = 0.0f; } z = damper_do(p->inputdamper, x); z = diffuser_do(p->ldifs[0],z); for(i = 0; i < FDNORDER; i++) { p->u[i] = p->tapgains[i]*fixeddelay_read(p->tapdelay,p->taps[i]); } fixeddelay_write(p->tapdelay,z); for(i = 0; i < FDNORDER; i++) { p->d[i] = damper_do(p->fdndamps[i], p->fdngains[i]*fixeddelay_read(p->fdndels[i], p->fdnlens[i])); } sum = 0.0f; sign = 1.0f; for(i = 0; i < FDNORDER; i++) { sum += sign*(p->taillevel*p->d[i] + p->earlylevel*p->u[i]); sign = -sign; } sum += x*p->earlylevel; lsum = sum; rsum = sum; gverb_fdnmatrix(p->d,p->f); for(i = 0; i < FDNORDER; i++) { fixeddelay_write(p->fdndels[i],p->u[i]+p->f[i]); } lsum = diffuser_do(p->ldifs[1],lsum); lsum = diffuser_do(p->ldifs[2],lsum); lsum = diffuser_do(p->ldifs[3],lsum); rsum = diffuser_do(p->rdifs[1],rsum); rsum = diffuser_do(p->rdifs[2],rsum); rsum = diffuser_do(p->rdifs[3],rsum); *yl = lsum; *yr = rsum; } static __inline void gverb_set_roomsize(ty_gverb *p, const float a) { unsigned int i; if (a <= 1.0 || (a != a)) { p->roomsize = 1.0; } else { p->roomsize = a; } p->largestdelay = p->rate * p->roomsize * 0.00294f; p->fdnlens[0] = f_round(1.000000f*p->largestdelay); p->fdnlens[1] = f_round(0.816490f*p->largestdelay); p->fdnlens[2] = f_round(0.707100f*p->largestdelay); p->fdnlens[3] = f_round(0.632450f*p->largestdelay); for(i = 0; i < FDNORDER; i++) { p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); } p->taps[0] = 5+f_round(0.410f*p->largestdelay); p->taps[1] = 5+f_round(0.300f*p->largestdelay); p->taps[2] = 5+f_round(0.155f*p->largestdelay); p->taps[3] = 5+f_round(0.000f*p->largestdelay); for(i = 0; i < FDNORDER; i++) { p->tapgains[i] = powf((float)p->alpha, p->taps[i]); } } static __inline void gverb_set_revtime(ty_gverb *p,float a) { float ga,gt; double n; unsigned int i; p->revtime = a; ga = 60.0; gt = p->revtime; ga = powf(10.0f,-ga/20.0f); n = p->rate*gt; p->alpha = (double)powf(ga,1.0f/n); for(i = 0; i < FDNORDER; i++) { p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); } } static __inline void gverb_set_damping(ty_gverb *p,float a) { unsigned int i; p->fdndamping = a; for(i = 0; i < FDNORDER; i++) { damper_set(p->fdndamps[i],p->fdndamping); } } static __inline void gverb_set_inputbandwidth(ty_gverb *p,float a) { p->inputbandwidth = a; damper_set(p->inputdamper,1.0 - p->inputbandwidth); } static __inline void gverb_set_earlylevel(ty_gverb *p,float a) { p->earlylevel = a; } static __inline void gverb_set_taillevel(ty_gverb *p,float a) { p->taillevel = a; } } // namespace rack_plugin_rcm #endif