BASS.NET API for the Un4seen BASS Audio Library

BassBASS_ChannelGetData Method (Int32, IntPtr, Int32)

BASS.NET API for the Un4seen BASS Audio Library
Retrieves the immediate sample data (or an FFT representation of it) of a sample channel, stream, MOD music, or recording channel. This overload uses an IntPtr to reference the buffer data.

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

[DllImportAttribute("bass")]
public static int BASS_ChannelGetData(
	int handle,
	IntPtr buffer,
	int length
)

Parameters

handle
Type: SystemInt32
The channel handle... a HCHANNEL, HMUSIC, HSTREAM, or HRECORD.
buffer
Type: SystemIntPtr
Location to write the data as an IntPtr (can be Zero when handle is a recording channel (HRECORD), to discard the requested amount of data from the recording buffer).

Use "Marshal.AllocCoTaskMem" to allocate a memory buffer, use "Marshal.Copy" to copy the buffer data from unmanaged BASS to your managed code and use "Marshal.FreeCoTaskMem" to free the memory buffer when not needed anymore.

Or make use of a "GCHandle" to receive data to a pinned managed object.

length
Type: SystemInt32
Number of bytes wanted, and/or the following flags (BASSData):
BASS_DATA_FLOATReturn floating-point sample data.
BASS_DATA_FIXEDReturn 8.24 fixed-point data.
BASS_DATA_FFT256256 sample FFT (returns 128 floating-point values)
BASS_DATA_FFT512512 sample FFT (returns 256 floating-point values)
BASS_DATA_FFT10241024 sample FFT (returns 512 floating-point values)
BASS_DATA_FFT20482048 sample FFT (returns 1024 floating-point values)
BASS_DATA_FFT40964096 sample FFT (returns 2048 floating-point values)
BASS_DATA_FFT81928192 sample FFT (returns 4096 floating-point values)
BASS_DATA_FFT1638416384 sample FFT (returns 8192 floating-point values)
BASS_DATA_FFT3276816384 sample FFT (returns 16384 floating-point values)
BASS_DATA_FFT_COMPLEXReturn the complex FFT result rather than the magnitudes. This increases the amount of data returned (as listed above) fourfold, as it returns real and imaginary parts and the full FFT result (not only the first half). The real and imaginary parts are interleaved in the returned data.
BASS_DATA_FFT_INDIVIDUALPerform a separate FFT for each channel, rather than a single combined FFT. The size of the data returned (as listed above) is multiplied by the number of channels.
BASS_DATA_FFT_NOWINDOWPrevent a Hann window being applied to the sample data when performing an FFT.
BASS_DATA_FFT_NYQUISTReturn an extra value for the Nyquist frequency magnitude. The Nyquist frequency is always included in a complex FFT result.
BASS_DATA_FFT_REMOVEDCRemove any DC bias from the sample data when performing an FFT.
BASS_DATA_NOREMOVEDo not remove the data from a recording channel's buffer. This is automatic if the recording channel is using a RECORDPROC callback function. This flag is ignored on other channel types.
BASS_DATA_AVAILABLEQuery the amount of data the channel has buffered. This flag is primarily of use when recording, and can't be used with decoding channels as they do not have playback buffers. buffer can be when using this flag.

Return Value

Type: Int32
If an error occurs, -1 is returned, use BASS_ErrorGetCode to get the error code.

When requesting FFT data, the number of bytes read from the channel (to perform the FFT) is returned.

When requesting sample data, the number of bytes written to buffer will be returned (not necessarily the same as the number of bytes read when using the BASS_DATA_FLOAT or BASS_DATA_FIXED flag).

When using the BASS_DATA_AVAILABLE flag, the number of bytes in the channel's buffer is returned.

Remarks

This function can only return as much data as has been written to the channel's buffer, so it may not always be possible to get the amount of data requested, especially if you request large amounts. If you really do need large amounts, then increase the buffer lengths (BASS_CONFIG_BUFFER). The BASS_DATA_AVAILABLE flag can be used to check how much data a channel's buffer contains at any time, including when stopped or stalled.

When requesting data from a decoding channel, data is decoded directly from the channel's source (no playback buffer) and as much data as the channel has available can be decoded at a time.

When retrieving sample data, 8-bit samples are unsigned (0 to 255) , 16-bit samples are signed (-32768 to 32767), 32-bit floating-point samples range from -1 to +1 (not clipped, so can actually be outside this range). That is unless the BASS_DATA_FLOAT flag is used, in which case, the sample data will be converted to 32-bit floating-point if it is not already, or if the BASS_DATA_FIXED flag is used, in which case the data will be coverted to 8.24 fixed-point.

