#include "fluid_rev.h"
# if defined(WITH_FLOATX)
# define zap_almost_zero(sample) (((*(unsigned int*)&(sample))&0x7f800000) < 0x08000000)?0.0f:(sample)
# else
#define zap_almost_zero(sample) fabs(sample)<1e-10 ? 0 : sample;
#endif
#define DC_OFFSET 1e-8
typedef struct _fluid_allpass fluid_allpass;
typedef struct _fluid_comb fluid_comb;
struct _fluid_allpass {
fluid_real_t feedback;
fluid_real_t *buffer;
int bufsize;
int bufidx;
};
void fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size);
void fluid_allpass_init(fluid_allpass* allpass);
void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
void
fluid_allpass_setbuffer(fluid_allpass* allpass, fluid_real_t *buf, int size)
{
allpass->bufidx = 0;
allpass->buffer = buf;
allpass->bufsize = size;
}
void
fluid_allpass_init(fluid_allpass* allpass)
{
int i;
int len = allpass->bufsize;
fluid_real_t* buf = allpass->buffer;
for (i = 0; i < len; i++) {
buf[i] = DC_OFFSET;
}
}
void
fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val)
{
allpass->feedback = val;
}
fluid_real_t
fluid_allpass_getfeedback(fluid_allpass* allpass)
{
return allpass->feedback;
}
#define fluid_allpass_process(_allpass, _input) \
{ \
fluid_real_t output; \
fluid_real_t bufout; \
bufout = _allpass.buffer[_allpass.bufidx]; \
output = bufout-_input; \
_allpass.buffer[_allpass.bufidx] = _input + (bufout * _allpass.feedback); \
if (++_allpass.bufidx >= _allpass.bufsize) { \
_allpass.bufidx = 0; \
} \
_input = output; \
}
struct _fluid_comb {
fluid_real_t feedback;
fluid_real_t filterstore;
fluid_real_t damp1;
fluid_real_t damp2;
fluid_real_t *buffer;
int bufsize;
int bufidx;
};
void fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size);
void fluid_comb_init(fluid_comb* comb);
void fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val);
fluid_real_t fluid_comb_getdamp(fluid_comb* comb);
void fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val);
fluid_real_t fluid_comb_getfeedback(fluid_comb* comb);
void
fluid_comb_setbuffer(fluid_comb* comb, fluid_real_t *buf, int size)
{
comb->filterstore = 0;
comb->bufidx = 0;
comb->buffer = buf;
comb->bufsize = size;
}
void
fluid_comb_init(fluid_comb* comb)
{
int i;
fluid_real_t* buf = comb->buffer;
int len = comb->bufsize;
for (i = 0; i < len; i++) {
buf[i] = DC_OFFSET;
}
}
void
fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val)
{
comb->damp1 = val;
comb->damp2 = 1 - val;
}
fluid_real_t
fluid_comb_getdamp(fluid_comb* comb)
{
return comb->damp1;
}
void
fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val)
{
comb->feedback = val;
}
fluid_real_t
fluid_comb_getfeedback(fluid_comb* comb)
{
return comb->feedback;
}
#define fluid_comb_process(_comb, _input, _output) \
{ \
fluid_real_t _tmp = _comb.buffer[_comb.bufidx]; \
_comb.filterstore = (_tmp * _comb.damp2) + (_comb.filterstore * _comb.damp1); \
_comb.buffer[_comb.bufidx] = _input + (_comb.filterstore * _comb.feedback); \
if (++_comb.bufidx >= _comb.bufsize) { \
_comb.bufidx = 0; \
} \
_output += _tmp; \
}
#define numcombs 8
#define numallpasses 4
#define fixedgain 0.015f
#define scalewet 3.0f
#define scaledamp 1.0f
#define scaleroom 0.28f
#define offsetroom 0.7f
#define initialroom 0.5f
#define initialdamp 0.2f
#define initialwet 1
#define initialdry 0
#define initialwidth 1
#define stereospread 23
#define combtuningL1 1116
#define combtuningR1 1116 + stereospread
#define combtuningL2 1188
#define combtuningR2 1188 + stereospread
#define combtuningL3 1277
#define combtuningR3 1277 + stereospread
#define combtuningL4 1356
#define combtuningR4 1356 + stereospread
#define combtuningL5 1422
#define combtuningR5 1422 + stereospread
#define combtuningL6 1491
#define combtuningR6 1491 + stereospread
#define combtuningL7 1557
#define combtuningR7 1557 + stereospread
#define combtuningL8 1617
#define combtuningR8 1617 + stereospread
#define allpasstuningL1 556
#define allpasstuningR1 556 + stereospread
#define allpasstuningL2 441
#define allpasstuningR2 441 + stereospread
#define allpasstuningL3 341
#define allpasstuningR3 341 + stereospread
#define allpasstuningL4 225
#define allpasstuningR4 225 + stereospread
struct _fluid_revmodel_t {
fluid_real_t roomsize;
fluid_real_t damp;
fluid_real_t wet, wet1, wet2;
fluid_real_t width;
fluid_real_t gain;
fluid_comb combL[numcombs];
fluid_comb combR[numcombs];
fluid_allpass allpassL[numallpasses];
fluid_allpass allpassR[numallpasses];
fluid_real_t bufcombL1[combtuningL1];
fluid_real_t bufcombR1[combtuningR1];
fluid_real_t bufcombL2[combtuningL2];
fluid_real_t bufcombR2[combtuningR2];
fluid_real_t bufcombL3[combtuningL3];
fluid_real_t bufcombR3[combtuningR3];
fluid_real_t bufcombL4[combtuningL4];
fluid_real_t bufcombR4[combtuningR4];
fluid_real_t bufcombL5[combtuningL5];
fluid_real_t bufcombR5[combtuningR5];
fluid_real_t bufcombL6[combtuningL6];
fluid_real_t bufcombR6[combtuningR6];
fluid_real_t bufcombL7[combtuningL7];
fluid_real_t bufcombR7[combtuningR7];
fluid_real_t bufcombL8[combtuningL8];
fluid_real_t bufcombR8[combtuningR8];
fluid_real_t bufallpassL1[allpasstuningL1];
fluid_real_t bufallpassR1[allpasstuningR1];
fluid_real_t bufallpassL2[allpasstuningL2];
fluid_real_t bufallpassR2[allpasstuningR2];
fluid_real_t bufallpassL3[allpasstuningL3];
fluid_real_t bufallpassR3[allpasstuningR3];
fluid_real_t bufallpassL4[allpasstuningL4];
fluid_real_t bufallpassR4[allpasstuningR4];
};
void fluid_revmodel_update(fluid_revmodel_t* rev);
void fluid_revmodel_init(fluid_revmodel_t* rev);
fluid_revmodel_t*
new_fluid_revmodel()
{
fluid_revmodel_t* rev;
rev = FLUID_NEW(fluid_revmodel_t);
if (rev == NULL) {
return NULL;
}
fluid_comb_setbuffer(&rev->combL[0], rev->bufcombL1, combtuningL1);
fluid_comb_setbuffer(&rev->combR[0], rev->bufcombR1, combtuningR1);
fluid_comb_setbuffer(&rev->combL[1], rev->bufcombL2, combtuningL2);
fluid_comb_setbuffer(&rev->combR[1], rev->bufcombR2, combtuningR2);
fluid_comb_setbuffer(&rev->combL[2], rev->bufcombL3, combtuningL3);
fluid_comb_setbuffer(&rev->combR[2], rev->bufcombR3, combtuningR3);
fluid_comb_setbuffer(&rev->combL[3], rev->bufcombL4, combtuningL4);
fluid_comb_setbuffer(&rev->combR[3], rev->bufcombR4, combtuningR4);
fluid_comb_setbuffer(&rev->combL[4], rev->bufcombL5, combtuningL5);
fluid_comb_setbuffer(&rev->combR[4], rev->bufcombR5, combtuningR5);
fluid_comb_setbuffer(&rev->combL[5], rev->bufcombL6, combtuningL6);
fluid_comb_setbuffer(&rev->combR[5], rev->bufcombR6, combtuningR6);
fluid_comb_setbuffer(&rev->combL[6], rev->bufcombL7, combtuningL7);
fluid_comb_setbuffer(&rev->combR[6], rev->bufcombR7, combtuningR7);
fluid_comb_setbuffer(&rev->combL[7], rev->bufcombL8, combtuningL8);
fluid_comb_setbuffer(&rev->combR[7], rev->bufcombR8, combtuningR8);
fluid_allpass_setbuffer(&rev->allpassL[0], rev->bufallpassL1, allpasstuningL1);
fluid_allpass_setbuffer(&rev->allpassR[0], rev->bufallpassR1, allpasstuningR1);
fluid_allpass_setbuffer(&rev->allpassL[1], rev->bufallpassL2, allpasstuningL2);
fluid_allpass_setbuffer(&rev->allpassR[1], rev->bufallpassR2, allpasstuningR2);
fluid_allpass_setbuffer(&rev->allpassL[2], rev->bufallpassL3, allpasstuningL3);
fluid_allpass_setbuffer(&rev->allpassR[2], rev->bufallpassR3, allpasstuningR3);
fluid_allpass_setbuffer(&rev->allpassL[3], rev->bufallpassL4, allpasstuningL4);
fluid_allpass_setbuffer(&rev->allpassR[3], rev->bufallpassR4, allpasstuningR4);
fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
fluid_allpass_setfeedback(&rev->allpassL[1], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[1], 0.5f);
fluid_allpass_setfeedback(&rev->allpassL[2], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[2], 0.5f);
fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
rev->roomsize = initialroom * scaleroom + offsetroom;
rev->damp = initialdamp * scaledamp;
rev->wet = initialwet * scalewet;
rev->width = initialwidth;
rev->gain = fixedgain;
fluid_revmodel_update(rev);
fluid_revmodel_init(rev);
return rev;
}
void
delete_fluid_revmodel(fluid_revmodel_t* rev)
{
FLUID_FREE(rev);
}
void
fluid_revmodel_init(fluid_revmodel_t* rev)
{
int i;
for (i = 0; i < numcombs;i++) {
fluid_comb_init(&rev->combL[i]);
fluid_comb_init(&rev->combR[i]);
}
for (i = 0; i < numallpasses; i++) {
fluid_allpass_init(&rev->allpassL[i]);
fluid_allpass_init(&rev->allpassR[i]);
}
}
void
fluid_revmodel_reset(fluid_revmodel_t* rev)
{
fluid_revmodel_init(rev);
}
void
fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
int i, k = 0;
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
outL = outR = 0;
input = (2 * in[k] + DC_OFFSET) * rev->gain;
for (i = 0; i < numcombs; i++) {
fluid_comb_process(rev->combL[i], input, outL);
fluid_comb_process(rev->combR[i], input, outR);
}
for (i = 0; i < numallpasses; i++) {
fluid_allpass_process(rev->allpassL[i], outL);
fluid_allpass_process(rev->allpassR[i], outR);
}
outL -= DC_OFFSET;
outR -= DC_OFFSET;
left_out[k] = outL * rev->wet1 + outR * rev->wet2;
right_out[k] = outR * rev->wet1 + outL * rev->wet2;
}
}
void
fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
int i, k = 0;
fluid_real_t outL, outR, input;
for (k = 0; k < FLUID_BUFSIZE; k++) {
outL = outR = 0;
input = (2 * in[k] + DC_OFFSET) * rev->gain;
for (i = 0; i < numcombs; i++) {
fluid_comb_process(rev->combL[i], input, outL);
fluid_comb_process(rev->combR[i], input, outR);
}
for (i = 0; i < numallpasses; i++) {
fluid_allpass_process(rev->allpassL[i], outL);
fluid_allpass_process(rev->allpassR[i], outR);
}
outL -= DC_OFFSET;
outR -= DC_OFFSET;
left_out[k] += outL * rev->wet1 + outR * rev->wet2;
right_out[k] += outR * rev->wet1 + outL * rev->wet2;
}
}
void
fluid_revmodel_update(fluid_revmodel_t* rev)
{
int i;
rev->wet1 = rev->wet * (rev->width / 2 + 0.5f);
rev->wet2 = rev->wet * ((1 - rev->width) / 2);
for (i = 0; i < numcombs; i++) {
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
}
for (i = 0; i < numcombs; i++) {
fluid_comb_setdamp(&rev->combL[i], rev->damp);
fluid_comb_setdamp(&rev->combR[i], rev->damp);
}
}
void
fluid_revmodel_setroomsize(fluid_revmodel_t* rev, fluid_real_t value)
{
rev->roomsize = (value * scaleroom) + offsetroom;
fluid_revmodel_update(rev);
}
fluid_real_t
fluid_revmodel_getroomsize(fluid_revmodel_t* rev)
{
return (rev->roomsize - offsetroom) / scaleroom;
}
void
fluid_revmodel_setdamp(fluid_revmodel_t* rev, fluid_real_t value)
{
rev->damp = value * scaledamp;
fluid_revmodel_update(rev);
}
fluid_real_t
fluid_revmodel_getdamp(fluid_revmodel_t* rev)
{
return rev->damp / scaledamp;
}
void
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
{
fluid_clip(value, 0.0f, 1.0f);
rev->wet = value * scalewet;
fluid_revmodel_update(rev);
}
fluid_real_t
fluid_revmodel_getlevel(fluid_revmodel_t* rev)
{
return rev->wet / scalewet;
}
void
fluid_revmodel_setwidth(fluid_revmodel_t* rev, fluid_real_t value)
{
rev->width = value;
fluid_revmodel_update(rev);
}
fluid_real_t
fluid_revmodel_getwidth(fluid_revmodel_t* rev)
{
return rev->width;
}