BASS.NET API for the Un4seen BASS Audio Library

BASS.NET Overview

BASS.NET API for the Un4seen BASS Audio Library

BASS.NET API is the .NET wrapper for the Un4seen BASS Audio libraray and all the Add-Ons. It is entirely written in C# (managed code) and works with the Microsoft .NET Full Framework v4.8 or above (e.g. to target Windows x86 or x64 platforms) as well as with the .NET Core v6.0 or above (e.g. to target Windows, Linux, macOS, iOS, Android) and supports any managed language, like C#, VB.Net, JScript, F# or managed C++

Content in this Topic:

Note Note

© 2005-2022 by radio42, Germany. Author: Bernd Niedergesaess - All rights reserved.

BASS.NET is the property of radio42 and is protected by copyright laws and international copyright treaties. BASS.NET is not sold, it is licensed.

BASS and Add-Ons: All trademarks and other registered names contained in the BASS.NET package are the property of their respective owners.

Requires: BASS © 1999-2022 by Ian Luck.

Caution note Caution

TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, BASS.NET IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS SHALL NOT BE HELD LIABLE FOR ANY DAMAGE THAT MAY RESULT FROM THE USE OF BASS.NET. BASICALLY, YOU USE BASS.NET ENTIRELY AT YOUR OWN RISK.

Usage

BASS and BASS.NET are available at www.un4seen.com. In addition the respective Add-Ons might be required as well, if you are using any classes or methods from the Un4seen.Bass.AddOn or Un4seen.BassAsio resp. Un4seen.BassWasapi namespace. In addition many members of the Un4seen.Bass.Misc namespace make use of the BASS plugin system (see BASS_PluginLoad) and as such also require the respective add-ons to be loaded first.

The native BASS libraries need to be downloaded seperately - so make sure to place the BASS library and the needed add-on libraries (dlls) to your project executable directory (e.g. place the bass.dll to your .\bin\Debug folder).

There is no guarantee that all future BASS.NET versions will be compatible with all previous versions, so your program should use BASS_GetVersion to check the version that is loaded. This also means that you should put the BASS, Add-On and BASS.NET module in the same directory as your executable (not just somewhere in the path), to avoid the possibility of a wrong version being loaded.

If you are updating your software from a previous BASS.NET version, then you should check the Version History topic, to see if any of the functions that you are using have been affected by a change. In addition see also here: Upgrading from Previous Versions.

Disclaimer

The freeware version of BASS.NET is free for non-money making use. If you are not charging for or making any money with your software AND you are an individual person (not a company) AND your software is intended for personal use only, then you can use the BASS.NET API in your software for free. Free in this case means, that the you can use BASS.NET without any further license fees. It does NOT mean that you are free to change, copy, redistribute, share or use BASS.NET in any purpose.

By using this software, you agree to the following conditions:

  • The freeware version of BASS.NET is distributed under the license of radio42 (see LICENSE.rtf).
  • The LICENSEE (you) may not charge for or make any money with the software using the freeware version of BASS.NET.
  • It is prohibited to change any of the provided source code and ALL the files must at any time remain intact and unmodified.
  • You may not decompile, disassemble, reverse engineer or modify any part of BASS.NET.
  • The LICENSEE (you) may ONLY distribute the DLL part of BASS.NET (Bass.Net.dll). No other part of BASS.NET may be distributed.
  • You may not resell or sublicense BASS.NET.
  • An exception might be raised (unless you obtained a valid Registration-Key).
  • You are NOT allowed to pass your personal Registration-Key to anyone at anytime!
  • Your products must be end-user products, eg. not components used by other products. Please note that a licence only covers your own software, not the publishing of other's software.
Please note, that you also need to take care of all BASS modules and their respective rights.

License and Cost

BASS.NET is free for non-commercial use. If you are a non-commercial entity (eg. an individual) and you are not charging for your product, and the product has no other commercial purpose, then you can use BASS.NET in it for free.

In any other case a license is required from radio42, Bernd Niedergesaess (e.g. if you wish to use BASS.NET in shareware or commercial products)!

BASS.NET is available for use in your shareware or commercial products. The licence types available are as follows:

  • Shareware license: 29.00 Euro

    Allows the usage of BASS.NET in an unlimited number of your shareware products, which must sell for no more than 40 Euros each. If you're an individual (not a corporation) making and selling your own software (and its price is within the limit), this is the licence for you.

  • Single Commercial license: 199.00 Euro

    Allows the usage of BASS.NET in a single commercial product. If you are a company making and selling your own software (and use BASS.NET only in a single product), this is the licence for you.

  • Unlimited Commercial license: 499.00 Euro

    Allows the usage of BASS.NET in an unlimited number of your commercial products. This licence is on a per site basis. So if your company has two sites that use BASS.NET, then two licences are required.

Please note, that the products must be end-user products, e.g. not components used by other products. These licences only cover your own software. Not the publishing of other's software. If you publish other's software, its developers (or the software itself) will need to be licensed to use BASS.NET.

You can obtain your license and Registration-Key here: http://www.bass.radio42.com

In all cases there are no royalties to pay, and you can use future BASS.NET updates without further cost. One licence covers one person or entity and is not transferable. These licences do not allow reselling/sublicensing of BASS.NET. For example, if a product is a development system, the users of said product are not licensed to use BASS.NET in their productions - they will need their own licences.

BASS.NET is a .Net wrapper of the product BASS (www.un4seen.com). In order to use BASS.NET an additional BASS license might need to be obtained separately.

If the standard licences do not meet your requirements, or if you have any questions, please get in touch:

radio42, Bernd Niedergesaess - Gryphiusstrasse 9 - 22299 Hamburg, Germany (bn@radio42.com)

Registration

You need to register BASS.NET in order to obtain a valid license. Without registering BASS.NET an exception will be raised with the first call to any BASS.NET method. You can obtain your license and Registration-Key here: http://www.bass.radio42.com/

After you have received your Registration-Key, please call the following method prior to any other BASS method:

Register to prevent any exception
Un4seen.Bass.BassNet.Registration("your email", "your regkey")
A good place to call Registration is the static Main method of your application.

If you would like to support the development of BASS.NET in any other form, please donate something to the following PayPal account:

Included, Installed Files

Files that you should have found after you installed BASS.NET:

Folder

Content

<InstallDir>

e.g. C:\Program Files (x86)\BASS.NET

Note, that even if the Installer might install BASS.NET within your x86 directory, you can use it in any x64 environment, as BASS.NET is compiled for 'Any CPU'.

LICENSE.rtf

The BASS.NET API license file.

readme.txt

Setup and general information text file.

.\core

Sub-Folder containing the Bass.Net for .Net 6 (core)) assembly (Bass.Net.dll)

Targeting a platform independ development e.g. for Windows, Linux, macOS, iOS and Android.

Bass.Net.dll

The BASS.NET API assembly (targeting .Net 6.0 or above).

Bass.Net.xml

The BASS.NET API xml documentation file (needed for IntelliSense).

.\full

Sub-Folder containing the Bass.Net for .Net 4.8 or above assembly (Bass.Net.dll)

Targeting the Full Framework x86 and x64 Windows development.

Bass.Net.dll

The BASS.NET API assembly (targeting the .Net Framework 4.8 or above).

Bass.Net.xml

The BASS.NET API xml documentation file (needed for IntelliSense).

.\Help

Sub-Folder containing the Bass.Net help files.

Bass.Net.chm

The MS Help 1.x offline help file.

.\Samples

Sub-Folder containing various C# and VB examples.

.\CS

This sub-folder contains all C# examples and a global solution for it (sample.sln).

