2008-01-17 14:07:22 +00:00
|
|
|
|
#region --- License ---
|
|
|
|
|
/* Copyright (c) 2008 the OpenTK team
|
|
|
|
|
* See license.txt for license details
|
|
|
|
|
* http://www.opentk.com
|
|
|
|
|
*/
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
using OpenTK.OpenAL;
|
|
|
|
|
using OpenTK.OpenAL.Enums;
|
2008-01-18 13:56:27 +00:00
|
|
|
|
using System.Diagnostics;
|
2008-01-17 14:07:22 +00:00
|
|
|
|
|
|
|
|
|
namespace OpenTK.Audio
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Provides methods to create and use an audio context.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class AudioContext : IDisposable
|
|
|
|
|
{
|
|
|
|
|
#region --- Fields ---
|
|
|
|
|
|
|
|
|
|
bool disposed;
|
2008-01-18 14:15:03 +00:00
|
|
|
|
bool is_processing;
|
2008-01-18 13:56:27 +00:00
|
|
|
|
ContextHandle device_handle, context_handle;
|
|
|
|
|
string device_name;
|
2008-01-17 14:07:22 +00:00
|
|
|
|
static object audio_context_lock = new object();
|
2008-01-18 13:56:27 +00:00
|
|
|
|
static List<string> available_devices = new List<string>();
|
|
|
|
|
static Dictionary<ContextHandle, AudioContext> available_contexts = new Dictionary<ContextHandle, AudioContext>();
|
2008-01-17 14:07:22 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region --- Constructors ---
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
#region static AudioContext()
|
|
|
|
|
|
|
|
|
|
/// <private />
|
|
|
|
|
/// <static />
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Runs before the actual class constructor, to load available devices.
|
|
|
|
|
/// </summary>
|
2008-01-22 21:18:47 +00:00
|
|
|
|
//static AudioContext()
|
|
|
|
|
//{
|
|
|
|
|
// LoadAvailableDevices();
|
|
|
|
|
//}
|
2008-01-17 14:07:22 +00:00
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public AudioContext()
|
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
/// <summary>Constructs a new AudioContext, using the default audio device.</summary>
|
|
|
|
|
/// <exception cref="NotSupportedException">Occurs when no audio devices are available.</exception>
|
2008-01-20 20:56:38 +00:00
|
|
|
|
public AudioContext() : this(available_devices.Count > 0 ? available_devices[0] : null, 0, 0, false, 0) { }
|
2008-01-18 13:56:27 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public AudioContext(string device)
|
2008-01-17 14:07:22 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>Constructs a new AudioContext, using the specified audio device.</summary>
|
|
|
|
|
/// <param name="device">The name of the audio device to use.</param>
|
|
|
|
|
/// <remarks>
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
|
|
|
|
|
/// devices.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public AudioContext(string device) : this(device, 0, 0, false, 0) { }
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public AudioContext(string device, int freq)
|
|
|
|
|
|
|
|
|
|
/// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
|
|
|
|
|
/// <param name="device">The name of the audio device to use.</param>
|
|
|
|
|
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
|
2008-01-17 14:07:22 +00:00
|
|
|
|
/// devices.
|
|
|
|
|
/// </remarks>
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <see cref="AudioContext(string device, int freq, int refresh, bool sync, int maxEfxSends)"/>
|
|
|
|
|
public AudioContext(string device, int freq) : this(device, freq, 0, false, 0) { }
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public AudioContext(string device, int freq, int refresh)
|
|
|
|
|
|
|
|
|
|
/// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
|
|
|
|
|
/// <param name="device">The name of the audio device to use.</param>
|
|
|
|
|
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
|
|
|
|
|
/// devices.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <see cref="AudioContext(string device, int freq, int refresh, bool sync, int maxEfxSends)"/>
|
|
|
|
|
public AudioContext(string device, int freq, int refresh)
|
|
|
|
|
: this(device, freq, refresh, false, 0) { }
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public AudioContext(string device)
|
|
|
|
|
|
|
|
|
|
/// <summary>Constructs a new AudioContext, using the specified audio device and device parameters.</summary>
|
|
|
|
|
/// <param name="device">The name of the audio device to use.</param>
|
|
|
|
|
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <param name="sync">Flag, indicating a synchronous context.</param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
|
|
|
|
|
/// devices.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <see cref="AudioContext(string device, int freq, int refresh, bool sync, int maxEfxSends)"/>
|
|
|
|
|
public AudioContext(string device, int freq, int refresh, bool sync)
|
|
|
|
|
: this(available_devices[0], freq, refresh, sync, 0) { }
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public AudioContext(string device, int freq, int refresh, bool sync, int maxEfxSends)
|
|
|
|
|
|
|
|
|
|
/// <summary>Creates the audio context using the specified device and device parameters.</summary>
|
|
|
|
|
/// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices.</param>
|
|
|
|
|
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <param name="sync">Flag, indicating a synchronous context.</param>
|
|
|
|
|
/// <param name="maxEfxSends">Number of auxilliary send slots for the EFX extensions. Can be 0 (use driver default) or higher.</param>
|
|
|
|
|
/// <exception cref="ArgumentNullException">Occurs when the device string is invalid.</exception>
|
|
|
|
|
/// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
|
|
|
|
|
/// <exception cref="InvalidAudioDeviceException">
|
|
|
|
|
/// Occurs when the specified device is not available, or is in use by another program.
|
|
|
|
|
/// </exception>
|
|
|
|
|
/// <exception cref="InvalidAudioContextException">
|
|
|
|
|
/// Occurs when an audio context could not be created with the specified parameters.
|
|
|
|
|
/// </exception>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// <para>
|
|
|
|
|
/// Use AudioContext.AvailableDevices to obtain a list of all available audio devices.
|
|
|
|
|
/// </para>
|
|
|
|
|
/// <para>
|
|
|
|
|
/// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
|
|
|
|
|
/// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
|
|
|
|
|
/// Values not supported will be clamped by the driver.
|
|
|
|
|
/// </para>
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public AudioContext(string device, int freq, int refresh, bool sync, int maxEfxSends)
|
2008-01-17 14:07:22 +00:00
|
|
|
|
{
|
2008-01-18 13:56:27 +00:00
|
|
|
|
CreateContext(device, freq, refresh, sync, maxEfxSends);
|
2008-01-17 14:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
#region --- Private Members ---
|
|
|
|
|
|
|
|
|
|
#region static void LoadAvailableDevices()
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <private />
|
|
|
|
|
/// <static />
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Loads all available audio devices into the available_devices array.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Only called by the static AudioContext constructor.
|
|
|
|
|
/// </remarks>
|
2008-01-17 14:07:22 +00:00
|
|
|
|
static void LoadAvailableDevices()
|
|
|
|
|
{
|
|
|
|
|
lock (audio_context_lock)
|
|
|
|
|
{
|
2008-01-18 13:56:27 +00:00
|
|
|
|
if (available_devices.Count == 0)
|
2008-01-17 14:07:22 +00:00
|
|
|
|
{
|
2008-01-18 13:56:27 +00:00
|
|
|
|
if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT"))
|
|
|
|
|
available_devices.AddRange(Alc.GetString(IntPtr.Zero, AlcGetStringList.AllDevicesSpecifier));
|
2008-01-20 21:05:49 +00:00
|
|
|
|
else
|
|
|
|
|
Debug.Print("Device enumeration extension not available. Failed to enumerate devices.");
|
2008-01-17 14:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region void CreateContext(string device)
|
|
|
|
|
|
|
|
|
|
/// <private />
|
|
|
|
|
/// <summary>Creates the audio context using the specified device.</summary>
|
2008-01-20 20:56:38 +00:00
|
|
|
|
/// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices, or null for the default device.</param>
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <param name="freq">Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default.</param>
|
|
|
|
|
/// <param name="refresh">Refresh intervals, in units of Hz. Pass 0 for driver default.</param>
|
2008-01-17 14:07:22 +00:00
|
|
|
|
/// <param name="sync">Flag, indicating a synchronous context.</param>
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <param name="maxEfxSends">Number of auxilliary send slots for the EFX extensions. Can be 0 (use driver default) or higher.</param>
|
|
|
|
|
/// <exception cref="ArgumentNullException">Occurs when the device string is invalid.</exception>
|
|
|
|
|
/// /// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception>
|
2008-01-17 14:07:22 +00:00
|
|
|
|
/// <exception cref="InvalidAudioDeviceException">
|
|
|
|
|
/// Occurs when the specified device is not available, or is in use by another program.
|
|
|
|
|
/// </exception>
|
|
|
|
|
/// <exception cref="InvalidAudioContextException">
|
|
|
|
|
/// Occurs when an audio context could not be created with the specified parameters.
|
|
|
|
|
/// </exception>
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <remarks>
|
|
|
|
|
/// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well
|
|
|
|
|
/// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends.
|
|
|
|
|
/// Values higher than supported will be clamped by the driver.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
void CreateContext(string device, int freq, int refresh, bool sync, int maxEfxSends)
|
2008-01-17 14:07:22 +00:00
|
|
|
|
{
|
2008-01-20 20:56:38 +00:00
|
|
|
|
//if (String.IsNullOrEmpty(device)) throw new ArgumentNullException("device");
|
2008-01-18 13:56:27 +00:00
|
|
|
|
if (freq < 0) throw new ArgumentOutOfRangeException("freq", freq, "Should be greater than zero.");
|
|
|
|
|
if (refresh < 0) throw new ArgumentOutOfRangeException("refresh", refresh, "Should be greater than zero.");
|
|
|
|
|
if (maxEfxSends < 0) throw new ArgumentOutOfRangeException("maxEfxSends", maxEfxSends, "Should be greater than zero.");
|
2008-01-20 21:00:59 +00:00
|
|
|
|
//if (available_devices.Count == 0) throw new NotSupportedException("No audio hardware is available.");
|
2008-01-17 14:07:22 +00:00
|
|
|
|
|
2008-01-22 21:18:47 +00:00
|
|
|
|
if (available_devices.Count == 0)
|
|
|
|
|
LoadAvailableDevices();
|
|
|
|
|
|
|
|
|
|
// HACK: Do not allow multiple contexts under linux (crashes under Ubuntu 7.04 and 7.10)
|
|
|
|
|
if (available_contexts.Count > 0)
|
|
|
|
|
throw new NotSupportedException("Multiple AudioContexts are not supported under Linux.");
|
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
device_handle = Alc.OpenDevice(device);
|
|
|
|
|
if (device_handle == IntPtr.Zero)
|
2008-01-18 13:56:27 +00:00
|
|
|
|
throw new AudioDeviceException("The specified audio device does not exist or is tied up by another application.");
|
|
|
|
|
|
2008-01-20 22:42:49 +00:00
|
|
|
|
CheckForAlcErrors();
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
device_name = device;
|
2008-01-22 21:18:47 +00:00
|
|
|
|
|
2008-01-20 21:00:59 +00:00
|
|
|
|
// Build the attribute list
|
2008-01-17 14:07:22 +00:00
|
|
|
|
List<int> attributes = new List<int>();
|
2008-01-18 13:56:27 +00:00
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
if (freq != 0)
|
|
|
|
|
{
|
|
|
|
|
attributes.Add((int)AlcContextAttributes.Frequency);
|
|
|
|
|
attributes.Add(freq);
|
|
|
|
|
}
|
2008-01-18 13:56:27 +00:00
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
if (refresh != 0)
|
|
|
|
|
{
|
|
|
|
|
attributes.Add((int)AlcContextAttributes.Refresh);
|
|
|
|
|
attributes.Add(refresh);
|
|
|
|
|
}
|
2008-01-18 13:56:27 +00:00
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
attributes.Add((int)AlcContextAttributes.Frequency);
|
|
|
|
|
attributes.Add(sync ? 1 : 0);
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
if (maxEfxSends > 0)
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
//if (Alc.IsExtensionPresent(device_handle, "ALC_EXT_EFX"))
|
|
|
|
|
//attributes.Add((int)AlcContextAttributes.MaxAuxilliarySends);
|
|
|
|
|
//attributes.Add(maxEfxSends);
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
context_handle = Alc.CreateContext(device_handle, attributes.ToArray());
|
2008-01-22 21:18:47 +00:00
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
if (context_handle == IntPtr.Zero)
|
|
|
|
|
{
|
|
|
|
|
Alc.CloseDevice(device_handle);
|
2008-01-18 13:56:27 +00:00
|
|
|
|
throw new AudioContextException("The audio context could not be created with the specified parameters.");
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-20 22:42:49 +00:00
|
|
|
|
CheckForAlcErrors();
|
2008-01-18 13:56:27 +00:00
|
|
|
|
|
2008-01-20 22:42:49 +00:00
|
|
|
|
MakeCurrent();
|
2008-01-18 14:15:03 +00:00
|
|
|
|
|
2008-01-20 22:42:49 +00:00
|
|
|
|
CheckForAlcErrors();
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
//device_name = Alc.GetString(device_handle, AlcGetString.DeviceSpecifier);
|
|
|
|
|
//Debug.Print(device_name);
|
|
|
|
|
lock (audio_context_lock)
|
|
|
|
|
{
|
|
|
|
|
available_contexts.Add(this.context_handle, this);
|
2008-01-17 14:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-20 22:42:49 +00:00
|
|
|
|
#region void CheckForAlcErrors()
|
|
|
|
|
|
|
|
|
|
void CheckForAlcErrors()
|
|
|
|
|
{
|
|
|
|
|
AlcError err = Alc.GetError(device_handle);
|
|
|
|
|
if (err != AlcError.NoError)
|
|
|
|
|
throw new AudioContextException(err.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
#region static void MakeCurrent(AudioContext context)
|
|
|
|
|
|
|
|
|
|
/// <private />
|
|
|
|
|
/// <summary>Makes the specified AudioContext current in the calling thread.</summary>
|
|
|
|
|
/// <param name="context">The OpenTK.Audio.AudioContext to make current, or null.</param>
|
|
|
|
|
/// <exception cref="ObjectDisposedException">
|
|
|
|
|
/// Occurs if this function is called after the AudioContext has been disposed.
|
|
|
|
|
/// </exception>
|
|
|
|
|
/// <exception cref="AudioContextException">
|
|
|
|
|
/// Occurs when the AudioContext could not be made current.
|
|
|
|
|
/// </exception>
|
|
|
|
|
static void MakeCurrent(AudioContext context)
|
|
|
|
|
{
|
2008-01-20 22:42:49 +00:00
|
|
|
|
lock (audio_context_lock)
|
2008-01-18 13:56:27 +00:00
|
|
|
|
{
|
|
|
|
|
if (!Alc.MakeContextCurrent(context != null ? (IntPtr)context.context_handle : IntPtr.Zero))
|
2008-01-20 22:35:46 +00:00
|
|
|
|
throw new AudioContextException(Alc.GetError(
|
|
|
|
|
context != null ? (IntPtr)context.context_handle : IntPtr.Zero).ToString());
|
2008-01-18 13:56:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2008-01-17 14:07:22 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-20 17:55:55 +00:00
|
|
|
|
// TODO: Remove before release!
|
|
|
|
|
public IntPtr Device { get { return device_handle.Handle; } }
|
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
#region --- Public Members ---
|
|
|
|
|
|
|
|
|
|
#region public static string[] AvailableDevices
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets a System.String array containing all available audio devices.
|
|
|
|
|
/// </summary>
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <remarks>This property allocates memory.</remarks>
|
|
|
|
|
public static string[] AvailableDevices
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2008-01-22 21:18:47 +00:00
|
|
|
|
if (available_devices.Count == 0)
|
|
|
|
|
LoadAvailableDevices();
|
2008-01-18 13:56:27 +00:00
|
|
|
|
return available_devices.ToArray();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public void MakeCurrent()
|
|
|
|
|
|
|
|
|
|
/// <summary>Makes the AudioContext current in the calling thread.</summary>
|
|
|
|
|
/// <exception cref="ObjectDisposedException">
|
|
|
|
|
/// Occurs if this function is called after the AudioContext has been disposed.
|
|
|
|
|
/// </exception>
|
|
|
|
|
/// <exception cref="AudioContextException">
|
|
|
|
|
/// Occurs when the AudioContext could not be made current.
|
|
|
|
|
/// </exception>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Only one AudioContext can be current in the application at any time,
|
|
|
|
|
/// <b>regardless of the number of threads</b>.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public void MakeCurrent()
|
|
|
|
|
{
|
|
|
|
|
AudioContext.MakeCurrent(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public bool IsCurrent
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets a System.Boolean indicating whether the AudioContext
|
|
|
|
|
/// is current.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Only one AudioContext can be current in the application at any time,
|
|
|
|
|
/// <b>regardless of the number of threads</b>.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public bool IsCurrent
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
lock (audio_context_lock)
|
|
|
|
|
{
|
|
|
|
|
if (available_contexts.Count == 0)
|
|
|
|
|
return false;
|
|
|
|
|
else
|
2008-01-18 15:10:25 +00:00
|
|
|
|
{
|
|
|
|
|
return AudioContext.CurrentContext == this;
|
|
|
|
|
}
|
2008-01-18 13:56:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (value) AudioContext.MakeCurrent(this);
|
|
|
|
|
else AudioContext.MakeCurrent(null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-18 14:15:03 +00:00
|
|
|
|
#region public bool IsProcessing
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets a System.Boolean indicating whether the AudioContext is
|
|
|
|
|
/// currently processing audio events.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <seealso cref="Process"/>
|
|
|
|
|
/// <seealso cref="Suspend"/>
|
|
|
|
|
public bool IsProcessing
|
|
|
|
|
{
|
|
|
|
|
get { return is_processing; }
|
|
|
|
|
private set { is_processing = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
#region public void Process
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Processes queued audio events.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// <para>
|
|
|
|
|
/// If AudioContext.IsSynchronized is true, this function will resume
|
|
|
|
|
/// the internal audio processing thread. If AudioContext.IsSynchronized is false,
|
|
|
|
|
/// you will need to call this function multiple times per second to process
|
|
|
|
|
/// audio events.
|
|
|
|
|
/// </para>
|
|
|
|
|
/// <para>
|
|
|
|
|
/// In some implementations this function may have no effect.
|
|
|
|
|
/// </para>
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <exception cref="ObjectDisposedException">Occurs when this function is called after the AudioContext had been disposed.</exception>
|
|
|
|
|
/// <seealso cref="Suspend"/>
|
|
|
|
|
/// <seealso cref="IsSuspended"/>
|
|
|
|
|
/// <seealso cref="IsSynchronized"/>
|
|
|
|
|
public void Process()
|
|
|
|
|
{
|
|
|
|
|
if (disposed) throw new ObjectDisposedException(this.ToString());
|
|
|
|
|
Alc.ProcessContext(this.context_handle);
|
2008-01-18 14:15:03 +00:00
|
|
|
|
IsProcessing = true;
|
2008-01-18 13:56:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public void Suspend
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Suspends processing of audio events.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// <para>
|
|
|
|
|
/// To avoid audio artifacts when calling this function, set audio gain to zero before
|
|
|
|
|
/// suspending an AudioContext.
|
|
|
|
|
/// </para>
|
|
|
|
|
/// <para>
|
|
|
|
|
/// In some implementations, it can be faster to suspend processing before changing
|
|
|
|
|
/// AudioContext state.
|
|
|
|
|
/// </para>
|
|
|
|
|
/// <para>
|
|
|
|
|
/// In some implementations this function may have no effect.
|
|
|
|
|
/// </para>
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <exception cref="ObjectDisposedException">Occurs when this function is called after the AudioContext had been disposed.</exception>
|
|
|
|
|
/// <seealso cref="Process"/>
|
|
|
|
|
/// <seealso cref="IsSuspended"/>
|
|
|
|
|
/// <seealso cref="IsSynchronized"/>
|
|
|
|
|
public void Suspend()
|
|
|
|
|
{
|
|
|
|
|
if (disposed) throw new ObjectDisposedException(this.ToString());
|
|
|
|
|
Alc.SuspendContext(this.context_handle);
|
2008-01-18 14:15:03 +00:00
|
|
|
|
IsProcessing = false;
|
2008-01-18 13:56:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public static AudioContext CurrentContext
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the OpenTK.Audio.AudioContext which is current in the application.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Only one AudioContext can be current in the application at any time,
|
|
|
|
|
/// <b>regardless of the number of threads</b>.
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public static AudioContext CurrentContext
|
2008-01-17 14:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2008-01-18 13:56:27 +00:00
|
|
|
|
lock (audio_context_lock)
|
|
|
|
|
{
|
|
|
|
|
if (available_contexts.Count == 0)
|
|
|
|
|
return null;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AudioContext context;
|
|
|
|
|
AudioContext.available_contexts.TryGetValue(
|
|
|
|
|
(ContextHandle)Alc.GetCurrentContext(),
|
|
|
|
|
out context);
|
|
|
|
|
return context;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-01-17 14:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region --- IDisposable Members ---
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Disposes of the AudioContext, cleaning up all resources consumed by it.
|
|
|
|
|
/// </summary>
|
2008-01-17 14:07:22 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
this.Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Dispose(bool manual)
|
|
|
|
|
{
|
|
|
|
|
if (!disposed)
|
|
|
|
|
{
|
2008-01-18 13:56:27 +00:00
|
|
|
|
available_contexts.Remove(this.context_handle);
|
|
|
|
|
|
|
|
|
|
if (this.IsCurrent)
|
|
|
|
|
this.IsCurrent = false;
|
|
|
|
|
|
|
|
|
|
if (context_handle != IntPtr.Zero)
|
|
|
|
|
Alc.DestroyContext(context_handle);
|
|
|
|
|
|
|
|
|
|
if (device_handle != IntPtr.Zero)
|
|
|
|
|
Alc.CloseDevice(device_handle);
|
|
|
|
|
|
2008-01-17 14:07:22 +00:00
|
|
|
|
if (manual)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
disposed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~AudioContext()
|
|
|
|
|
{
|
|
|
|
|
this.Dispose(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2008-01-18 13:56:27 +00:00
|
|
|
|
|
|
|
|
|
#region --- Overrides ---
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
|
|
|
|
return base.GetHashCode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
|
|
|
|
return base.Equals(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return String.Format("{0} (handle: {1}, device: {2})",
|
|
|
|
|
this.device_name, this.context_handle, this.device_handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2008-01-17 14:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region --- Exceptions ---
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <summary>Represents errors related to an Audio device.</summary>
|
|
|
|
|
public class AudioDeviceException : Exception
|
2008-01-17 14:07:22 +00:00
|
|
|
|
{
|
2008-01-18 13:56:27 +00:00
|
|
|
|
public AudioDeviceException() : base() { }
|
|
|
|
|
public AudioDeviceException(string message) : base(message) { }
|
2008-01-17 14:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-18 13:56:27 +00:00
|
|
|
|
/// <summary>Represents errors related to an AudioContext.</summary>
|
|
|
|
|
public class AudioContextException : Exception
|
2008-01-17 14:07:22 +00:00
|
|
|
|
{
|
2008-01-18 13:56:27 +00:00
|
|
|
|
public AudioContextException() : base() { }
|
|
|
|
|
public AudioContextException(string message) : base(message) { }
|
2008-01-17 14:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|