Namespace: Un4seen.Bass
Assembly: Bass.Net (in Bass.Net.dll) Version: 2.4.17.5
public delegate void DSPPROC( int handle, int channel, IntPtr buffer, int length, IntPtr user )
Parameters
- handle
- Type: SystemInt32
The DSP handle (as returned by BASS_ChannelSetDSP(Int32, DSPPROC, IntPtr, Int32)). - channel
- Type: SystemInt32
Channel that the DSP is being applied to. - buffer
- Type: SystemIntPtr
The pointer to the buffer to apply the DSP to. The sample data is in standard Windows PCM format - 8-bit samples are unsigned, 16-bit samples are signed, 32-bit floating-point samples range from -1 to 1 (not clipped, so can actually be outside this range). - length
- Type: SystemInt32
The number of bytes to process. - user
- Type: SystemIntPtr
The user instance data given when BASS_ChannelSetDSP(Int32, DSPPROC, IntPtr, Int32) was called.
A DSP function should obviously be as quick as possible... playing streams, MOD musics and other DSP functions can not be processed until it has finished.
Some functions can cause problems if called from within a DSP (or stream) function. Do not call these functions from within a DSP callback:
BASS_Stop, BASS_Free, BASS_MusicLoad(String, Int64, Int32, BASSFlag, Int32), BASS_StreamCreate(Int32, Int32, BASSFlag, STREAMPROC, IntPtr) (or any other stream creation functions).
Also, do not call BASS_ChannelRemoveDSP(Int32, Int32) with the same DSP handle as received by the callback, or BASS_ChannelStop(Int32), BASS_MusicFree(Int32), BASS_StreamFree(Int32) with the same channel handle as received by the callback.
If the BASS_CONFIG_FLOATDSP config option is set, then DSP callback functions will always be passed 32-bit floating-point sample data, regardless of what the channels' actual sample format is.
It is clever to NOT alloc buffer data (e.g. a float[]) everytime within the callback method, since ALL callbacks should be really fast! And if you would do a 'float[] data = new float[]' every time here...the GarbageCollector would never really clean up that memory. Sideeffects might occure, due to the fact, that BASS will call this callback too fast and too often... However, this is not always the case, so in most examples it'll work just fine - but if you got problems - try moving any memory allocation things outside any callbacks.
NOTE: When you pass an instance of a callback delegate to one of the BASS functions, this delegate object will not be reference counted. This means .NET would not know, that it might still being used by BASS. The Garbage Collector might (re)move the delegate instance, if the variable holding the delegate is not declared as global. So make sure to always keep your delegate instance in a variable which lives as long as BASS needs it, e.g. use a global variable or member.
private DSPPROC _myDSPAddr; // make it global, so that the GC can not remove it private float[] _data; // local data buffer ... _myDSPAddr = new DSPPROC(MyDSPCallback); Bass.BASS_ChannelSetDSP(_stream, _myDSPAddr, IntPtr.Zero, 2); ... private void MyDSPCallback(int handle, int channel, IntPtr buffer, int length, IntPtr user) { if (length == 0 || buffer == IntPtr.Zero) return; // number of bytes in 32-bit floats, since length is in bytes int l4 = length/4; // increase the data buffer as needed if (_data == null || _data.Length < l4) _data = new float[l4]; // copy from managed to unmanaged memory Marshal.Copy(buffer, _data, 0, l4); // ... do your processing here // copy back from unmanaged to managed memory Marshal.Copy(_data, 0, buffer, l4); }
Note: such application must be compiled using the /unsafe compiler option!
myDSPAddr = new DSPPROC(MyDSPGainUnsafe); Bass.BASS_ChannelSetDSP(_stream, myDSPAddr, IntPtr.Zero, 2); ... // the unsafe callback private DSPPROC myDSPAddr; // make it global, so that the Garbage Collector can not remove it private void MyDSPGainUnsafe(int handle, int channel, IntPtr buffer, int length, IntPtr user) { if (_gainAmplification == 1f || length == 0 || buffer == IntPtr.Zero) return; // length is in bytes, so the number of floats to process is: // length/4 : byte = 8-bit, float = 32-bit int l4 = length/4; unsafe { float *data = (float*)buffer; for (int a=0; a<l4; a++) { data[a] *= _gainAmplification; } } }