.\VB

This sub-folder contains all VB.Net examples and a global solution for it (sample.sln).

Third Party Intellectual Property Rights

MP3 technology is patented, and Thomson license the use of their and Fraunhofer's patents. The inclusion of an MP3 decoder (e.g. BASS) in a commercial product requires an MP3 patent licence. Contact Thomson for details: www.mp3licensing.com

Alternatively, the 'MP3-FREE' BASS version doesn't include its own MP3 decoder but instead makes use of the operating system's already licensed decoder.

NOTE: When using the OS's MP3 decoder, BASS still does the file handling so all the usual features are still supported, including streaming, tag reading, pre-scanning, gapless playback, etc.

Other Add-Ons might require additional licenses - see the respective add-on documentation for details.

Using BASS.NET In Your Own Application

When writing your own application using BASS.NET, you can simply add a new project reference and select the BASS.NET API from the standard .NET components tab (make sure to select the appropriate assembly for the framework you are targeting).

By default the local copy attribute is selected and so the Bass.Net.dll will be copied to your output directory of your own application or own class library.

NOTE: Do NOT copy the Bass.Net.dll manually to another location (e.g. the windows system directory)!

Note Note

In addition to the Bass.Net assembly you also need the native BASS libraries (e.g. bass.dll)! So make sure to download BASS or any needed Add-Ons from www.un4seen.com.

You then need to manually copy the bass.dll or any other native add-on dll to your output directory (e.g. .\bin\Debug resp. .\bin\Release). Typically your executable application as well as the Bass.Net.dll and the native bass.dll resp. the add-on dlls must reside within the same folder. If you want to deploy your application using different locations see LoadMe resp. BASS_PluginLoadDirectory for more information (Note, that these helper methods are only available under the Full Framework and Windows).

Also note, that BASS.NET is not installed to your gobal assembly cache (GAC) automatically. However you might do so by yourself (if that is really desired, even this is under normal circumstances really not needed). Use the Global Assembly Cache tool (Gacutil.exe) to install or remove an assembly to or from the global assembly cache. At the command prompt in the BASS.NET [install-directory], type the following command:
Install BASS.NET into the GAC:
gacutil -i Bass.Net.dll
Remove BASS.NET from the GAC:
gacutil -u Bass.Net.dll
NOTE: Gacutil.exe is only for development purposes and should not be used to install production assemblies into the global assembly cache.

It's a good idea to permit the use of the BASS.NET types contained in the BASS.NET namespaces so you do not have to specify the fully qualified name - or you might also want to create an alias for the BASS.NET namespace in your source code. E.g. add the following lines to your source code:

C#: Permit the use of some BASS.NET types in your namespace
using Un4seen.Bass;
using Un4seen.Bass.Misc;
using Un4seen.Bass.AddOn.Wma;
VB.Net: Permit the use of some BASS.NET types in your namespace
Imports Un4seen.Bass
Imports Un4seen.Bass.Misc
Imports Un4seen.Bass.AddOn.Wma
Add as much BASS.NET namespaces as needed and used in your source code.

Bass.Net comes with various build versions being installed. All versions are based on the exact same source code, but the build versions differ in various aspects, which are listed below:

The .Net 6 (core) versions has the following limitations:

  • no support for any Image or Bitmaps

  • no picture tag reading support (Image, Bitmap support)

  • no WaveForm rendering support

  • no Visuals helper support

My First BASS Application

  1. Create a new "Project" from your Visual Studio Environment (Console Application).
  2. Add a "Reference" to the BASS.NET library to your project.
  3. Paste the following code to your source file.
  4. Copy the 'bass.dll' to your executable directory (e.g. .\bin\Debug).
  5. Copy a MP3 audio test file named 'test.mp3' to the executable directory (e.g. .\bin\Debug).
  6. Compile and start the project.
C#:
using System;
using Un4seen.Bass;

namespace MyFirstBass
{
  class Program
  {
    static void Main(string[] args)
    {
      // init BASS using the default output device
      if ( Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero) )
      {
        // create a stream channel from a file
        int stream = Bass.BASS_StreamCreateFile("test.mp3", 0, 0, BASSFlag.BASS_DEFAULT);
        if (stream != 0)
        {
          // play the stream channel
          Bass.BASS_ChannelPlay(stream, false);
        }
        else
        {
          // error creating the stream
          Console.WriteLine("Stream error: {0}", Bass.BASS_ErrorGetCode());
        }

        // wait for a key
        Console.WriteLine("Press any key to exit");
        Console.ReadKey(false);

        // free the stream
        Bass.BASS_StreamFree(stream);
        // free BASS
        Bass.BASS_Free();
      }
    }
  }
}
VB.Net:
Imports System
Imports Un4seen.Bass

Namespace MyFirstBass
  Class Program
    Shared  Sub Main(ByVal args() As String)
      ' init BASS using the default output device
      If Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero) Then
        ' create a stream channel from a file
        Dim stream As Integer =  Bass.BASS_StreamCreateFile("test.mp3", 0, 0, BASSFlag.BASS_DEFAULT) 
        If stream <> 0 Then
          ' play the stream channel
          Bass.BASS_ChannelPlay(stream, False)
        Else 
          ' error creating the stream
          Console.WriteLine("Stream error: {0}", Bass.BASS_ErrorGetCode())
        End If

        ' wait for a key
        Console.WriteLine("Press any key to exit")
        Console.ReadKey(False)

        ' free the stream
        Bass.BASS_StreamFree(stream)
        ' free BASS
        Bass.BASS_Free()
      End If
    End Sub
  End Class
End Namespace

Basic Concepts

This chapter contains general information about BASS and its implementation details.

Content:

Initializing BASS

Before you can use any other BASS method you must first initialize BASS using the BASS_Init method (which actually initializes an output device).

When you are done with BASS (e.g. you are about to exit or close the application) make sure to free BASS to cleanup any unmanaged resources being used by calling BASS_Free.

BASS Configuration

There are various configuration options to fine tune the behaviour of BASS. Call BASS_SetConfig to set a new configuration option or BASS_GetConfig to retrieve a current setting. Take a look to the BASSConfig enum for a complete list of options.

Here is a list of commonly used options:

BASS_CONFIG_BUFFER : Playback buffer length (controls the latency for buffered streams).

BASS_CONFIG_UPDATEPERIOD : Update period of playback buffers (controls the period of time between updates).

BASS_CONFIG_FLOATDSP : Pass 32-bit floating-point sample data to all DSP functions?

BASS_CONFIG_REC_BUFFER : The buffer length for recording channels.

And many many more...

What Is a Stream/Channel?

Within BASS the term "stream" or "channel" is used when you open an audio item for processing, e.g. from a file location, URL, user defined callback, sample or recording. Thus you are using functions like e.g. BASS_StreamCreateFile etc. These function return a handle for such created stream, as such handle is also called a stream handle or channel handle. So do not get confused, if sometimes the terms stream or channel are used in exchange - both typically refer to the underlying handle being used. There are different types of handles you might create:

HCHANNEL : Returned by e.g. BASS_SampleGetChannel.

HSTREAM : Returned by e.g. BASS_StreamCreate, BASS_StreamCreateFile, BASS_StreamCreateFileUser or various other add-on functions like e.g. BASS_FX_TempoCreate.

HMUSIC : Returned by e.g. BASS_MusicLoad.

HRECORD : Returned by e.g. BASS_RecordStart.

As you can see, different names for the same thing resp. different things having the same name! The above handle names always mean: H=Handle for a certain type.