Unless complex data is requested via the BASS_DATA_FFT_COMPLEX flag, the magnitudes of the first half of an FFT result are returned. For example, with a 2048 sample FFT, there will be 1024 floating-point values returned. If the BASS_DATA_FIXED flag is used, then the FFT values will be in 8.24 fixed-point form rather than floating-point. Each value, or "bin", ranges from 0 to 1 (can actually go higher if the sample data is floating-point and not clipped). The 1st bin contains the DC component, the 2nd contains the amplitude at 1/2048 of the channel's sample rate, followed by the amplitude at 2/2048, 3/2048, etc. A Hann window is applied to the sample data to reduce leakage, unless the BASS_DATA_FFT_NOWINDOW flag is used. When a window is applied, it causes the DC component to leak into the next bin, but that can be removed (reduced to 0) by using the BASS_DATA_FFT_REMOVEDC flag. Doing so slightly increases the processing required though, so it should only be done when needed, which is when a window is applied and the 2nd bin value is important.

Channels that have 2 or more sample channels (ie. stereo or above) may have FFT performed on each individual channel, using the BASS_DATA_FFT_INDIVIDUAL flag. Without this flag, all of the channels are combined, and a single mono FFT is performed. Performing the extra individual FFTs of course increases the amount of processing required. The return values are interleaved in the same order as the channel's sample data, eg. stereo = left,right,left,etc.

This function is most useful if you wish to visualize (eg. spectrum analyze) the sound.

FFT processing hint 1: DC stands for direct current (same as what a flashlight cell gives out) and is represents a 0 Hz sound, which cannot exist in real life. A sound sample should not have any DC component but probably will due to inaccuracies in the recording equipment. You won't hear it (except a click when playing and stopping the sample). The DC component is basically the average of all the samples that the FFT was applied to, and is pretty useless. You'll have to halve the DC component that BASS returns to get the actual DC component, as BASS doubles all the bin values.

FFT processing hint 2: How to read out the amplitude of a single frequency/a frequency band? FFT[0] maps to amplitude at 0 Hz, FFT[length-1] maps to amplitude at Nyquist's frequency. So the index to FFT data at an arbitrary band is:

idx = length*freq/Nyquist
where:
length : length of the returned FFT buffer (in samples)
freq : required frequency (Hz)
Nyquist : Nyquist's frequency of the signal (half the sampling rate) (in Hz)
Example: If the stream is 44100Hz, then 16500Hz will be around bin 191 of a 512 sample FFT (512*16500/44100). Or, if you are using BASS_DATA_FFT4096 on a stream with a sample rate of 44100 a tone at 540Hz will be at: 540*4096/44100 = 50.15, so a bit of the energy will be in fft[51], but mostly in fft[50]. Note: With a sample rate of 44100 the Nyquist frequency is 22050Hz, which is the max. frequency. This is also why BASS_DATA_FFT4096 only returns 2048 values - fft[2048] would represent 22050Hz.

ERROR CODEDescription
BASS_ERROR_HANDLEhandle is not a valid channel.
BASS_ERROR_ENDEDThe channel has reached the end.
BASS_ERROR_NOTAVAILThe BASS_DATA_AVAILABLE flag was used with a decoding channel.
BASS_ERROR_BUFLOSTShould not happen... check that a valid window handle was used with BASS_Init(Int32, Int32, BASSInit, IntPtr, IntPtr).

Platform-specific:

The BASS_DATA_FIXED flag is only available on Android and Windows CE.

Examples

The following example assumes that you have created the stream with the BASS_SAMPLE_FLOAT flag. So the buffer will contain 32-bit values between -1 and 1...as an array of float:
// a 30ms window in bytes to be filled with sample data
int length = (int)Bass.BASS_ChannelSeconds2Bytes(channel, 0.03);

// first we need a mananged object where the sample data should be held
// only length/4 elements needed, since length is in byte and a float uses 4 bytes
float[] data = new float[length/4];

// create a pinned handle to a managed object
GCHandle hGC = GCHandle.Alloc(data, GCHandleType.Pinned);

// get the data
length = Bass.BASS_ChannelGetData(channel, hGC.AddrOfPinnedObject(), length);

// free the pinned handle
hGC.Free();
A more simple way is to use the other overloads where you simply pass the array itself (those overloads pass the buffer array as a reference type by value with automatic pinning, which is as fast as the following example).

If you are into C# you might even use native pointers in an unsafe code block:

C#
// a 30ms window in bytes to be filled with sample data
int length = (int)Bass.BASS_ChannelSeconds2Bytes(channel, 0.03);

// first we need a mananged object where the sample data should be held
// only length/4 elements needed, since length is in byte and a float uses 4 bytes
float[] data = new float[length/4];

// start an unsafe code block allowing you to use native pointers
unsafe
{
  // pointers to managed objects need to be fixed
  fixed (float* buffer = data)    // equivalent to buffer = &data[0]
  {
    length = Bass.BASS_ChannelGetData(channel, (IntPtr)buffer, length);
  }
}
This is by far the fastest way to use BASS_ChannelGetData, but unfortunately not availabe with VB.Net. However, the other overloads do automatically pin the buffer as needed and are as fast as this.
See Also

Reference