Files
BlitzNext/fmodapi375win/samples/fmod/reverb.c
T
Michael Fabain Dirks b75ca4142c x
2016-05-04 09:58:44 +02:00

419 lines
14 KiB
C

#include "reverb.h"
#include <string.h>
#include <stdlib.h>
/*
Pre-verb stuff
*/
REVERBTAP PreverbTap[PREVERB_NUMTAPS];
/*
Reverb stuff
*/
REVERBTAP ReverbTap[REVERB_NUMTAPS];
extern int outputfreq;
/*
[
[DESCRIPTION]
Callback to mix in one reverb tap. It copies the buffer into its own history buffer also.
[PARAMETERS]
'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down
through the dsp chain. They are in newbuffer.
'newbuffer' Pointer to buffer passed from previous DSP unit.
'length' Length in SAMPLES of buffer being passed.
'param' User parameter. In this case it is a pointer to LowPassBuffer.
[RETURN_VALUE]
a pointer to the buffer that was passed in, with a tap mixed into it.
[REMARKS]
]
*/
void * F_CALLBACKAPI ReverbCallback(void *originalbuffer, void *newbuffer, int length, void *userdata)
{
int mixertype = FSOUND_GetMixer();
int count;
int bytesperoutputsample;
REVERBTAP *tap = (REVERBTAP *)userdata;
union sample
{
void *vptr;
signed int *dptr;
signed short *wptr;
float *fptr;
};
if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
bytesperoutputsample = 4; // 16bit stereo
}
else
{
bytesperoutputsample = 8; // 32bit stereo
}
// reverb history buffer is a ringbuffer. If the length makes the copy wrap, then split the copy
// into end part, and start part..
if (tap->historyoffset + length > tap->historylen)
{
int taillen = tap->historylen - tap->historyoffset;
int startlen = length - taillen;
// mix a scaled version of history buffer into output
FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), taillen, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS);
FSOUND_DSP_MixBuffers((char *)newbuffer+(taillen * bytesperoutputsample), tap->historybuff, startlen, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS);
// now copy input into reverb/history buffer
{
signed short *dest;
union sample src;
dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2));
src.vptr = newbuffer;
for (count=0; count < taillen * 2; count++)
{
int val;
if (mixertype == FSOUND_MIXER_QUALITY_FPU)
{
val = (int)src.fptr[count];
}
else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
val = (int)src.wptr[count];
}
else
{
val = (int)src.dptr[count];
}
val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val);
dest[count] = val;
}
}
{
signed short *dest;
union sample src;
dest = (signed short *)tap->historybuff; // always 16bit
src.vptr = (char *)newbuffer + (taillen * bytesperoutputsample);
for (count=0; count < startlen * 2; count++)
{
int val;
if (mixertype == FSOUND_MIXER_QUALITY_FPU)
{
val = (int)src.fptr[count];
}
else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
val = (int)src.wptr[count];
}
else
{
val = (int)src.dptr[count];
}
val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val);
dest[count] = val;
}
}
}
// no wrapping reverb buffer, just write dest
else
{
// mix a scaled version of history buffer into output
FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), length, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS);
// now copy input into reverb/history buffer
{
signed short *dest;
union sample src = { newbuffer };
dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2));
for (count=0; count < length * 2; count++)
{
int val;
if (mixertype == FSOUND_MIXER_QUALITY_FPU)
{
val = (int)src.fptr[count];
}
else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
val = (int)src.wptr[count];
}
else
{
val = (int)src.dptr[count];
}
val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val);
dest[count] = val;
}
}
}
tap->historyoffset += length;
if (tap->historyoffset >= tap->historylen)
{
tap->historyoffset -= tap->historylen;
}
// reverb history has been mixed into new buffer, so return it.
return newbuffer;
}
/*
[
[DESCRIPTION]
Similair to a reverb tap except the history copy and the tap mix are done back to front.
[PARAMETERS]
'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down
through the dsp chain. They are in newbuffer.
'newbuffer' Pointer to buffer passed from previous DSP unit.
'length' Length in SAMPLES of buffer being passed.
'param' User parameter. In this case it is a pointer to a REVERBTAP structure
[RETURN_VALUE]
A pointer to the new modified buffer.
[REMARKS]
[SEE_ALSO]
LowPassCallback
]
*/
void * F_CALLBACKAPI PreverbCallback(void *originalbuffer, void *newbuffer, int length, void *userdata)
{
int mixertype = FSOUND_GetMixer();
int count;
REVERBTAP *tap = (REVERBTAP *)userdata;
int bytesperoutputsample;
union sample
{
void *vptr;
signed int *dptr;
signed short *wptr;
float *fptr;
};
if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
bytesperoutputsample = 4; // 16bit stereo
}
else
{
bytesperoutputsample = 8; // 32bit stereo
}
// preverbbuff is a ringbuffer. If the length makes the copy wrap, then split the copy
// into end part, and start part
if (tap->historyoffset + length > tap->historylen)
{
int taillen = tap->historylen - tap->historyoffset;
int startlen = length - taillen; // whatever is left
// get a clean version of the preverb buffer (should be an unscaled history of the mixbuffer)
memcpy(tap->workarea, tap->historybuff + (tap->historyoffset * bytesperoutputsample), taillen * bytesperoutputsample);
memcpy(tap->workarea + (taillen * bytesperoutputsample), tap->historybuff, (length - taillen) * bytesperoutputsample);
// now copy input into preverb/history buffer
memcpy(tap->historybuff + (tap->historyoffset * bytesperoutputsample), newbuffer, taillen * bytesperoutputsample);
memcpy(tap->historybuff, (signed char *)newbuffer + (taillen * bytesperoutputsample), (length - taillen) * bytesperoutputsample);
}
// no wrapping preverb buffer, just write dest
else
{
// get a clean version of the preverb buffer (should be an unscaled history of the mixbuffer)
memcpy(tap->workarea, tap->historybuff + (tap->historyoffset * bytesperoutputsample), length * bytesperoutputsample);
// now copy input into preverb/history buffer
memcpy(tap->historybuff + (tap->historyoffset * bytesperoutputsample), newbuffer, length * bytesperoutputsample);
}
/*
Now we mix a copy of the NEW input into our preverbed buffer
*/
{
union sample src = { newbuffer };
signed short *dest = (signed short *)tap->workarea2;
for (count=0; count < length * 2; count++)
{
int val;
if (mixertype == FSOUND_MIXER_QUALITY_FPU)
{
val = (int)src.fptr[count];
}
else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
val = (int)src.wptr[count];
}
else
{
val = (int)src.dptr[count];
}
val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val);
dest[count] = val;
}
}
// now mix a scaled input into this
FSOUND_DSP_MixBuffers(tap->workarea, tap->workarea2, length, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS);
tap->historyoffset += length;
if (tap->historyoffset >= tap->historylen)
{
tap->historyoffset -= tap->historylen;
}
// preverb history has been mixed into new buffer, so return it.
return tap->workarea;
}
void Reverb_Init()
{
int bytesperoutputsample;
int mixertype = FSOUND_GetMixer();
if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
bytesperoutputsample = 4; // 16bit stereo
}
else
{
bytesperoutputsample = 8; // 32bit stereo
}
// ====================================================================================================================
// PREVERB SETUP
// ====================================================================================================================
{
int delay[PREVERB_NUMTAPS] = { 57, 97, 163 }; // // prime numbers! dont go lower than 20! it will be smaller than the DSP bufferlen!! (a check is done below for this)
int volume[PREVERB_NUMTAPS] = { 128, 78, 46 };
int pan[PREVERB_NUMTAPS] = { 128-24, 128+24, 128 };
int count;
for (count=0; count< PREVERB_NUMTAPS; count++)
{
PreverbTap[count].delayms = delay[count];
PreverbTap[count].volume = volume[count];
PreverbTap[count].pan = pan[count];
PreverbTap[count].historyoffset = 0;
PreverbTap[count].historylen = (PreverbTap[count].delayms * outputfreq / 1000);
if (PreverbTap[count].historylen < FSOUND_DSP_GetBufferLength())
{
PreverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); // just in case our calc is not the same.
}
PreverbTap[count].historybuff = calloc(PreverbTap[count].historylen + 2048, bytesperoutputsample);
PreverbTap[count].workarea = calloc(FSOUND_DSP_GetBufferLength(), bytesperoutputsample);
PreverbTap[count].workarea2 = calloc(FSOUND_DSP_GetBufferLength(), 4);
PreverbTap[count].Unit = FSOUND_DSP_Create(&PreverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+count, &PreverbTap[count]);
}
}
// ====================================================================================================================
// REVERB SETUP
// ====================================================================================================================
{
// something to fiddle with..
int delay[REVERB_NUMTAPS] = { 131, 149, 173, 211, 281, 401, 457}; // prime numbers!
int volume[REVERB_NUMTAPS] = { 120, 100, 95, 90, 80, 60, 50};
int pan[REVERB_NUMTAPS] = { 100, 128, 128, 152, 128, 100, 152};
int count;
for (count=0; count< REVERB_NUMTAPS; count++)
{
ReverbTap[count].delayms = delay[count];
ReverbTap[count].volume = volume[count];
ReverbTap[count].pan = pan[count];
ReverbTap[count].historyoffset = 0;
ReverbTap[count].historylen = (ReverbTap[count].delayms * outputfreq / 1000);
if (ReverbTap[count].historylen < FSOUND_DSP_GetBufferLength())
{
ReverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); // just in case our calc is not the same.
}
ReverbTap[count].historybuff = calloc(ReverbTap[count].historylen, 4); // * 4 is for 16bit stereo buffer
ReverbTap[count].workarea = NULL;
ReverbTap[count].workarea2 = NULL;
ReverbTap[count].Unit = FSOUND_DSP_Create(&ReverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+20+(count*2), &ReverbTap[count]);
}
}
}
void Reverb_Close()
{
int count;
for (count=0; count<PREVERB_NUMTAPS; count++)
{
if (PreverbTap[count].Unit)
{
FSOUND_DSP_Free(PreverbTap[count].Unit);
}
PreverbTap[count].Unit = NULL;
if (PreverbTap[count].historybuff)
{
free(PreverbTap[count].historybuff);
}
PreverbTap[count].historybuff = NULL;
if (PreverbTap[count].workarea)
{
free(PreverbTap[count].workarea);
}
PreverbTap[count].workarea = NULL;
if (PreverbTap[count].workarea2)
{
free(PreverbTap[count].workarea2);
}
PreverbTap[count].workarea2 = NULL;
}
for (count=0; count<REVERB_NUMTAPS; count++)
{
if (ReverbTap[count].Unit)
{
FSOUND_DSP_Free(ReverbTap[count].Unit);
}
ReverbTap[count].Unit = NULL;
if (ReverbTap[count].historybuff)
{
free(ReverbTap[count].historybuff);
}
ReverbTap[count].historybuff = NULL;
if (ReverbTap[count].workarea)
{
free(ReverbTap[count].workarea);
}
ReverbTap[count].workarea = NULL;
if (ReverbTap[count].workarea2)
{
free(ReverbTap[count].workarea2);
}
ReverbTap[count].workarea2 = NULL;
}
}