/*=========================================================================================== DSP.EXE Copyright (c), Firelight Technologies Pty, Ltd, 1999-2003. This example demonstrates advanced DSP usage. You can now attach sounds to dsp units. The dsp units to be attached to must have a NULL callback. It is simply a holder for sounds to attach to, and have a specific position in the DSP chain.. see the diagram below for a visual representation of the DSP chain. It also demonstrates the use of hardware DirectX 8 FX. ===========================================================================================*/ /* Priority : 0 100 320-332 400 1000 Name : [CLEAR]-->[samp1-WET]-->[REVERB]-->[samp1-DRY]-->[CLIPCOPY]-->[SOUNDCARD] Note the above priority values correspond to the values in FMOD.H FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT 0 FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT 100 FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT 200 FSOUND_DSP_DEFAULTPRIORITY_USER 300 FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT 900 FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT 1000 Notice how 'SFX' unit is wet (has reverb). This is because it is the default destination For sound effects if NULL is passed to PlaySoundEx or PlaySound is used. Also the Reverb DSP has itself positioned AFTER the 'SFX' unit so then we will hear reverb. Now if a sound is attached to the 'Dry' DSP unit located at priority 400, then it will not be affected by reverb! */ /* INCLUDES */ #include #if defined(WIN32) || defined(__WATCOMC__) #include #include #elif defined(__linux__) #include "../../api/inc/wincompat.h" #endif #include #include #include "../../api/inc/fmod.h" #include "../../api/inc/fmod_errors.h" /* optional */ /* GLOBALS AND DEFINIITIONS */ /* Here's our simple reverb again */ #define REVERB_NUMTAPS 7 typedef struct { FSOUND_DSPUNIT *Unit; char *historybuff; /* storage space for tap history */ char *workarea; /* a place to hold 1 buffer worth of data (for preverb) */ int delayms; /* delay of p/reverb tab in milliseconds */ int volume; /* volume of p/reverb tab */ int pan; /* pan of p/reverb tab */ int historyoffset; /* running offset into history buffer */ int historylen; /* size of history buffer in SAMPLES */ } REVERBTAP; /* Reverb stuff */ REVERBTAP DSP_ReverbTap[REVERB_NUMTAPS]; /* Dry sfx unit */ FSOUND_DSPUNIT *DrySFXUnit = NULL; /* [ [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 DSP_LowPassBuffer. [RETURN_VALUE] a pointer to the buffer that was passed in, with a tap mixed into it. [REMARKS] ] */ void * F_CALLBACKAPI DSP_ReverbCallback(void *originalbuffer, void *newbuffer, int length, void *param) { int mixertype = FSOUND_GetMixer(); REVERBTAP *tap = (REVERBTAP *)param; #define MIXBUFFERFORMAT signed short /* This determines the format of the mixbuffer being passed in. change if you want to support int32 or float32 */ /* must be 16bit stereo integer buffer.. sorry fpu (32bit float) dont support this. */ if (mixertype == FSOUND_MIXER_BLENDMODE || mixertype == FSOUND_MIXER_QUALITY_FPU) { return newbuffer; } /* 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; int count; signed short *dest; MIXBUFFERFORMAT *src; /* Mix a scaled version of history buffer into output */ FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), taillen, 44100, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); FSOUND_DSP_MixBuffers((char *)newbuffer+((tap->historylen - tap->historyoffset) << 2), tap->historybuff, startlen, 44100, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); /* Now copy input into reverb/history buffer */ src = (MIXBUFFERFORMAT *)newbuffer; dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); for (count=0; count < taillen * 2; count++) /* *2 for stereo */ { int val = (int)src[count]; dest[count] = (signed short)(val < -32768 ? -32768 : val > 32767 ? 32767 : val); } src = (MIXBUFFERFORMAT *)((char *)newbuffer + ((tap->historylen - tap->historyoffset) * sizeof(MIXBUFFERFORMAT))); dest = (signed short *)tap->historybuff; for (count=0; count < startlen * 2; count++) { int val = (int)src[count]; dest[count] = (signed short)(val < -32768 ? -32768 : val > 32767 ? 32767 : val); } } /* No wrapping reverb buffer, just write dest */ else { int count; signed short *dest; MIXBUFFERFORMAT *src; /* Mix a scaled version of history buffer into output */ FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), length, 44100, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); /* Now copy input into reverb/history buffer */ src = (MIXBUFFERFORMAT *)newbuffer; dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); for (count=0; count < length * 2; count++) { int val = (int)src[count]; dest[count] = (signed short)(val < -32768 ? -32768 : val > 32767 ? 32767 : 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] [PARAMETERS] [RETURN_VALUE] [REMARKS] [SEE_ALSO] ] */ void SetupReverb() { /* REVERB SETUP */ /* something to fiddle with. */ int delay[REVERB_NUMTAPS] = { 131, 149, 173, 211, 281, 401, 457}; /* prime numbers make it sound cool! */ 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++) { DSP_ReverbTap[count].delayms = delay[count]; DSP_ReverbTap[count].volume = volume[count]; DSP_ReverbTap[count].pan = pan[count]; DSP_ReverbTap[count].historyoffset = 0; DSP_ReverbTap[count].historylen = (DSP_ReverbTap[count].delayms * 44100 / 1000); if (DSP_ReverbTap[count].historylen < FSOUND_DSP_GetBufferLength()) { DSP_ReverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); /* just in case our calc is not the same. */ } DSP_ReverbTap[count].historybuff = (char *)calloc(DSP_ReverbTap[count].historylen, 4); /* * 4 is for 16bit stereo (mmx only) */ DSP_ReverbTap[count].workarea = NULL; DSP_ReverbTap[count].Unit = FSOUND_DSP_Create(&DSP_ReverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+20+(count*2), &DSP_ReverbTap[count]); FSOUND_DSP_SetActive(DSP_ReverbTap[count].Unit, TRUE); } } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [SEE_ALSO] ] */ void CloseReverb() { int count; for (count=0; count