1. Devices, Buffers and X-Ram

OpenTK.Audio.AudioContext handles Device and Context allocation through Alc.

Instantiating a new AudioContext with a parameterless constructor will initialize the default Device and Context and makes it current. Calling the instance's Dispose method will destroy the Device and Context.

Buffers
Buffers in OpenAL are merely the storage for audio data in raw format, a Buffer Name (often called Handle) must be generated using AL.GenBuffers(). This buffer can now be filled using AL.BufferData().

X-Ram
The X-Ram Extension allows to manually assign Buffers a storage space, it's use is optional and not required. To use the Extension, the XRam wrapper must be instantiated (per used Device), which will take care of most ugly things with Extensions for you. The instantiated object contains a bool that returns if the Extension is usable, which should be checked before calling one of the Extension's Methods.

Example code:

var AC = new AudioContext();
var XRam = new XRamExtension(); // must be instantiated per used Device if X-Ram is desired.
 
// reserve 2 Handles
uint[] MyBuffers = new uint[2]; 
AL.GenBuffers(2, out MyBuffers); 
 
if (XRam.IsInitialized)
{
    XRam.SetBufferMode(ref MyBuffer[0], XRamStorage.Hardware); // optional
}
 
// Load a .wav file from disk. See example code at:
// https://github.com/opentk/opentk/blob/develop/Source/Examples/OpenAL/1.1/Playback.cs#L21
int channels, bits_per_sample, sample_rate;
var sound_data = LoadWave(
    File.Open(filename, FileMode.Open),
    out channels,
    out bits_per_sample,
    out sample_rate);
var sound_format =
    channels == 1 && bits_per_sample == 8 ? ALFormat.Mono8 :
    channels == 1 && bits_per_sample == 16 ? ALFormat.Mono16 :
    channels == 2 && bits_per_sample == 8 ? ALFormat.Stereo8 :
    channels == 2 && bits_per_sample == 16 ? ALFormat.Stereo16 :
    (ALFormat)0; // unknown
 
AL.BufferData(MyBuffers[0], sound_format, sound_data, sound_data.Length, sample_rate);
if (AL.GetError() != ALError.NoError)
{
   // respond to load error etc.
}
 
// Create a sinus waveform through parameters, this currently requires Alut.dll in the application directory
if (XRam.IsInitialized)
{
    XRam.SetBufferMode( ref MyBuffer[1], XRamStorage.Hardware ); // optional
}
MyBuffers[1] = Alut.CreateBufferWaveform(AlutWaveform.Sine, 500f, 42f, 1.5f);
 
// See next book page how to connect the buffers to sources in order to play them.
 
// Cleanup on application shutdown
AL.DeleteBuffers(MyBuffers.Length, MyBuffers); // free previously reserved Handles
AC.Dispose();

A description of the sound data in the Buffer can be queried using AL.GetBuffer().

Now that the Buffer Handle has been assigned a sound, we need to attach it to a Source for playback.