private void FillBuffer() { if (overrideSound != null) { int totalSampleCount = 0; while (totalSampleCount < VoipConfig.BUFFER_SIZE) { int sampleCount = overrideSound.FillStreamBuffer(overridePos, overrideBuf); overridePos += sampleCount * 2; Array.Copy(overrideBuf, 0, uncompressedBuffer, totalSampleCount, sampleCount); totalSampleCount += sampleCount; if (sampleCount == 0) { overridePos = 0; } } int sleepMs = VoipConfig.BUFFER_SIZE * 800 / VoipConfig.FREQUENCY; Thread.Sleep(sleepMs - 1); } else { int sampleCount = 0; while (sampleCount < VoipConfig.BUFFER_SIZE) { Alc.GetInteger(captureDevice, Alc.EnumCaptureSamples, out sampleCount); int alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine sample count: " + alcError.ToString()); } if (sampleCount < VoipConfig.BUFFER_SIZE) { int sleepMs = (VoipConfig.BUFFER_SIZE - sampleCount) * 800 / VoipConfig.FREQUENCY; if (sleepMs >= 1) { Thread.Sleep(sleepMs); } } if (!capturing) { return; } } Alc.CaptureSamples(captureDevice, nativeBuffer, VoipConfig.BUFFER_SIZE); Marshal.Copy(nativeBuffer, uncompressedBuffer, 0, uncompressedBuffer.Length); } }
internal int GetQueuedSampleCount() { if (_state == MicrophoneState.Stopped || BufferReady == null) { return(0); } int[] values = new int[1]; Alc.GetInteger(_captureDevice, AlcGetInteger.CaptureSamples, 1, values); CheckALCError("Failed to query capture samples."); return(values[0]); }
public void ChangeAudioDevice(string DeviceName) { this.Device = Alc.OpenDevice(DeviceName); this.AudioContext = Alc.CreateContext(Device, (int[])null); Alc.MakeContextCurrent(AudioContext); Alc.GetInteger(Device, AlcGetInteger.AttributesSize, 1, out int size); int[] data = new int[size]; Alc.GetInteger(Device, AlcGetInteger.AllAttributes, size, data); this.MaxSourceCount = data[Alc.GetEnumValue(Device, "ALC_MONO_SOURCES")];//ここあやしい Sources = AL.GenSources(MaxSourceCount); }
public AudioDevice(string deviceName) { if (deviceName != null && !AvailableDevices.Contains(deviceName)) { throw new InvalidOperationException(string.Format("AudioDevice \"{0}\" does not exist.", deviceName)); } Context = new OpenTK.Audio.AudioContext(deviceName, 0, 15, true, true, AudioContext.MaxAuxiliarySends.UseDriverDefault); CheckAlcError(); deviceHandle = Alc.GetContextsDevice(Alc.GetCurrentContext()); CheckAlcError(); Efx = new EffectsExtension(); CheckAlcError(); int[] val = new int[4]; DeviceName = Context.CurrentDevice; VendorName = AL.Get(ALGetString.Vendor); Renderer = AL.Get(ALGetString.Renderer); DriverVersion = AL.Get(ALGetString.Version); int major, minor; Alc.GetInteger(deviceHandle, AlcGetInteger.MajorVersion, 1, val); major = val[0]; Alc.GetInteger(deviceHandle, AlcGetInteger.MinorVersion, 1, val); minor = val[0]; Version = new Version(major, minor); Alc.GetInteger(deviceHandle, AlcGetInteger.EfxMajorVersion, 1, val); major = val[0]; Alc.GetInteger(deviceHandle, AlcGetInteger.EfxMinorVersion, 1, val); minor = val[0]; EfxVersion = new Version(major, minor); Alc.GetInteger(deviceHandle, AlcGetInteger.EfxMaxAuxiliarySends, 1, val); MaxRoutes = val[0]; Extensions = new List <string>(AL.Get(ALGetString.Extensions).Split(' ')).AsReadOnly(); AL.DistanceModel(ALDistanceModel.ExponentDistance); CheckAudioCapabilities(LogLevel.Verbose); LogDiagnostics(LogLevel.Verbose); Factory = new AudioFactory(this); Listener = new AudioListener(this); Listener.Orientation(Vector3.UnitY, Vector3.UnitZ); updateTaskCancelation = new CancellationTokenSource(); updateTask = Task.Factory.StartNew(Update); }
public AlcDiagnostic(IntPtr dev) { Trace.WriteLine("--- Alc related errors ---"); Alc.GetInteger(dev, AlcGetInteger.MajorVersion, 1, out MajorVersion); Alc.GetInteger(dev, AlcGetInteger.MinorVersion, 1, out MinorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMajorVersion, 1, out EfxMajorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMinorVersion, 1, out EfxMinorVersion); Alc.GetInteger(dev, AlcGetInteger.EfxMaxAuxiliarySends, 1, out EfxMaxAuxiliarySends); ExtensionString = Alc.GetString(dev, AlcGetString.Extensions); foreach (string s in Alc_Extension_C_Names) { Extensions.Add(s, Alc.IsExtensionPresent(dev, s)); } }
private OpenALSoundController() { try { this.context = new AudioContext(); } catch (Exception ex) { OpenALSoundController.Log("Last error in enumerator is " + AudioDeviceEnumerator.LastError); int num = (int)MessageBox.Show("Error initializing audio subsystem. Game will now exit.\n(see debug log for more details)", "OpenAL Error", MessageBoxButtons.OK, MessageBoxIcon.Hand); throw; } OpenALSoundController.Log("Sound manager initialized!"); int[] data1 = new int[1]; IntPtr contextsDevice = Alc.GetContextsDevice(Alc.GetCurrentContext()); Alc.GetInteger(contextsDevice, AlcGetInteger.AttributesSize, 1, data1); int[] data2 = new int[data1[0]]; Alc.GetInteger(contextsDevice, AlcGetInteger.AllAttributes, data1[0], data2); for (int index = 0; index < data2.Length; ++index) { if (data2[index] == 4112) { OpenALSoundController.Log("Available mono sources : " + (object)data2[index + 1]); break; } } this.filterId = ALHelper.Efx.GenFilter(); ALHelper.Efx.Filter(this.filterId, EfxFilteri.FilterType, 1); ALHelper.Efx.Filter(this.filterId, EfxFilterf.LowpassGain, 1f); ALHelper.Efx.Filter(this.filterId, EfxFilterf.LowpassGainHF, 1f); AL.DistanceModel(ALDistanceModel.InverseDistanceClamped); this.freeBuffers = new ConcurrentStack <int>(); this.ExpandBuffers(256); this.allocatedBuffers = new Dictionary <SoundEffect, OpenALSoundController.BufferAllocation>(); this.staleAllocations = new List <KeyValuePair <SoundEffect, OpenALSoundController.BufferAllocation> >(); this.filteredSources = new HashSet <int>(); this.activeSoundEffects = new List <SoundEffectInstance>(); this.freeSources = new ConcurrentStack <int>(); this.ExpandSources(64); }
private void UpdateCapture() { Array.Copy(uncompressedBuffer, 0, prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE); Array.Clear(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE); while (capturing && !Disconnected) { int alcError; if (CanDetectDisconnect) { Alc.GetInteger(captureDevice, Alc.EnumConnected, out int isConnected); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine if capture device is connected: " + alcError.ToString()); } if (isConnected == 0) { DebugConsole.ThrowError("Capture device has been disconnected. You can select another available device in the settings."); Disconnected = true; break; } } Alc.GetInteger(captureDevice, Alc.EnumCaptureSamples, out int sampleCount); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine sample count: " + alcError.ToString()); } if (sampleCount < VoipConfig.BUFFER_SIZE) { int sleepMs = (VoipConfig.BUFFER_SIZE - sampleCount) * 800 / VoipConfig.FREQUENCY; if (sleepMs < 5) { sleepMs = 5; } Thread.Sleep(sleepMs); continue; } GCHandle handle = GCHandle.Alloc(uncompressedBuffer, GCHandleType.Pinned); try { Alc.CaptureSamples(captureDevice, handle.AddrOfPinnedObject(), VoipConfig.BUFFER_SIZE); } finally { handle.Free(); } alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to capture samples: " + alcError.ToString()); } double maxAmplitude = 0.0f; for (int i = 0; i < VoipConfig.BUFFER_SIZE; i++) { uncompressedBuffer[i] = (short)MathHelper.Clamp((uncompressedBuffer[i] * Gain), -short.MaxValue, short.MaxValue); double sampleVal = uncompressedBuffer[i] / (double)short.MaxValue; maxAmplitude = Math.Max(maxAmplitude, Math.Abs(sampleVal)); } double dB = Math.Min(20 * Math.Log10(maxAmplitude), 0.0); LastdB = dB; LastAmplitude = maxAmplitude; bool allowEnqueue = false; if (GameMain.WindowActive) { ForceLocal = captureTimer > 0 ? ForceLocal : false; bool pttDown = false; if ((PlayerInput.KeyDown(InputType.Voice) || PlayerInput.KeyDown(InputType.LocalVoice)) && GUI.KeyboardDispatcher.Subscriber == null) { pttDown = true; if (PlayerInput.KeyDown(InputType.LocalVoice)) { ForceLocal = true; } else { ForceLocal = false; } } if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.Activity) { if (dB > GameMain.Config.NoiseGateThreshold) { allowEnqueue = true; } } else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk) { if (pttDown) { allowEnqueue = true; } } } if (allowEnqueue || captureTimer > 0) { LastEnqueueAudio = DateTime.Now; if (GameMain.Client?.Character != null) { var messageType = !ForceLocal && ChatMessage.CanUseRadio(GameMain.Client.Character, out _) ? ChatMessageType.Radio : ChatMessageType.Default; GameMain.Client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]); } //encode audio and enqueue it lock (buffers) { if (!prevCaptured) //enqueue the previous buffer if not sent to avoid cutoff { int compressedCountPrev = VoipConfig.Encoder.Encode(prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE); EnqueueBuffer(compressedCountPrev); } int compressedCount = VoipConfig.Encoder.Encode(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE); EnqueueBuffer(compressedCount); } captureTimer -= (VoipConfig.BUFFER_SIZE * 1000) / VoipConfig.FREQUENCY; if (allowEnqueue) { captureTimer = GameMain.Config.VoiceChatCutoffPrevention; } prevCaptured = true; } else { captureTimer = 0; prevCaptured = false; //enqueue silence lock (buffers) { EnqueueBuffer(0); } } Thread.Sleep(10); } }
public void Update() { if (Disconnected || Disabled) { return; } if (CanDetectDisconnect) { Alc.GetInteger(alcDevice, Alc.EnumConnected, out int isConnected); int alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine if device is connected: " + alcError.ToString()); } if (isConnected == 0) { DebugConsole.ThrowError("Playback device has been disconnected. You can select another available device in the settings."); GameMain.Config.AudioOutputDevice = "<disconnected>"; Disconnected = true; return; } } if (GameMain.Client != null && GameMain.Config.VoipAttenuationEnabled) { if (Timing.TotalTime > lastAttenuationTime + 0.2) { voipAttenuatedGain = voipAttenuatedGain * 0.9f + 0.1f; } } else { voipAttenuatedGain = 1.0f; } SetCategoryGainMultiplier("default", VoipAttenuatedGain, 1); SetCategoryGainMultiplier("ui", VoipAttenuatedGain, 1); SetCategoryGainMultiplier("waterambience", VoipAttenuatedGain, 1); SetCategoryGainMultiplier("music", VoipAttenuatedGain, 1); if (GameMain.Config.DynamicRangeCompressionEnabled) { float targetGain = (Math.Min(1.0f, 1.0f / PlaybackAmplitude) - 1.0f) * 0.5f + 1.0f; if (targetGain < CompressionDynamicRangeGain) { //if the target gain is lower than the current gain, lower the current gain immediately to prevent clipping CompressionDynamicRangeGain = targetGain; } else { //otherwise, let it rise back smoothly CompressionDynamicRangeGain = (targetGain) * 0.05f + CompressionDynamicRangeGain * 0.95f; } } else { CompressionDynamicRangeGain = 1.0f; } if (streamingThread == null || streamingThread.ThreadState.HasFlag(ThreadState.Stopped)) { bool startedStreamThread = false; for (int i = 0; i < playingChannels.Length; i++) { lock (playingChannels[i]) { for (int j = 0; j < playingChannels[i].Length; j++) { if (playingChannels[i][j] == null) { continue; } if (playingChannels[i][j].IsStream && playingChannels[i][j].IsPlaying) { InitStreamThread(); startedStreamThread = true; } if (startedStreamThread) { break; } } } if (startedStreamThread) { break; } } } }
internal static int[] StaticGetInt(AlcGetInteger param, int[] list) { Alc.GetInteger(IntPtr.Zero, param, list.Length, list); return(list); }
internal static int StaticGetInt(AlcGetInteger param) { int result; Alc.GetInteger(IntPtr.Zero, param, 1, out result); return(result); }
internal int[] GetInt(AlcGetInteger param, int[] list) { Alc.GetInteger(Handle, param, list.Length, list); return(list); }
internal int GetInt(AlcGetInteger param) { int result; Alc.GetInteger(Handle, param, 1, out result); return(result); }
protected bool init() { if (myIsInitialized == true) { return(true); } Info.print("------------------AUDIO MANAGER----------------"); try { //try to get the DirectSound default (openAL-soft's target) string defaultDevice = AudioContext.DefaultDevice; myContext = new AudioContext(defaultDevice); } catch (AudioException ex) { Error.print("Exception trying to initialize OpenAL Context. Verify OpenAL drivers are installed"); Error.print("Exception: {0}", ex.Message); if (ex.InnerException != null) { Error.print("Inner Exception: {0}", ex.InnerException.Message); } return(false); } //make the context current myContext.MakeCurrent(); myContext.CheckErrors(); myDevice = Alc.GetContextsDevice(Alc.GetCurrentContext()); //print out the attributs int attributeSize = 0; Alc.GetInteger(myDevice, AlcGetInteger.AttributesSize, 1, out attributeSize); int[] attBuffer = new int[attributeSize * 2 + 1]; Alc.GetInteger(myDevice, AlcGetInteger.AllAttributes, attributeSize * 2 + 1, attBuffer); int idx = 0; while (attBuffer[idx] != 0) { Info.print(String.Format("Context attribute: {0}:{1}", Audio.enumToString(attBuffer[idx]), attBuffer[idx + 1])); idx += 2; } //print some debug information about the system string alExtensions = AL.Get(ALGetString.Extensions); string alcExtensions = Alc.GetString(myDevice, AlcGetString.Extensions); Info.print("Opened Audio device {0}", myContext.ToString()); Info.print("OpenAL Vendor: {0}", AL.Get(ALGetString.Vendor)); Info.print("OpenAL Version: {0}", AL.Get(ALGetString.Version)); Info.print("OpenAL Renderer: {0}", AL.Get(ALGetString.Renderer)); Info.print("OpenAL Extensions: {0}", AL.Get(ALGetString.Extensions)); Info.print("OpenAL Context Extensions: {0} ", Alc.GetString(myDevice, AlcGetString.Extensions)); string[] extensions = alcExtensions.Split(' '); for (int i = 0; i < extensions.Length; i++) { if (extensions[i] == "ALC_EXT_EFX") { myEnvironmentalProcessingAvailable = true; } } Info.print("Environmental Processing: " + (myEnvironmentalProcessingAvailable ? "available" : "unavailable")); createVoices(myMaxVoices); Info.print("------------------AUDIO MANAGER----------------"); return(true); }
void UpdateCapture() { short[] uncompressedBuffer = new short[VoipConfig.BUFFER_SIZE]; while (capturing) { int alcError; Alc.GetInteger(captureDevice, Alc.EnumCaptureSamples, out int sampleCount); alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to determine sample count: " + alcError.ToString()); } if (sampleCount < VoipConfig.BUFFER_SIZE) { int sleepMs = (VoipConfig.BUFFER_SIZE - sampleCount) * 800 / VoipConfig.FREQUENCY; if (sleepMs < 5) { sleepMs = 5; } Thread.Sleep(sleepMs); continue; } GCHandle handle = GCHandle.Alloc(uncompressedBuffer, GCHandleType.Pinned); try { Alc.CaptureSamples(captureDevice, handle.AddrOfPinnedObject(), VoipConfig.BUFFER_SIZE); } finally { handle.Free(); } alcError = Alc.GetError(captureDevice); if (alcError != Alc.NoError) { throw new Exception("Failed to capture samples: " + alcError.ToString()); } double maxAmplitude = 0.0f; for (int i = 0; i < VoipConfig.BUFFER_SIZE; i++) { uncompressedBuffer[i] = (short)MathHelper.Clamp((uncompressedBuffer[i] * Gain), -short.MaxValue, short.MaxValue); double sampleVal = uncompressedBuffer[i] / (double)short.MaxValue; maxAmplitude = Math.Max(maxAmplitude, Math.Abs(sampleVal)); } double dB = Math.Min(20 * Math.Log10(maxAmplitude), 0.0); LastdB = dB; bool allowEnqueue = false; if (GameMain.WindowActive) { if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.Activity) { if (dB > GameMain.Config.NoiseGateThreshold) { allowEnqueue = true; } } else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk) { if (PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null) { allowEnqueue = true; } } } if (allowEnqueue) { LastEnqueueAudio = DateTime.Now; //encode audio and enqueue it lock (buffers) { int compressedCount = VoipConfig.Encoder.Encode(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE, BufferToQueue, 0, VoipConfig.MAX_COMPRESSED_SIZE); EnqueueBuffer(compressedCount); } } else { //enqueue silence lock (buffers) { EnqueueBuffer(0); } } Thread.Sleep(10); } }
public static void AlcUnitTestFunc() { AudioContext context = new AudioContext(); Trace.WriteLine("Testing AudioContext functions."); Trace.Indent(); // Trace.WriteLine("Suspend()..."); // context.Suspend(); // Trace.Assert(!context.IsProcessing); // // Trace.WriteLine("Process()..."); // context.Process(); // Trace.Assert(context.IsProcessing); //Trace.WriteLine("MakeCurrent()..."); //context.MakeCurrent(); //Trace.Assert(context.IsCurrent); //Trace.WriteLine("IsCurrent = false..."); //context.IsCurrent = false; //Trace.Assert(!context.IsCurrent); //Trace.WriteLine("IsCurrent = true..."); //context.IsCurrent = true; //Trace.Assert(context.IsCurrent); Trace.WriteLine("AudioContext.CurrentContext..."); Trace.Assert(AudioContext.CurrentContext == context); #region Get Attribs //int AttribCount; //Alc.GetInteger(context.Device, AlcGetInteger.AttributesSize, sizeof(int), out AttribCount); //Trace.WriteLine("AttributeSize: " + AttribCount); //if (AttribCount > 0) //{ // int[] Attribs = new int[AttribCount]; // Alc.GetInteger(context.Device, AlcGetInteger.AllAttributes, AttribCount, out Attribs[0]); // for (int i = 0; i < Attribs.Length; i++) // { // Trace.Write(Attribs[i]); // Trace.Write(" "); // } // Trace.WriteLine(); //} #endregion Get Attribs #if false AlDevice MyDevice; AlContext MyContext; // Initialize Open AL MyDevice = Alc.OpenDevice(null); // open default device if (MyDevice != Al.Null) { Trace.WriteLine("Device allocation succeeded."); MyContext = Alc.CreateContext(MyDevice, Al.Null); // create context if (MyContext != Al.Null) { Trace.WriteLine("Context allocation succeeded."); GetOpenALErrors(MyDevice); Alc.SuspendContext(MyContext); // disable context Alc.ProcessContext(MyContext); // enable context. The default state of a context created by alcCreateContext is that it is processing. Al.Bool result = Alc.MakeContextCurrent(MyContext); // set active context Trace.WriteLine("MakeContextCurrent succeeded? " + result); GetOpenALErrors(MyDevice); Trace.WriteLine("Default: " + Alc.GetString(MyDevice, Enums.AlcGetString.DefaultDeviceSpecifier)); Trace.WriteLine("Device: " + Alc.GetString(MyDevice, Enums.AlcGetString.DeviceSpecifier)); Trace.WriteLine("Extensions: " + Alc.GetString(MyDevice, Enums.AlcGetString.Extensions)); GetOpenALErrors(MyDevice); #region Get Attribs int AttribCount; Alc.GetInteger(MyDevice, Enums.AlcGetInteger.AttributesSize, sizeof(int), out AttribCount); Trace.WriteLine("AttributeSize: " + AttribCount); if (AttribCount > 0) { int[] Attribs = new int[AttribCount]; Alc.GetInteger(MyDevice, Enums.AlcGetInteger.AttributesSize, AttribCount, out Attribs[0]); for (int i = 0; i < Attribs.Length; i++) { Trace.Write(", " + Attribs[i]); } Trace.WriteLine( ); } #endregion Get Attribs GetOpenALErrors(MyDevice); AlDevice currdev = Alc.GetContextsDevice(MyContext); AlContext currcon = Alc.GetCurrentContext( ); if (MyDevice == currdev) { Trace.WriteLine("Devices match."); } else { Trace.WriteLine("Error: Devices do not match."); } if (MyContext == currcon) { Trace.WriteLine("Context match."); } else { Trace.WriteLine("Error: Contexts do not match."); } // exit Alc.MakeContextCurrent(Al.Null); // results in no context being current Alc.DestroyContext(MyContext); result = Alc.CloseDevice(MyDevice); Trace.WriteLine("Result: " + result); Trace.ReadLine( ); } else { Trace.WriteLine("Context creation failed."); } } else { Trace.WriteLine("Failed to find suitable Device."); } #endif /* * include <stdlib.h> * include <AL/alut.h> * * int * main (int argc, char **argv) * { * ALuint helloBuffer, helloSource; * alutInit (&argc, argv); * helloBuffer = alutCreateBufferHelloWorld (); alGenSources (1, &helloSource); * alSourcei (helloSource, AL_Buffer, helloBuffer); * alSourcePlay (helloSource); * alutSleep (1); * alutExit (); * return EXIT_SUCCESS; * }*/ /* * * Processing Loop Example: * // PlaceCamera - places OpenGL camera & updates OpenAL listener buffer * void AVEnvironment::PlaceCamera() * { * // update OpenGL camera position * glMatrixMode(GL_PROJECTION); * glLoadIdentity(); * glFrustum(-0.1333, 0.1333, -0.1, 0.1, 0.2, 50.0); * gluLookAt(listenerPos[0], listenerPos[1], listenerPos[2], * (listenerPos[0] + sin(listenerAngle)), listenerPos[1], * (listenerPos[2] - cos(listenerAngle)), * 0.0, 1.0, 0.0); * // update OpenAL * // place listener at camera * alListener3f(AL_POSITION, listenerPos[0], listenerPos[1], listenerPos[2]); * float directionvect[6]; * directionvect[0] = (float) sin(listenerAngle); * directionvect[1] = 0; * directionvect[2] = (float) cos(listenerAngle); * directionvect[3] = 0; * directionvect[4] = 1; * directionvect[5] = 0; * alListenerfv(AL_ORIENTATION, directionvect); * } * */ }
/// \internal /// <summary>Creates the audio context using the specified device.</summary> /// <param name="device">The device descriptor obtained through AudioContext.AvailableDevices, or null for the default device.</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="enableEfx">Indicates whether the EFX extension should be initialized, if present.</param> /// <param name="efxAuxiliarySends">Requires EFX enabled. The number of desired Auxiliary Sends per source.</param> /// <exception cref="ArgumentOutOfRangeException">Occurs when a specified parameter is invalid.</exception> /// <exception cref="AudioDeviceException"> /// Occurs when the specified device is not available, or is in use by another program. /// </exception> /// <exception cref="AudioContextException"> /// Occurs when an audio context could not be created with the specified parameters. /// </exception> /// <exception cref="NotSupportedException"> /// Occurs when an AudioContext already exists.</exception> /// <remarks> /// <para>For maximum compatibility, you are strongly recommended to use the default constructor.</para> /// <para>Multiple AudioContexts are not supported at this point.</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 higher than supported will be clamped by the driver. /// </para> /// </remarks> private void CreateContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxAuxiliarySends) { if (!AudioDeviceEnumerator.IsOpenALSupported) { throw new DllNotFoundException("openal32.dll"); } if (AudioDeviceEnumerator.Version == AudioDeviceEnumerator.AlcVersion.Alc1_1 && AudioDeviceEnumerator.AvailablePlaybackDevices.Count == 0) // Alc 1.0 does not support device enumeration. { throw new NotSupportedException("No audio hardware is available."); } if (context_exists) { throw new NotSupportedException("Multiple AudioContexts are not supported."); } 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 (!String.IsNullOrEmpty(device)) { device_name = device; Device = Alc.OpenDevice(device); // try to open device by name } if (Device == IntPtr.Zero) { device_name = "IntPtr.Zero (null string)"; Device = Alc.OpenDevice(null); // try to open unnamed default device } if (Device == IntPtr.Zero) { device_name = AudioContext.DefaultDevice; Device = Alc.OpenDevice(AudioContext.DefaultDevice); // try to open named default device } if (Device == IntPtr.Zero) { device_name = "None"; throw new AudioDeviceException(String.Format("Audio device '{0}' does not exist or is tied up by another application.", String.IsNullOrEmpty(device) ? "default" : device)); } CheckErrors(); // Build the attribute list List <int> attributes = new List <int>(); if (freq != 0) { attributes.Add((int)AlcContextAttributes.Frequency); attributes.Add(freq); } if (refresh != 0) { attributes.Add((int)AlcContextAttributes.Refresh); attributes.Add(refresh); } attributes.Add((int)AlcContextAttributes.Sync); attributes.Add(sync ? 1 : 0); if (enableEfx && Alc.IsExtensionPresent(Device, "ALC_EXT_EFX")) { int num_slots; switch (efxAuxiliarySends) { case MaxAuxiliarySends.One: case MaxAuxiliarySends.Two: case MaxAuxiliarySends.Three: case MaxAuxiliarySends.Four: num_slots = (int)efxAuxiliarySends; break; default: case MaxAuxiliarySends.UseDriverDefault: Alc.GetInteger(Device, AlcGetInteger.EfxMaxAuxiliarySends, 1, out num_slots); break; } attributes.Add((int)AlcContextAttributes.EfxMaxAuxiliarySends); attributes.Add(num_slots); } attributes.Add(0); context_handle = Alc.CreateContext(Device, attributes.ToArray()); if (context_handle == ContextHandle.Zero) { Alc.CloseDevice(Device); throw new AudioContextException("The audio context could not be created with the specified parameters."); } CheckErrors(); // HACK: OpenAL SI on Linux/ALSA crashes on MakeCurrent. This hack avoids calling MakeCurrent when // an old OpenAL version is detect - it may affect outdated OpenAL versions different than OpenAL SI, // but it looks like a good compromise for now. if (AudioDeviceEnumerator.AvailablePlaybackDevices.Count > 0) { MakeCurrent(); } CheckErrors(); device_name = Alc.GetString(Device, AlcGetString.DeviceSpecifier); lock (audio_context_lock) { available_contexts.Add(this.context_handle, this); context_exists = true; } }