Once you created a 'stream channel handle' and want/need to manipulate it, you are using the 'Channel' functions. As such you are using functions like e.g. BASS_ChannelSetPosition or BASS_ChannelSetAttribute. As a channel can be a sample playback channel (HCHANNEL), a sample stream (HSTREAM), a MOD music (HMUSIC), or a recording (HRECORD), each 'Channel' function can be used with one or more of these channel types.

And now it gets completely confusing: As seen above you have 'Channel' functions which operate on a HANDLE. But the name 'channel' might mean and reference something completely different in other contexts: E.g.: there are 'ASIO Channels' representing distinct hardware I/Os. or 'Audio Channels' representing the number of audio channels within the sample data (ie. left and right channel) etc.

When a sound is loaded, it is either decompressed as a static sample into memory as PCM (samples), loaded into memory in its native format and decompressed at runtime, or streamed and decoded in realtime (in chunks) from an external media such as a file or a URL. The main differences are:

  • Samples (raw PCM): Are loaded into memory or provided by the user in realtime in the specified PCM sample format (raw).

    Samples are good for small sounds that need to be played more than once at a time, for example sound effects. These generally use very little or no CPU to play back, since there is no additional decoding process involved.

  • Recording: A special case of a "sample" as the PCM sample data is created from an input device in realtime as they are recorded.
  • Streams (native): Are typically loaded from a file or URL (but might also be provided by the user in realtime or loaded into memory) in the native (e.g. compressed) format.

    Streams are good for large sounds that are too large to fit into memory and need to be streamed from the given location into a buffer that BASS manages. These take a small amount of CPU and I/O bandwidth based on the file format, since here an additional decoding process is involved.

  • MOD music: A special case of a "stream" supporting MOD music file - MO3/IT/XM/S3M/MTM/MOD/UMX formats.
So in essence a sample provides the data already in raw PCM format whereas a stream first needs to decode the format and convert it to the raw PCM format.

Playing a Sound

In order to play any audio sound with BASS you first need to create a stream or sample (as explained above). There are various ways to create a stream or sample (from memory, from a file or URL, by a user method - take a look to all the "BASS_StreamCreate*", "BASS_SampleCreate*", "BASS_SampleLoad*", "BASS_MusicLoad*" and "BASS_RecordStart*" methods). The most easiest way is of course to create a stream or sample from a file. E.g. use the BASS_StreamCreateFile method to do so.

After a stream/sample/music/recording is created you'll receive a channel handle which can be used in further BASS ("BASS_Channel*") methods. Note, that you should call BASS_StreamFree, BASS_SampleFree, BASS_MusicFree or BASS_RecordFree in order to free all resources once you don't need the channel handle anymore.

Use BASS_ChannelPlay to start the playback of the created channel resp. to start the recording.

Typical other methods which are used with a channel handle are:

BASS_ChannelGetInfo : Retrieves information on a channel (sample rate, resolution, format etc).

BASS_ChannelGetLength : Retrieves the playback length (in bytes) of a channel.

BASS_ChannelGetPosition/BASS_ChannelSetPosition : Retrieves/Sets the playback position (in bytes) of a channel.

BASS_ChannelBytes2Seconds/BASS_ChannelSeconds2Bytes : Translates a byte position into seconds (vice versa).

BASS_ChannelGetLevel : Retrieves the level (peak amplitude) of a channel.

BASS_ChannelPause : Pauses a channel.

And many many more...

Floating-Point Channels

Channels can be made to use 32-bit floating-point sample data (see BASS_SAMPLE_FLOAT and BASS_CONFIG_FLOATDSP). When a channel uses floating-point sample data, BASS takes full advantage of the extra resolution when generating the decoded sample data, it does not simply convert 16-bit data to floating-point.

The main advantage of floating-point channels, aside from the increased resolution/quality, is that they are not clipped until output. This makes them particularly good for DSP/FX, because the quality is not degraded as the data passes through a chain of DSP/FX. So even if the output device is not capable of outputting the channel in its full quality, the quality is still improved. Note that to use DX8 effects (see BASS_ChannelSetFX) with floating-point channels requires DirectX 9 or above. BASS_GetInfo can be used to check the DirectX version in use.

The floating-point sample data values range from -1.0 to +1.0 (or above). Though as mentioned above, it's not clipped to this range until output, so it's very possible that DSPPROC callback functions or BASS_ChannelGetData calls could receive data beyond this range.

When a floating-point channel is played, it is converted to whatever resolution the output device supports in the final mix.

Floating-point channels are not supported when using VxD drivers (on Windows 98/95), except for "decoding channels". Windows Vista (and later) audio is natively floating-point, so for optimum performance (not to mention quality), BASS channels should also be floating-point. That particularly applies to formats that are decoded in floating-point anyway, ie. lossy formats like MP3 and OGG. It also applies to Linux and OSX, where BASS's mix format is floating-point.

Floating-point channels are not supported on Android or Windows CE. That includes 'decoding channels'.

C#: Check for 32-bit floating-point channel support
bool floatable = true;
// try creating a floating-point stream
int stream = Bass.BASS_StreamCreate(44100, BASSFlag.BASS_SAMPLE_FLOAT, null, 0);
if (stream == 0)
    floatable = false;
VB.Net: Check for 32-bit floating-point channel support
Dim floatable As Boolean =  True 
' try creating a floating-point stream
Dim stream As Integer = Bass.BASS_StreamCreate(44100, BASSFlag.BASS_SAMPLE_FLOAT, Nothing, 0) 
If stream = 0 Then
    floatable = False
End If

Output Sample Rate and Resolution

The quality of audio data is mainly determined by its sample rate (given in Hz, how many samples are present/used per second) and the resolution of the data itself (the bitwidth, number of bits used to store a single sample data item, which is typically either 8-, 16, 24- or 32-bit). Note, that one audio sample consists of multiple data item values according to the number of channels used in the audio (e.g. a stereo audio contains 2 data items per sample - one for the left and one for the right channel - each data item having the given resolution). E.g. a 44.1kHz, 16-bit, stereo audio will have 44100 samples per second each containing two 16-bit values.

The format (sample rate and resolution) specified when calling BASS_Init only actually has effect on the device's output with VxD drivers. With WDM drivers, the output format is automatically set depending on the format of the channels that are played and what the device supports.

While in Windows Vista/7, the output format is determined by the user's choice in the control panel - BASS_GetInfo can be used to check what that is. For reference: Windows XP/2000 use only WDM drivers. Windows Me/98SE can use either WDM or the older VxD driver model. Windows 98/95 only use VxD drivers.

This means, if you create for example a 16-bit stereo stream from a compressed MP3 file who's sample rate is 44100Hz - so the output will be: 44100Hz, 16-bit, stereo. Creating a 32-bit floating-point stream of the same file will result in: 44100Hz, 32-bit, stereo (assuming your output device supports this format).

Note: On Windows Vista/7 the sample rate is set in the control panel and the resolution is always 32-bit float, so any stream format will automatically be converted as needed.

You can play multiple stream/sample channels on the same output device in parallel except when using ASIO or BASSWASPI (either using Hardware or Software Mixing as defined per stream/sample in it's create method - using the BASS_SAMPLE_SOFTWARE flag). Using Hardware Mixing is more efficient and uses less CPU, as the mixing is performed directly by the hardware/driver, but that needs a good and clean device driver, which supports the formats being used. Unfortunately a lot of soundcards come shipped with poor device drivers which might produce a distorted sound when using certain output formats. If you discover such problems try using the BASS_SAMPLE_SOFTWARE flag when creating a stream or sample and try again. Software Mixing means the mixing is performed by Windows/DirectSound (note, that on Windows Vista/7 Software Mixing is always used as Hardware Mixing isn't supported there).

