BASS.NET API for the Un4seen BASS Audio Library

RECORDPROC Delegate

BASS.NET API for the Un4seen BASS Audio Library
User defined callback function to process recorded sample data.

Namespace:  Un4seen.Bass
Assembly:  Bass.Net (in Bass.Net.dll) Version: 2.4.17.5
Syntax

public delegate bool RECORDPROC(
	int handle,
	IntPtr buffer,
	int length,
	IntPtr user
)

Parameters

handle
Type: SystemInt32
The recording handle that the data is from.
buffer
Type: SystemIntPtr
The pointer to the buffer containing the recorded sample data. The sample data is in standard Windows PCM format, that is 8-bit samples are unsigned, 16-bit samples are signed, 32-bit floating-point samples range from -1 to +1.
length
Type: SystemInt32
The number of bytes in the buffer.
user
Type: SystemIntPtr
The user instance data given when BASS_RecordStart(Int32, Int32, BASSFlag, RECORDPROC, IntPtr) was called.

Return Value

Type: Boolean
Return to stop recording, and anything else to continue recording.
Remarks

BASS_RecordFree should not be used to free the recording device within a recording callback function. Nor should BASS_ChannelStop(Int32) be used to stop the recording; return to do that instead.

It is clever to NOT alloc any buffer data (e.g. a byte[]) everytime within the callback method, since ALL callbacks should be really fast! And if you would do a 'byte[] data = new byte[]' 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...

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.

Examples

private RECORDPROC _myRecProc; // make it global, so that the GC can not remove it
private int _byteswritten = 0;
private byte[] _recbuffer; // local recording buffer
...
if ( Bass.BASS_RecordInit(-1) )
{
  _myRecProc = new RECORDPROC(MyRecording);
  int recHandle = Bass.BASS_RecordStart(44100, 2, BASSFlag.BASS_RECORD_PAUSE, _myRecProc, IntPtr.Zero);
  ...
  // start recording
  Bass.BASS_ChannelPlay(recHandle, false);
}
...
private bool MyRecording(int handle, IntPtr buffer, int length, IntPtr user)
{
  bool cont = true;
  if (length > 0 && buffer != IntPtr.Zero)
  {
    // increase the rec buffer as needed
    if (_recbuffer == null || _recbuffer.Length < length)
      _recbuffer = new byte[length];
    // copy from managed to unmanaged memory
    Marshal.Copy(buffer, _recbuffer, 0, length);
    _byteswritten += length;
    // write to file
    ...
    // stop recording after a certain amout (just to demo)
    if (_byteswritten > 800000)
      cont = false; // stop recording
  }
  return cont;
}
If you are into C# you might also use an unsafe codeblock with native pointer access (which might be must faster than the above - depending on what you are doing with the data):
C#
private unsafe bool MyRecording(int handle, IntPtr buffer, int length, IntPtr user)
{
  bool cont = true;
  if (length > 0 && buffer != IntPtr.Zero)
  {
    // assuming 16-bit sample data here
    short *data = (short*)buffer;
    ...

    // stop recording after a certain amout (just to demo)
    if (_byteswritten > 800000)
      cont = false; // stop recording
  }
  return cont;
}
See Also

Reference