So it is a good idea to give the user a choice within your application on whether to use hardware or software mixing.

If multiple playing channels do use different formats the theory is, that Windows should set (when possible) the device's output rate to the highest rate of the sounds that are playing. Of course, some device's have a fixed sample rate anyway, fixed either by the hardware or the driver control panel.

Buffered vs. Decoding Channels

Unless you specify the BASS_STREAM_DECODE flag with your stream/sample creation method all channels are "buffered". Meaning there is an internal BASS playback buffer involved (as specified with the BASS_CONFIG_BUFFER option). Increasing the buffer length, decreases the chance of the sound possibly breaking-up on slower computers, but also increases the latency for DSP/FX.

Decoding channles might be created using the above flags at creation. However, decoding channels can not directly be used for playback (BASS_ChannelPlay has no effect on decoding channels, instead BASS_ChannelGetData must be used). Decoding channels however might be usefull in e.g. the following scenarios:

Decoding channels are particularly fast and are perfectly suited for any kind of non-realtime batch processing.

Note: When requesting data from a "decoding channel" via BASS_ChannelGetData, there are no intermediate buffers involved, so as much data as is available can be decoded in one go. This means the data is 'taken away' immediately. So don't call BASS_ChannelGetData when you use the decoding channel to feed an output channel.

The opposite is true when requesting data from a "buffered channel". If you call BASS_ChannelGetData on a "buffered channel" the last data of the BASS internal buffer is returned without having any effect on playback. This makes it possible to perform any kind of PeakLevel or FFT calculation based on the current buffered sample data.

Sample Data

When retrieving sample data, 8-bit samples are unsigned (0 to 255; byte datatype), 16-bit samples are signed (-32768 to 32767; Int16 datatype), 32-bit floating-point samples range from -1.0 to +1.0 or above (float/Single datatype; not clipped, so can actually be outside this range). You can retrive sample data via the BASS_ChannelGetData method. Note, that any compressed file format (e.g. MP3, OGG, WMA etc.) will first be decoded, so that you will always receive PCM sample data. The resolution (bitwidth) of the returned sample data depends on the BASSFlag flag used with your sample/stream creation resp. the BASSData flag used when requesting the data.

In the digital audio world the sample rate defines the number of samples per second (measured in Hz) taken from a continuous signal to make a discrete signal. A sample consists of all bytes needed to represent the discrete signal for all channels.

Example: 16-bit, stereo, 44.1kHz

  • 16-bit = 2 byte per channel (left/right) = 4 bytes per sample
  • the sample rate is 44100 samples per second
  • one sample is 1/44100th of a second long (or 1/44th of a millisecond)
  • 44100 samples represent 1 second which is worth 176400 bytes
To convert between the different values, the following formulas can be used:

milliseconds = samples * 1000 / samplerate

samples = ms * samplerate / 1000

samplerate = samples * 1000 / ms

bytes = samples * bits * channels / 8

samples = bytes * 8 / bits / channels

The Nyquist–Shannon sampling theorem states that perfect reconstruction of a signal is possible when the sample rate is greater than twice the maximum frequency of the signal being sampled, or equivalently, that the Nyquist frequency (half the sample rate) exceeds the bandwidth of the signal being sampled. If lower sampling rates are used, the original signal's information may not be completely recoverable from the sampled signal. That's why standard Audio-CDs use a sample rate of 44100Hz, as the human ear can typically only recognize frequencies up to 20000Hz.

In case of streams with more than one channel (ie. stereo or above) the data of the individual channels are interleaved within the sample data:

StereoLeft, Right = 1 sample
3 channelsLeftFront, RightFront, Center = 1 sample
4 channelsLeftFront, RightFront, LeftRear, RightRear = 1 sample
6 channels (5.1)LeftFront, RightFront, Center, LFE, LeftRear, RightRear = 1 sample
8 channels (7.1)LeftFront, RightFront, Center, LFE, LeftRear, RightRear, LeftCenter, RightCenter = 1 sample
When retrieving sample data (or when seeking/positioning within a channel via BASS_ChannelGetPosition/BASS_ChannelSetPosition) the position is always aligned to the next sample, so that the returned buffer always starts with a full "sample". You might extract the individual channel data by counting the channel number:
C#: Calculating the audio level for a stereo 32-bit float channel
private int _stream = 0;
...

// create a 32-bit floating-point stream
_stream = Bass.BASS_StreamCreateFile("test.mp3", 0, 0, 
                    BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN);
if (_stream != 0)
{
  Bass.BASS_ChannelPlay(_stream, false);
}
...

// e.g. use a (windows)timer to periodically invoke this 
private void timerUpdate_Tick(object sender, System.EventArgs e)
{
  // calculate the sound level
  int peakL = 0;
  int peakR = 0;
  GetLevel(_stream, out peakL, out peakR);
  // convert the level to dB
  double dBlevelL = Utils.LevelToDB(peakL, 65535);
  double dBlevelR = Utils.LevelToDB(peakR, 65535);
}
...

// calculates the level of a stereo signal between 0 and 65535
// where 0 = silent, 32767 = 0dB and 65535 = +6dB
private void GetLevel(int channel, out int peakL, out int peakR)
{
  float maxL = 0f;
  float maxR = 0f;

  // length of a 20ms window in bytes
  int length20ms = (int)Bass.BASS_ChannelSeconds2Bytes(channel, 0.02);
  // the number of 32-bit floats required (since length is in bytes!)
  int l4 = length20ms/4; // 32-bit = 4 bytes

  // create a data buffer as needed
  float[] sampleData = new float[l4];

  int length = Bass.BASS_ChannelGetData(channel, sampleData, length20ms);

  // the number of 32-bit floats received
  // as less data might be returned by BASS_ChannelGetData as requested
  l4 = length/4;

  for (int a=0; a < l4; a++)
  {
    float absLevel = Math.Abs(sampleData[a]);

    // decide on L/R channel
    if (a % 2 == 0)
    {
      // Left channel
      if (absLevel > maxL)
        maxL = absLevel;
    }
    else
    {
      // Right channel
      if (absLevel > maxR)
        maxR = absLevel;
    }
  }

  // limit the maximum peak levels to +6bB = 65535 = 0xFFFF
  // the peak levels will be int values, where 32767 = 0dB
  // and a float value of 1.0 also represents 0db.
  peakL = (int)Math.Round(32767f * maxL) & 0xFFFF;
  peakR = (int)Math.Round(32767f * maxR) & 0xFFFF;
}
VB.Net: Calculating the audio level for a stereo 32-bit float channel
Private _stream As Integer = 0 
...

' create a 32-bit floating-point stream
_stream = Bass.BASS_StreamCreateFile("test.mp3", 0, 0, 
                    BASSFlag.BASS_SAMPLE_FLOAT Or BASSFlag.BASS_STREAM_PRESCAN)
If _stream <> 0 Then
  Bass.BASS_ChannelPlay(_stream, False)
End If
...

' e.g. use a (windows)timer to periodically invoke this 
Private Sub timerUpdate_Tick(ByVal sender As Object, ByVal e As System.EventArgs)
  ' calculate the sound level
  Dim peakL As Integer = 0 
  Dim peakR As Integer = 0 
  GetLevel(_stream, peakL, peakR)
  ' convert the level to dB
  Dim dBlevelL As Double = Utils.LevelToDB(peakL, 65535) 
  Dim dBlevelR As Double = Utils.LevelToDB(peakR, 65535) 
End Sub
...

' calculates the level of a stereo signal between 0 and 65535
' where 0 = silent, 32767 = 0dB and 65535 = +6dB
Private Sub GetLevel(ByVal channel As Integer, ByRef peakL As Integer, ByRef peakR As Integer)
  Dim maxL As single = 0f 
  Dim maxR As single = 0f 

  ' length of a 20ms window in bytes
  Dim length20ms As Integer = CType(Bass.BASS_ChannelSeconds2Bytes(channel,0.02), Integer)
  ' the number of 32-bit floats required (since length is in bytes!)
  Dim l4 As Integer = length20ms/4  ' 32-bit = 4 bytes

  ' create a data buffer as needed
    Dim sampleData(l4 - 1) As Single

  Dim length As Integer = Bass.BASS_ChannelGetData(channel, sampleData, length20ms) 

  ' the number of 32-bit floats received
  ' as less data might be returned by BASS_ChannelGetData as requested
  l4 = length/4

  Dim a As Integer
  For  a=0 To l4-1 Step a+1
    Dim absLevel As single = Math.Abs(sampleData(a)) 

    ' decide on L/R channel
    If a Mod 2 = 0 Then
      ' Left channel
      If absLevel > maxL Then
        maxL = absLevel
      End If
    Else 
      ' Right channel
      If absLevel > maxR Then
        maxR = absLevel
      End If
    End If
  Next

  ' limit the maximum peak levels to +6bB = 65535 = 0xFFFF
  ' the peak levels will be int values, where 32767 = 0dB
  ' and a float value of 1.0 also represents 0db.
  peakL = CInt(Math.Round(32767F * maxL)) And &Hffff 
  peakR = CInt(Math.Round(32767F * maxR)) And &Hffff 
End Sub

Using Add-Ons

There are two types of Add-Ons:

1. PlugIns

2. Add-Ons

The simple distinction between a "plugin" and an "add-on" is that a "plugin" plugs into standard BASS functions (eg. stream/sample creation), while an "add-on" provides additional functions. All "plugins" are "add-ons" (they can be used either way), but not all "add-ons" are "plugins". For example, there's no way that the BASS_VST features can be accessed via standard BASS functions.

BASS has built-in support for various audio codecs, like MPEG, OGG, WAV and AIFF files (and more). But if you want to support playback of other audio formats (e.g. FLAC or AAC) you can use the BASS_PluginLoad method to load a plugin. Once plugged, you can use the standard BASS stream creation methods (e.g. BASS_StreamCreateFile) to play any other supported audio format - just don't forget to also download the resp. add-on and place the dll to your executable directory! Also make sure to call BASS_PluginFree to unload the plugin and free it's resources once it is not needed anymore.

Please see the BASS_PluginLoad documentation for further details.

C#: Add support for WMA
int plg = Bass.BASS_PluginLoad("basswma.dll");
...
int stream = Bass.BASS_StreamCreateFile("test.wma", 0, 0, BASSFlag.BASS_DEFAULT);
...
Bass.BASS_PluginFree(plg);
VB.Net: Add support for WMA
Dim plg As Integer =  Bass.BASS_PluginLoad("basswma.dll")
...
Dim stream As Integer =  Bass.BASS_StreamCreateFile("test.wma", 0, 0, BASSFlag.BASS_DEFAULT)
...
Bass.BASS_PluginFree(plg)
All other (none plugin) add-ons typically doesn't need to be loaded explititly, as they are loaded automatically with the first call to an add-on method. These other add-ons extend the functionality of BASS, e.g. provide encoding support (BassEnc), support for mixing/splitting multiple streams (BassMix), provide several DSP and effect functions (BassFx) etc.

Some BASS add-ons introduce new configuration options to the BASS_SetConfig/BASS_GetConfig methods respectively new channel attributes to the BASS_ChannelSetAttribute/BASS_ChannelGetAttribute or even new effects to the BASS_ChannelSetFX. Note, that the respective add-on must have already been loaded before being able to use these new options. So if the first thing you try to do with an add-on is to set one of it's new options, then you need to explititly load the add-on first.

There are 2 ways to load an add-on library explititly into memory:

  1. by calling any of the add-on methods for the very first time before using a new option (e.g. use the _GetVersion method, if available) - which is the recommended way (this results in the very first call to a library method being a little slower than all subsequent calls).
  2. by calling a BASS.NET specific "LoadMe" method associated with each add-on, e.g. LoadMe (when manually loading an add-on, make sure to call FreeMe when you are done with the add-on).
Remember: For all plugins it is recommended to use BASS_PluginLoad.

Speaker Assignement

Most soundcards these days are capable of more than plain stereo output. To take advantage of this, channels can be assigned to specific speakers. For example, channels can be played on the front or rear speakers to effectively have 2 separate stereo outputs from the one device. A 3rd stereo output is available on 5.1 cards, and a 4th on 7.1 cards.

To use speaker assignment, the output device obviously needs to support more than 2 speakers - the speakers member of the BASS_INFO class can be used to check that. The device's speaker config (in its control panel) will need to be set accordingly too. Speaker assignment is not available with VxD drivers. Windows XP/2000 use only WDM drivers. Windows Me/98SE can use either WDM or the older VxD driver model. Windows 98/95 only use VxD drivers.

If BASS doesn't detect the number of speaker correctly you might use the BASS_DEVICE_SPEAKERS or the BASS_DEVICE_CPSPEAKERS flag in the BASS_Init call).

Use the BASS_SPEAKER_* flags of the BASSFlag enum at creation of a sample/stream to assigned the output to specific speakers.

Stereo speaker assignment flags:

BASS_SPEAKER_FRONTThe front speakers.
BASS_SPEAKER_REARThe rear/side speakers.
BASS_SPEAKER_CENLFEThe center and LFE (subwoofer) speakers in a 5.1 setup.
BASS_SPEAKER_REAR2The rear center speakers in a 7.1 setup.
Mono speaker assignment flags:
BASS_SPEAKER_FRONTLEFTThe left-front speaker.
BASS_SPEAKER_FRONTRIGHTThe right-front speaker.
BASS_SPEAKER_REARLEFTThe left-rear/side speaker.
BASS_SPEAKER_REARRIGHTThe right-rear/side speaker.
BASS_SPEAKER_CENTERThe center speaker in a 5.1 speaker setup.
BASS_SPEAKER_LFEThe LFE (subwoofer) speaker in a 5.1 setup.
BASS_SPEAKER_REAR2LEFTThe left-rear center speaker in a 7.1 setup.
BASS_SPEAKER_REAR2RIGHTThe right-rear center speaker in a 7.1 setup.
The stereo speaker assignment flags can also be used with mono channels, so that, for example, a mono channel can be played on both the front speakers. But mono speaker assignment flags can not be used with stereo channels, so, for example, it's not possible to play a stereo channel on just the center speaker.

Here is an example on how to stream two different files on the same device but using different speaker flags, so that one file plays on the front speakers and the other file plays on the rear speakers:

C#: Multiple Speakers
// init the output device
Bass.BASS_Init(1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
...
// create a first stream using the front speakers
int stream1 = Bass.BASS_StreamCreateFile("test1.mp3", 0L, 0L, BASSFlag.BASS_SPEAKER_FRONT);
Bass.BASS_ChannelPlay(stream1, false);

// create a second stream using the rear speakers
int stream2 = Bass.BASS_StreamCreateFile("test2.mp3", 0L, 0L, BASSFlag.BASS_SPEAKER_REAR);
Bass.BASS_ChannelPlay(stream2, false);
...
VB.Net: Multiple Speakers
' init the output device
Bass.BASS_Init(1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero)
...
' create a first stream using the front speakers
Dim stream1 As Integer = Bass.BASS_StreamCreateFile("test1.mp3", 0L, 0L, BASSFlag.BASS_SPEAKER_FRONT)
Bass.BASS_ChannelPlay(stream1, False)

' create a second stream using the rear speakers
Dim stream2 As Integer = Bass.BASS_StreamCreateFile("test2.mp3", 0L, 0L, BASSFlag.BASS_SPEAKER_REAR)
Bass.BASS_ChannelPlay(stream2, False)
...

Multi-Channel Streams

Most soundcards these days are capable of more than plain stereo output. To take advantage of this, as well as the speaker assignment flags, BASS has support for multi-channel user streams, and also has built-in support for multi-channel OGG, WAV and AIFF files. Add-ons provide support for other multi-channel formats.

Except on Windows Vista/7, to use multi-channel streams in Windows requires the output device to have WDM drivers installed. The device should also support more than 2 speakers - the speakers member of the BASS_INFO class can be used to check that. When a stream having more channels than there are speakers is played, the extra channels may be heard on other speakers, or not heard at all.

One limitation when using multi-channel streams is that BASS_ChannelSetFX can not be used to set DX8 effects on the stream.

Using Multiple Devices

Simultaneously using multiple devices is supported in the BASS API via a context switching system - instead of there being an extra "device" parameter in the function calls, the device to be used is set prior to calling the functions (via BASS_SetDevice). The device setting is local to the current thread, so calling functions with different devices simultaneously in multiple threads is not a problem.

The functions that use the device selection are the following: BASS_Free, BASS_GetDSoundObject, BASS_GetInfo, BASS_Start, BASS_Stop, BASS_Pause, BASS_SetVolume, BASS_GetVolume, BASS_Set3DFactors, BASS_Get3DFactors, BASS_Set3DPosition, BASS_Get3DPosition, BASS_SetEAXParameters, BASS_GetEAXParameters.

It also determines which device is used by a new sample/stream/music: BASS_MusicLoad, BASS_SampleLoad, BASS_StreamCreateFile, etc.

When one of the above functions (or BASS_GetDevice/BASS_SetDevice) is called, BASS will check the current thread's device setting, and if no device is selected (or the selected device is not initialized), BASS will automatically select the lowest device that is initialized. This means that when using a single device, there is no need to use the BASS_SetDevice function - BASS will automatically use the device that's initialized. Even if you free the device, and initialize another, BASS will automatically switch to the one that is initialized.

Here is an example on how to stream two different files on two different devices, so that one file plays on the first output and the other file plays on the second output device:

C#: Multiple Devices
// init the two output devices
Bass.BASS_Init(1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
Bass.BASS_Init(2, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
...
// set the device context to the first device
Bass.BASS_SetDevice(1);
// create a first stream in this context
int stream1 = Bass.BASS_StreamCreateFile("test1.mp3", 0L, 0L, BASSFlag.BASS_DEFAULT);
Bass.BASS_ChannelPlay(stream1, false);

// set the device context to the second device
Bass.BASS_SetDevice(2);
// create a second stream using this context
int stream2 = Bass.BASS_StreamCreateFile("test2.mp3", 0L, 0L, BASSFlag.BASS_DEFAULT);
Bass.BASS_ChannelPlay(stream2, false);
...
// if you want to change the output of the first stream to the second output
// you might call this (even during playback)
Bass.BASS_ChannelSetDevice(stream1, 2);
...
VB.Net: Multiple Devices
' init the two output devices
Bass.BASS_Init(1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero)
Bass.BASS_Init(2, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero)
...
' set the device context to the first device
Bass.BASS_SetDevice(1)
' create a first stream using this context
Dim stream1 As Integer = Bass.BASS_StreamCreateFile("test1.mp3", 0L, 0L, BASSFlag.BASS_DEFAULT)
Bass.BASS_ChannelPlay(stream1, False)

' set the device context to the second device
Bass.BASS_SetDevice(2)
' create a second stream using this context
Dim stream2 As Integer = Bass.BASS_StreamCreateFile("test2.mp3", 0L, 0L, BASSFlag.BASS_DEFAULT)
Bass.BASS_ChannelPlay(stream2, False)
...
' if you want to change the output of the first stream to the second output
' you might call this (even during playback)
Bass.BASS_ChannelSetDevice(stream1, 2)
...

Applying Effects (DSP)

A digital signal processor (DSP) is used to modify the signal (sample data) of the audio sound (e.g. chorus, reverb, flanger, echo, EQ, I3DL etc). With BASS you have a lot of capabilities to use DSPs:

DX8/DMO Effects

DX8 effects are otherwise known as DirectX Media Object (DMO) effects, and as the name suggests, requires DirectX 8 (or above) to be installed. BASS provides 2 different implementations of DX8 effects, each with its advantages. The method used by a sample/stream depends on whether the BASS_SAMPLE_FX flag is used in its creation. Effects are set on a channel using the BASS_ChannelSetFX method.

  • With the BASS_SAMPLE_FX flag:

    This is the standard way of using DX8 effects. The main advantage of this method is that effect parameter changes are audible instantaneously. The main disadvantages are that the channel's sample rate can not be changed (can now with DX9), and it can not be used with decoding channels or speaker assignment.

  • Without the BASS_SAMPLE_FX flag:

    The advantages/disadvantages of this method are basically the opposite of the other method - the channel's sample rate can be changed, but there's a delay in effect parameter changes being audible. The reason being that, using this method, the effects are applied at the same stage as user DSP functions. There are also other advantages to this method, as shown in the table below.

With FX flagWithout FX flag
Adding & Removing:Channel need be stopped/paused when adding or removing an effect.Can add and remove effects without stopping playback.
Decoding channels:Not possible.Automatically used for decoding channels.
Speaker assignment:Not possible.Can be used with speaker assignment.
Recording:Not possible.Automatically used for recording channels.
Parameter changes:Audible instantaneously.Delayed by the length of the channel's buffer - using a smaller buffer means less delay.
Channel sample rate:Can only be changed when using DirectX 9.Can be changed.
Effected sample data:Not available. DSP functions, BASS_ChannelGetData and BASS_ChannelGetLevel receive the original data (without the effects applied).The effected data is available to BASS functions.
Effect chain ordering:Not possible.The effects can be applied in any order you want, and can be intermingled with DSP functions.
Channel buffer length:Must be at least 150ms.No restriction.
CPU usage:CPU use is not included in BASS_GetCPU.CPU use is included in BASS_GetCPU. Also slightly lower CPU usage.
In both cases, DX8 effects are not supported on channels that are more than stereo, and floating-point support is not available prior to DirectX 9.

Away from Windows, the DX8 effects are emulated by BASS and the 'With FX flag' system is unavailable. Floating-point is supported (8.24 bit fixed-point on Windows CE and Android), and the PARAMEQ effect also supports more than stereo.

Mixing/Splitting Multiple Streams

Beside the fact, that you are able to play multiple streams on the same output device in parallel, it is sometimes desired to mix multiple source streams into one single stream for further processing, or you might want to duplicate (split) a single stream into multiple streams procressing the same audio data.

The BassMix add-on provides this ability, including resampling and matrix mixing features.

The usage concept is pretty simple: Instead of using the stream handles directly you first create a new mixer channel. Then you create the sources as decoding channels and plug them into the mixer channel. You do then play out the mixer channel. Source can be plugged or removed to/from the mixer at any time. In addition the mixer channel itself might also be a decoding channel (e.g. to be used with ASIO or WASAPI).

The mixer ensures, that the needed data is automatically requested from the sources as needed (by calling BASS_ChannelGetData internally).

Splitting works similar but the other way around: Based on an existing source stream you create one or more splitter streams on top of it. These splitter streams can then be further used independently (e.g. each splitter can be used to feed a different output).

C#: Creating a mixer and adding two sources
using Un4seen.Bass.AddOn.Mix;
...

// create a mixer output stream
int mixerStream = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT );

// now we need some source channels (must be decoding)
int streamA = Bass.BASS_StreamCreateFile("testA.mp3", 0, 0, 
                        BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT);
int streamB = Bass.BASS_StreamCreateFile("testB.mp3", 0, 0, 
                        BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT);

// finally we plug them into the mixer
BassMix.BASS_Mixer_StreamAddChannel(mixerStream, streamA, 
                   BASSFlag.BASS_STREAM_AUTOFREE | BASSFlag.BASS_MIXER_DOWNMIX);
BassMix.BASS_Mixer_StreamAddChannel(mixerStream, streamB, 
                   BASSFlag.BASS_STREAM_AUTOFREE | BASSFlag.BASS_MIXER_DOWNMIX);

// and play the mixer channel
Bass.BASS_ChannelPlay(mixerStream, false);
VB.Net: Creating a mixer and adding two sources
Imports Un4seen.Bass.AddOn.Mix

' create a mixer output stream
Dim mixerStream As Integer = BassMix.BASS_Mixer_StreamCreate(44100, 2, BASSFlag.BASS_SAMPLE_FLOAT) 

' now we need some source channels (must be decoding)
Dim streamA As Integer = Bass.BASS_StreamCreateFile("testA.mp3", 0, 0, 
                                   BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT) 
Dim streamB As Integer = Bass.BASS_StreamCreateFile("testB.mp3", 0, 0, 
                                   BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_FLOAT) 

' finally we plug them into the mixer
BassMix.BASS_Mixer_StreamAddChannel(mixerStream, streamA, 
                   BASSFlag.BASS_STREAM_AUTOFREE Or BASSFlag.BASS_MIXER_DOWNMIX)
BassMix.BASS_Mixer_StreamAddChannel(mixerStream, streamB, 
                   BASSFlag.BASS_STREAM_AUTOFREE Or BASSFlag.BASS_MIXER_DOWNMIX)

' and play the mixer channel
Bass.BASS_ChannelPlay(mixerStream, False)

Implementation Details

This chapter contains general information about Bass.Net and its implementation details.

Content:

Naming Conventions

The goal was to implement the BASS.NET API as close as possible to the original BASS C/C++ API. However, some changes have been made in order to be .NET compliant and to offer you a little bit more convenience.

The main namespace reflecting the BASS implementation is called Un4seen.Bass Here you will find the main class called Bass, which contains all static BASS methods. The native API functions have been implemented as static methods! So there is no need to create an instance of the Bass class!

In addition the namespace hosts various enumerations, callback delegates and other helper structures (represented in capital letters) which are exposed by BASS (e.g. BASS_INFO). Those original BASS structures have been implemented as classes in the BASS.NET API. This because they are much easier to use and reflect exactly what BASS would expect (no additional casting is needed). Those classes need to be instantiated before their use

BASS Add-Ons are represented in their own namespace called Un4seen.Bass.AddOn.Xyz where .Xyz denotes the abbreviated add-on name. Each add-on namespace again hosts a main class called BassXyz containing all static add-on methods.

E.g. the BASSWMA add-on is located in the Un4seen.Bass.AddOn.Wma namespace and contains the BassWma class exposing all BASSWMA methods.

Beside these native BASS and Add-On namespaces and classes there are several BASS.NET specific ones (to make your life easier). Namely: Utils (helper and conversion class), Un4seen.Bass.AddOn.Tags (TAG reading namespace), Un4seen.Bass.Misc (namespace containing broadcast and streaming, DSP, BPM, encoding, wave form rendering, visualization and other miscellaneous classes), BassAsioHandler (Asio helper class), BassWasapiHandler (Wasapi helper class) and the radio42.Multimedia.Midi (native MIDI in/out support namespace).

Example signature of a BASS API method:
[DllImport("bass.dll", CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool BASS_StreamFree(int handle);

Additional Overloads

For various methods multiple overloads have been implemented. The BASS.NET API offers more methods than the original APIs. This is due to the fact, that the BASS.NET API wants to offer as much convenience as possible. In addition the original APIs often make use of void pointers or non type safe structures or references. Since .NET is always type safe, there was the need to offer multiple overloads to enable all possibilities of the original APIs.

An example are the overloads for the BASS_StreamCreateFile method:

  1. Implementing Ansi Filename support:

    public static int BASS_StreamCreateFile(string file, int offset, int length, int flags)

  2. Implementing Unicode Filename support:

    public static int BASS_StreamCreateFile(string file, int offset, int length, BASSFlag flags)

  3. Implementing Memory streaming support as an IntPtr:

    public static int BASS_StreamCreateFile(IntPtr memory, int offset, int length, BASSFlag flags)

  4. Implementing Memory streaming support as a byte[]:

    public static int BASS_StreamCreateFile(byte[] memory, int offset, int length, BASSFlag flags)

Some overloads make use of an IntPtr references. Note, that the native BASS API often exposes a void *pointer, so make sure to handle these pointers correctly (e.g. as a pinned GCHandle) - see the respective method documentation for details.

Constants

In contrast to native BASS, the BASS.NET API does not make use of any plain constants. All constants have been encapsulated as static enumerations! Enums exist in its API namespace (e.g. the BASSFlag enum exists in the Un4seen.Bass namespace).

However, most add-on related constants (like all additional stream create options) have been incorporated into the main Bass enums.

32-bit vs. 64-bit

BASS.NET is a pure .Net assembly which is compiled with the for Any CPU switch. This means it can directly be used on any 32-bit or 64-bit operating system. In a 32-bit environment BASS.NET will automatically be executed as a 32-bit assembly and in a 64-bit environment as a 64-bit assembly.

As BASS.NET is the .Net wrapper for native BASS and all add-ons you still need these native dlls to run your application. So make sure to use the correct native BASS/add-on dlls (either the 32-bit or the 64-bit once)!

In general .Net (not BASS.NET) tries to automatically load an assembly resp. library with the very first call made to one of its referenced functions – this unless it was already loaded. The same is true with all native dlls. E.g. the first call to one of the BASS functions will actually load the library the function is contained in (if not already loaded).

The .Net runtime environment typically tries to locate a library which needs to be loaded in the current executable directory. So in order to run your application you need to make sure to have the Bass.Net.dll as well as any used native dll (e.g. bass.dll) in your current executable directory. And for the native dlls you have to also make sure to use the correct version (32-bit or 64-bit) depending on your environment resp. operating system.

In normal situations (when you are targeting only one operating system, e.g. only 32-bit systems) you don't have worry any more, as the automatic .Net library loading feature is just working great for you. But when it comes to shipping your application (which you created with BASS and BASS.NET) this might get a bit more complex, e.g. if you are targeting both 32-bit and 64-bit systems. In some cases you want to provide a way to support both OS versions in parallel on a target machine (e.g. because your installer doesn't support any OS depended installation steps and thus picking the correct native dll versions, 32-bit vs. 64-bit, is impossible and needs to be handled manually).

To support these scenarios you need to bypass the automatic loading feature of .Net and load any native library manually (since once they are loaded .Net knows that and wouldn't try to load them again).

For exactly this reason a little helper method exists for each of Bass's module/add-on called: LoadMe. In addition there is a method in the Utils namespace called Is64Bit.

To manually load native BASS libraries and to support both 32-bit and 64-bit operating systems you might create two sub-directories underneath your executable directory called e.g. x86 and x64. Make sure, that these directories contain the correct native BASS libraries.

Your code to load the native libraries manually might then look like this (make sure to execute it before calling any BASS or add-on function!):

C#:
Dim stream As String = ""
if (Utils.Is64Bit)
    targetPath = Path.Combine(Application.StartupPath, "x64");
else
    targetPath = Path.Combine(Application.StartupPath, "x86");

// now load all libs manually
Bass.LoadMe(targetPath);
BassMix.LoadMe(targetPath);
...
loadedPlugIns = Bass.BASS_PluginLoadDirectory(targetPath);
...

// at the end of your application call this!
Bass.FreeMe(targetPath);
BassMix.FreeMe(targetPath);
...
foreach (int plugin in LoadedBassPlugIns.Keys)
    Bass.BASS_PluginFree(plugin);
VB.Net:
string targetPath = "";
If Utils.Is64Bit Then
    targetPath = Path.Combine(Application.StartupPath, "x64")
Else
    targetPath = Path.Combine(Application.StartupPath, "x86")
End If

// now load all libs manually
Bass.LoadMe(targetPath)
BassMix.LoadMe(targetPath)
...
loadedPlugIns = Bass.BASS_PluginLoadDirectory(targetPath)
...

// at the end of your application call this!
Bass.FreeMe(targetPath)
BassMix.FreeMe(targetPath)
...
For Each plugin As Integer In LoadedBassPlugIns.Keys 
    Bass.BASS_PluginFree(plugin) 
Next
Nore1: Make sure to call the above code before you call any other BASS or add-on method, as this would try to load the respective library automatically

Note2: Make sure, if you are using LoadMe to also call FreeMe at the end of your program to unload all the libs you loaded manually!

Also note, that the above code is only needed, if you really want to dynamically support both versions 32-bit and 64-bit in parallel.

Encoding Streams

The BassEnc add-on allows BASS channels to be encoded using any command-line encoder with STDIN support (e.g. LAME/OGGENC2/FAAC/etc.), or any ACM codec. It also includes Shoutcast and Icecast sourcing features, and PCM/WAV file writing. See the Enc namespace for details.

Beside the native BASS encoding support BASS.NET has implemented a complete Encoding-Framework, StreamingServer-Framework and Broadcasting-Solution on top of it:

Encoding-Framework: The BaseEncoder class is the base class for the currently implemented encoders, which are: EncoderLAME, EncoderMP3S, EncoderOGG, EncoderWMA, EncoderWAV, EncoderFAAC, EncoderTooLAME, EncoderFLAC, EncoderTwoLAME, EncoderWinampAACplus,EncoderFHGAACplus, EncoderQTAAC, EncoderNeroAAC, EncoderACM, EncoderCMDLN, EncoderWavPack and EncoderMPC.

They all implement the IBaseEncoder interface, which is used by the StreamingServer-Framework.

You might also use the base class to derive your own encoder implementations.

In addition the base class contains various EncodeFile methods which allows you to easily transcode files from one audio format to another one.

StreamingServer-Framework:The StreamingServer class is the base class for the currently implemented streaming servers, which are: SHOUTcast, ICEcast and WMAcast.

They all implement the IStreamingServer interface, which is used by the broadcasting solution.

You might also use the base class to derive your own streaming server implementations.

Broadcasting Solution: Enables streaming of audio content to the internet (acting as e.g. a source to a SHOUTcast or ICEcast server).

See the BroadCast class for details.

TAG Reading Support

You might retrieve tags/headers from a BASS channel using the BASS_ChannelGetTags method. However this method basically delivers a pointer to the native TAG structure of the respective audio format. Which means it is up to you to evaluate the tags/headers pointers depending on the audio format used.

For your convenience BASS.NET comes with an extra BassTags class, which supports a structured way to read ID3v1, ID3v2, WMA, OGG, RIFF, BEXT, MOD, MP4 and APE tags.

The BASS_TAG_GetFromFile method returns an instance of the TAG_INFO class, which represents the tags being read in.

C#: Reading TAGs from a file
using using Un4seen.Bass.AddOn.Tags;
...
TAG_INFO tagInfo = BassTags.BASS_TAG_GetFromFile("test.mp3");
if ( tagInfo != null )
{
  // display the tags...
  Console.WriteLine(tagInfo.artist);
  Console.WriteLine(tagInfo.title);
  ...
}
VB.Net: Reading TAGs from a file
Imports Imports Un4seen.Bass.AddOn.Tags
...
Dim tagInfo As TAG_INFO =  BassTags.BASS_TAG_GetFromFile("test.mp3") 
If Not tagInfo Is Nothing Then
  ' display the tags...
  Console.WriteLine(tagInfo.artist)
  Console.WriteLine(tagInfo.title)
  ...
End If
TAG editing/writing is not supported by BASS or BASS.NET.

Other BASS.NET Extras

There is more stuff added to the BASS.NET API to make your life easier. So make sure to check the stuff below as well:

General Conversion and Helpers:Check the Utils class.
Display visual Spectrums:Check the Visuals class.
Render a visual WaveForm:Check the WaveForm class.
Creating WAVE files:Check the WaveWriter class.
DSP Framework:Check the BaseDSP class.
Encoder Framework:Check the BaseEncoder class.
Streaming Framework:Check the StreamingServer and BroadCast class.
TAG Reading:Check the BassTags class.
MIDI Input/Output:Check the radio42.Multimedia.Midi namespace.
BPM Detection:See the Un4seen.Bass.AddOn.Fx add-on for details.

Or as an alternative, check the BPMCounter class.

Using BASSASIO:Beside using the native BassAsio add-on you might also check the BassAsioHandler class, which provides ready-made members for direct and more simple ASIO usage.
Using BASSWASAPI:Beside using the native BassWasapi add-on you might also check the BassWasapiHandler class, which provides ready-made members for direct and more simple WASAPI usage.

BASS is unmanaged C/C++ code, BASS.NET is mananged code

This is one of the most ignored facts. Everytime you make a call to a BASS method you are entering the unmanaged world. BASS.NET tries to already marshal as much as possible in each BASS interface call so that you don't have to worry too much about specific interop handling. However, sometimes you have to understand the details about interop marshaling, PInvoke and the concept of the .NET Garbage Collector - so please refer to the related Microsoft documentation.

Make sure to also read this: Interoperating with Unmanaged Code

Int32, Int64 instead of DWORD, QWORD

BASS.NET is type-save, strong-named and CLS-compliant. Even if BASS sometimes uses unsigned DWORD or QWORD values - BASS.NET uses signed values (Int32 or Int64) to ensure language interoperability.

However, internal type casting from Int32 to UInt32 or Int64 to UInt64 is always possible, as integral promotions preserve the value.

Samples

The included samples are quick and dirty! They should just give you a good starting or reference point - but they do NOT cover all exceptions and possible errors which might occur. They are NOT designed for cut and paste to your code. So it is easy to break the samples. Time was spend for a clean API design. The samples therefore lack a little bit in design patterns and nice code.

Note: The provided samples are installed to the 'AppUserData' directory as on Windows Vista/7 projects can/should not be installed to the 'Program Files' directory due to UAC reasons.

As a menu group called "BASS.NET API" is added to the Program menu of your Windows Start menu during installation, just check that menu to locate the samples!

See Also

Other Resources