public SoundSourcePool(int sourceCount = SoundManager.SOURCE_COUNT) { int alError = Al.NoError; ALSources = new uint[sourceCount]; for (int i = 0; i < sourceCount; i++) { Al.GenSource(out ALSources[i]); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Error generating alSource[" + i.ToString() + "]: " + Al.GetErrorString(alError)); } if (!Al.IsSource(ALSources[i])) { throw new Exception("Generated alSource[" + i.ToString() + "] is invalid!"); } Al.SourceStop(ALSources[i]); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Error stopping newly generated alSource[" + i.ToString() + "]: " + Al.GetErrorString(alError)); } Al.Sourcef(ALSources[i], Al.MinGain, 0.0f); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Error setting min gain: " + Al.GetErrorString(alError)); } Al.Sourcef(ALSources[i], Al.MaxGain, 1.0f); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Error setting max gain: " + Al.GetErrorString(alError)); } Al.Sourcef(ALSources[i], Al.RolloffFactor, 1.0f); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Error setting rolloff factor: " + Al.GetErrorString(alError)); } } }
private const int AMPLITUDE_SAMPLE_COUNT = 4410; //100ms in a 44100hz file public OggSound(SoundManager owner, string filename, bool stream, XElement xElement) : base(owner, filename, stream, true, xElement) { filename = filename.CleanUpPath(); if (!ToolBox.IsProperFilenameCase(filename)) { DebugConsole.ThrowError("Sound file \"" + filename + "\" has incorrect case!"); } reader = new VorbisReader(filename); ALFormat = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16; SampleRate = reader.SampleRate; if (!stream) { int bufferSize = (int)reader.TotalSamples * reader.Channels; float[] floatBuffer = new float[bufferSize]; short[] shortBuffer = new short[bufferSize]; int readSamples = reader.ReadSamples(floatBuffer, 0, bufferSize); playbackAmplitude = new List <float>(); for (int i = 0; i < bufferSize; i += reader.Channels * AMPLITUDE_SAMPLE_COUNT) { float maxAmplitude = 0.0f; for (int j = i; j < i + reader.Channels * AMPLITUDE_SAMPLE_COUNT; j++) { if (j >= bufferSize) { break; } maxAmplitude = Math.Max(maxAmplitude, Math.Abs(floatBuffer[j])); } playbackAmplitude.Add(maxAmplitude); } CastBuffer(floatBuffer, shortBuffer, readSamples); Al.BufferData(ALBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } MuffleBuffer(floatBuffer, SampleRate, reader.Channels); CastBuffer(floatBuffer, shortBuffer, readSamples); Al.BufferData(ALMuffledBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } reader.Dispose(); } }
public override void InitializeALBuffers() { base.InitializeALBuffers(); reader ??= new VorbisReader(Filename); ALFormat = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16; SampleRate = reader.SampleRate; if (!Stream) { int bufferSize = (int)reader.TotalSamples * reader.Channels; float[] floatBuffer = new float[bufferSize]; short[] shortBuffer = new short[bufferSize]; int readSamples = reader.ReadSamples(floatBuffer, 0, bufferSize); playbackAmplitude = new List <float>(); for (int i = 0; i < bufferSize; i += reader.Channels * AMPLITUDE_SAMPLE_COUNT) { float maxAmplitude = 0.0f; for (int j = i; j < i + reader.Channels * AMPLITUDE_SAMPLE_COUNT; j++) { if (j >= bufferSize) { break; } maxAmplitude = Math.Max(maxAmplitude, Math.Abs(floatBuffer[j])); } playbackAmplitude.Add(maxAmplitude); } CastBuffer(floatBuffer, shortBuffer, readSamples); Al.BufferData(ALBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } MuffleBuffer(floatBuffer, SampleRate, reader.Channels); CastBuffer(floatBuffer, shortBuffer, readSamples); Al.BufferData(ALMuffledBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } reader.Dispose(); reader = null; } }
public virtual void DeleteALBuffers() { Owner.KillChannels(this); if (alBuffer != 0) { if (!Al.IsBuffer(alBuffer)) { throw new Exception("Buffer to delete is invalid!"); } Al.DeleteBuffer(alBuffer); alBuffer = 0; int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } } if (alMuffledBuffer != 0) { if (!Al.IsBuffer(alMuffledBuffer)) { throw new Exception("Buffer to delete is invalid!"); } Al.DeleteBuffer(alMuffledBuffer); alMuffledBuffer = 0; int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } } }
public virtual void InitializeALBuffers() { if (!Stream) { Al.GenBuffer(out alBuffer); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(alBuffer)) { throw new Exception("Generated OpenAL buffer is invalid!"); } Al.GenBuffer(out alMuffledBuffer); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(alMuffledBuffer)) { throw new Exception("Generated OpenAL buffer is invalid!"); } } else { alBuffer = 0; } }
public void UpdateStream() { if (!IsStream) { throw new Exception("Called UpdateStream on a non-streamed sound channel!"); } try { Monitor.Enter(mutex); if (!reachedEndSample) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); int state; Al.GetSourcei(alSource, Al.SourceState, out state); bool playing = state == Al.Playing; int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine playing state from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } int unqueuedBufferCount; Al.GetSourcei(alSource, Al.BuffersProcessed, out unqueuedBufferCount); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine processed buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } Al.SourceUnqueueBuffers(alSource, unqueuedBufferCount, unqueuedBuffers); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to unqueue buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } buffersToRequeue += unqueuedBufferCount; int iterCount = buffersToRequeue; for (int k = 0; k < iterCount; k++) { int index = queueStartIndex; short[] buffer = streamShortBuffer; int readSamples = Sound.FillStreamBuffer(streamSeekPos, buffer); float readAmplitude = 0.0f; for (int i = 0; i < Math.Min(readSamples, buffer.Length); i++) { float sampleF = ((float)buffer[i]) / ((float)short.MaxValue); readAmplitude = Math.Max(readAmplitude, Math.Abs(sampleF)); } if (FilledByNetwork) { if (Sound is VoipSound voipSound) { voipSound.ApplyFilters(buffer, readSamples); } if (readSamples <= 0) { streamAmplitude *= 0.5f; decayTimer++; if (decayTimer > 120) //TODO: replace magic number { reachedEndSample = true; } } else { decayTimer = 0; } } else if (Sound.StreamsReliably) { streamSeekPos += readSamples; if (readSamples < STREAM_BUFFER_SIZE) { if (looping) { streamSeekPos = 0; } else { reachedEndSample = true; } } } if (readSamples > 0) { streamBufferAmplitudes[index] = readAmplitude; Al.BufferData <short>(streamBuffers[index], Sound.ALFormat, buffer, readSamples, Sound.SampleRate); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to assign data to stream buffer: " + Al.GetErrorString(alError) + ": " + streamBuffers[index].ToString() + "/" + streamBuffers.Length + ", readSamples: " + readSamples + ", " + debugName); } Al.SourceQueueBuffer(alSource, streamBuffers[index]); queueStartIndex = (queueStartIndex + 1) % 4; alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to queue streamBuffer[" + index.ToString() + "] to stream: " + debugName + ", " + Al.GetErrorString(alError)); } } else { if (readSamples < 0) { reachedEndSample = true; } break; } buffersToRequeue--; } streamAmplitude = streamBufferAmplitudes[queueStartIndex]; Al.GetSourcei(alSource, Al.SourceState, out state); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to retrieve stream source state: " + debugName + ", " + Al.GetErrorString(alError)); } if (state != Al.Playing) { Al.SourcePlay(alSource); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to start stream playback: " + debugName + ", " + Al.GetErrorString(alError)); } } } if (reachedEndSample) { streamAmplitude = 0.0f; } } catch (Exception e) { DebugConsole.ThrowError($"An exception was thrown when updating a sound stream ({debugName})", e); } finally { Monitor.Exit(mutex); } }
public void Dispose() { for (int i = 0; i < ALSources.Length; i++) { Al.DeleteSource(ALSources[i]); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to delete ALSources[" + i.ToString() + "]: " + Al.GetErrorString(alError)); } } ALSources = null; }
public Sound(SoundManager owner, string filename, bool stream, bool streamsReliably) { Owner = owner; Filename = Path.GetFullPath(filename); Stream = stream; StreamsReliably = streamsReliably; BaseGain = 1.0f; BaseNear = 100.0f; BaseFar = 200.0f; if (!stream) { Al.GenBuffer(out alBuffer); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(alBuffer)) { throw new Exception("Generated OpenAL buffer is invalid!"); } Al.GenBuffer(out alMuffledBuffer); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(alMuffledBuffer)) { throw new Exception("Generated OpenAL buffer is invalid!"); } } else { alBuffer = 0; } }
public SoundChannel(Sound sound, float gain, Vector3?position, float near, float far, string category, bool muffle = false) { Sound = sound; debugName = sound == null ? "SoundChannel (null)" : $"SoundChannel ({(string.IsNullOrEmpty(sound.Filename) ? "filename empty" : sound.Filename) })"; IsStream = sound.Stream; FilledByNetwork = sound is VoipSound; decayTimer = 0; streamSeekPos = 0; reachedEndSample = false; buffersToRequeue = 4; muffled = muffle; if (IsStream) { mutex = new object(); } try { if (mutex != null) { Monitor.Enter(mutex); } if (sound.Owner.CountPlayingInstances(sound) < sound.MaxSimultaneousInstances) { ALSourceIndex = sound.Owner.AssignFreeSourceToChannel(this); } if (ALSourceIndex >= 0) { if (!IsStream) { Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to reset source buffer: " + debugName + ", " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(sound.ALBuffer)) { throw new Exception(sound.Filename + " has an invalid buffer!"); } uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer; Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + sound.ALBuffer.ToString() + "): " + debugName + ", " + Al.GetErrorString(alError)); } Al.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to play source: " + debugName + ", " + Al.GetErrorString(alError)); } } else { uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer; Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to reset source buffer: " + debugName + ", " + Al.GetErrorString(alError)); } Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Looping, Al.False); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set stream looping state: " + debugName + ", " + Al.GetErrorString(alError)); } streamShortBuffer = new short[STREAM_BUFFER_SIZE]; streamBuffers = new uint[4]; unqueuedBuffers = new uint[4]; streamBufferAmplitudes = new float[4]; for (int i = 0; i < 4; i++) { Al.GenBuffer(out streamBuffers[i]); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to generate stream buffers: " + debugName + ", " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(streamBuffers[i])) { throw new Exception("Generated streamBuffer[" + i.ToString() + "] is invalid! " + debugName); } } Sound.Owner.InitStreamThread(); } } this.Position = position; this.Gain = gain; this.Looping = false; this.Near = near; this.Far = far; this.Category = category; } catch { throw; } finally { if (mutex != null) { Monitor.Exit(mutex); } } Sound.Owner.Update(); }
public SoundChannel(Sound sound, float gain, Vector3?position, float near, float far, string category, bool muffle = false) { Sound = sound; IsStream = sound.Stream; FilledByNetwork = sound is VoipSound; decayTimer = 0; streamSeekPos = 0; reachedEndSample = false; startedPlaying = true; mutex = new object(); lock (mutex) { if (sound.Owner.CountPlayingInstances(sound) < sound.MaxSimultaneousInstances) { ALSourceIndex = sound.Owner.AssignFreeSourceToChannel(this); } if (ALSourceIndex >= 0) { if (!IsStream) { Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to reset source buffer: " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(sound.ALBuffer)) { throw new Exception(sound.Filename + " has an invalid buffer!"); } uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer; Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + sound.ALBuffer.ToString() + "): " + Al.GetErrorString(alError)); } Al.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to play source: " + Al.GetErrorString(alError)); } } else { Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)sound.ALBuffer); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to reset source buffer: " + Al.GetErrorString(alError)); } Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Looping, Al.False); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set stream looping state: " + Al.GetErrorString(alError)); } streamShortBuffer = new short[STREAM_BUFFER_SIZE]; streamBuffers = new uint[4]; emptyBuffers = new List <uint>(); for (int i = 0; i < 4; i++) { Al.GenBuffer(out streamBuffers[i]); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to generate stream buffers: " + Al.GetErrorString(alError)); } if (!Al.IsBuffer(streamBuffers[i])) { throw new Exception("Generated streamBuffer[" + i.ToString() + "] is invalid!"); } } Sound.Owner.InitStreamThread(); } } this.Position = position; this.Gain = gain; this.Looping = false; this.Near = near; this.Far = far; this.Category = category; } }
public void UpdateStream() { if (!IsStream) { throw new Exception("Called UpdateStream on a non-streamed sound channel!"); } lock (mutex) { if (!reachedEndSample) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); int state; Al.GetSourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.SourceState, out state); bool playing = state == Al.Playing; int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine playing state from streamed source: " + Al.GetErrorString(alError)); } int buffersToUnqueue = 0; uint[] unqueuedBuffers = null; if (!startedPlaying) { buffersToUnqueue = 0; Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToUnqueue); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine processed buffers from streamed source: " + Al.GetErrorString(alError)); } unqueuedBuffers = new uint[buffersToUnqueue + emptyBuffers.Count]; Al.SourceUnqueueBuffers(alSource, buffersToUnqueue, unqueuedBuffers); for (int i = 0; i < emptyBuffers.Count; i++) { unqueuedBuffers[buffersToUnqueue + i] = emptyBuffers[i]; } buffersToUnqueue += emptyBuffers.Count; emptyBuffers.Clear(); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to unqueue buffers from streamed source: " + Al.GetErrorString(alError)); } } else { startedPlaying = false; buffersToUnqueue = 4; unqueuedBuffers = new uint[4]; for (int i = 0; i < 4; i++) { unqueuedBuffers[i] = streamBuffers[i]; } } for (int i = 0; i < buffersToUnqueue; i++) { short[] buffer = streamShortBuffer; int readSamples = Sound.FillStreamBuffer(streamSeekPos, buffer); if (FilledByNetwork) { if (Sound is VoipSound voipSound) { voipSound.ApplyFilters(buffer, readSamples); } if (readSamples <= 0) { decayTimer++; if (decayTimer > 120) //TODO: replace magic number { reachedEndSample = true; } } else { decayTimer = 0; } } else if (Sound.StreamsReliably) { streamSeekPos += readSamples; if (readSamples < STREAM_BUFFER_SIZE) { if (looping) { streamSeekPos = 0; } else { reachedEndSample = true; } } } if (readSamples > 0) { Al.BufferData <short>(unqueuedBuffers[i], Sound.ALFormat, buffer, readSamples, Sound.SampleRate); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to assign data to stream buffer: " + Al.GetErrorString(alError) + ": " + unqueuedBuffers[i].ToString() + "/" + unqueuedBuffers.Length + ", readSamples: " + readSamples); } Al.SourceQueueBuffer(alSource, unqueuedBuffers[i]); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to queue buffer[" + i.ToString() + "] to stream: " + Al.GetErrorString(alError)); } } else if (readSamples < 0) { reachedEndSample = true; } else { emptyBuffers.Add((uint)unqueuedBuffers[i]); } } Al.GetSourcei(alSource, Al.SourceState, out state); if (state != Al.Playing) { Al.SourcePlay(alSource); } } } }
public SoundManager() { loadedSounds = new List <Sound>(); streamingThread = null; categoryModifiers = null; alcDevice = Alc.OpenDevice(null); if (alcDevice == null) { DebugConsole.ThrowError("Failed to open an ALC device! Disabling audio playback..."); Disabled = true; return; } int alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { //The audio device probably wasn't ready, this happens quite often //Just wait a while and try again Thread.Sleep(100); alcDevice = Alc.OpenDevice(null); alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error initializing ALC device: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; return; } } int[] alcContextAttrs = new int[] { }; alcContext = Alc.CreateContext(alcDevice, alcContextAttrs); if (alcContext == null) { DebugConsole.ThrowError("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return; } if (!Alc.MakeContextCurrent(alcContext)) { DebugConsole.ThrowError("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return; } alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error after assigning ALC context: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; return; } sourcePools = new SoundSourcePool[2]; sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT); playingChannels[(int)SourcePoolIndex.Default] = new SoundChannel[SOURCE_COUNT]; sourcePools[(int)SourcePoolIndex.Voice] = new SoundSourcePool(16); playingChannels[(int)SourcePoolIndex.Voice] = new SoundChannel[16]; Al.DistanceModel(Al.LinearDistanceClamped); int alError = Al.GetError(); if (alError != Al.NoError) { DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback..."); Disabled = true; return; } ListenerPosition = Vector3.Zero; ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f); ListenerUpVector = new Vector3(0.0f, -1.0f, 0.0f); CompressionDynamicRangeGain = 1.0f; }
public OggSound(SoundManager owner, string filename, bool stream) : base(owner, filename, stream, true) { if (!ToolBox.IsProperFilenameCase(filename)) { DebugConsole.ThrowError("Sound file \"" + filename + "\" has incorrect case!"); } reader = new VorbisReader(filename); ALFormat = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16; SampleRate = reader.SampleRate; if (!stream) { int bufferSize = (int)reader.TotalSamples * reader.Channels; float[] floatBuffer = new float[bufferSize]; short[] shortBuffer = new short[bufferSize]; int readSamples = reader.ReadSamples(floatBuffer, 0, bufferSize); CastBuffer(floatBuffer, shortBuffer, readSamples); Al.BufferData(ALBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } MuffleBuffer(floatBuffer, SampleRate, reader.Channels); CastBuffer(floatBuffer, shortBuffer, readSamples); Al.BufferData(ALMuffledBuffer, ALFormat, shortBuffer, readSamples * sizeof(short), SampleRate); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError)); } reader.Dispose(); } }
public SoundManager() { loadedSounds = new List <Sound>(); streamingThread = null; categoryModifiers = null; int alcError = Alc.NoError; string deviceName = Alc.GetString(IntPtr.Zero, Alc.DefaultDeviceSpecifier); DebugConsole.NewMessage($"Attempting to open ALC device \"{deviceName}\""); alcDevice = IntPtr.Zero; for (int i = 0; i < 3; i++) { alcDevice = Alc.OpenDevice(deviceName); if (alcDevice == IntPtr.Zero) { DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: device is null"); } else { alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: error code {Alc.GetErrorString(alcError)}"); bool closed = Alc.CloseDevice(alcDevice); if (!closed) { DebugConsole.NewMessage($"Failed to close ALC device"); } alcDevice = IntPtr.Zero; } } } if (alcDevice == IntPtr.Zero) { DebugConsole.ThrowError("ALC device creation failed too many times!"); Disabled = true; return; } int[] alcContextAttrs = new int[] { }; alcContext = Alc.CreateContext(alcDevice, alcContextAttrs); if (alcContext == null) { DebugConsole.ThrowError("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return; } if (!Alc.MakeContextCurrent(alcContext)) { DebugConsole.ThrowError("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return; } alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error after assigning ALC context: " + Alc.GetErrorString(alcError) + ". Disabling audio playback..."); Disabled = true; return; } sourcePools = new SoundSourcePool[2]; sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT); playingChannels[(int)SourcePoolIndex.Default] = new SoundChannel[SOURCE_COUNT]; sourcePools[(int)SourcePoolIndex.Voice] = new SoundSourcePool(16); playingChannels[(int)SourcePoolIndex.Voice] = new SoundChannel[16]; Al.DistanceModel(Al.LinearDistanceClamped); int alError = Al.GetError(); if (alError != Al.NoError) { DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback..."); Disabled = true; return; } ListenerPosition = Vector3.Zero; ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f); ListenerUpVector = new Vector3(0.0f, -1.0f, 0.0f); CompressionDynamicRangeGain = 1.0f; }
public bool InitializeAlcDevice(string deviceName) { ReleaseResources(true); DebugConsole.NewMessage($"Attempting to open ALC device \"{deviceName}\""); alcDevice = IntPtr.Zero; int alcError = Al.NoError; for (int i = 0; i < 3; i++) { alcDevice = Alc.OpenDevice(deviceName); if (alcDevice == IntPtr.Zero) { alcError = Alc.GetError(IntPtr.Zero); DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: device is null (error code {Alc.GetErrorString(alcError)})"); if (!string.IsNullOrEmpty(deviceName)) { deviceName = null; DebugConsole.NewMessage($"Switching to default device..."); } } else { alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: error code {Alc.GetErrorString(alcError)}"); bool closed = Alc.CloseDevice(alcDevice); if (!closed) { DebugConsole.NewMessage($"Failed to close ALC device"); } alcDevice = IntPtr.Zero; } else { break; } } } if (alcDevice == IntPtr.Zero) { DebugConsole.ThrowError("ALC device creation failed too many times!"); Disabled = true; return(false); } CanDetectDisconnect = Alc.IsExtensionPresent(alcDevice, "ALC_EXT_disconnect"); alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error determining if disconnect can be detected: " + alcError.ToString() + ". Disabling audio playback..."); Disabled = true; return(false); } Disconnected = false; int[] alcContextAttrs = new int[] { }; alcContext = Alc.CreateContext(alcDevice, alcContextAttrs); if (alcContext == null) { DebugConsole.ThrowError("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return(false); } if (!Alc.MakeContextCurrent(alcContext)) { DebugConsole.ThrowError("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback..."); Disabled = true; return(false); } alcError = Alc.GetError(alcDevice); if (alcError != Alc.NoError) { DebugConsole.ThrowError("Error after assigning ALC context: " + Alc.GetErrorString(alcError) + ". Disabling audio playback..."); Disabled = true; return(false); } Al.DistanceModel(Al.LinearDistanceClamped); int alError = Al.GetError(); if (alError != Al.NoError) { DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback..."); Disabled = true; return(false); } sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT); sourcePools[(int)SourcePoolIndex.Voice] = new SoundSourcePool(16); ReloadSounds(); Disabled = false; return(true); }
public void Dispose() { try { if (mutex != null) { Monitor.Enter(mutex); } if (ALSourceIndex >= 0) { Al.SourceStop(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to stop source: " + debugName + ", " + Al.GetErrorString(alError)); } if (IsStream) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); Al.SourceStop(alSource); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to stop streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } int buffersToRequeue = 0; buffersToRequeue = 0; Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToRequeue); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine processed buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } Al.SourceUnqueueBuffers(alSource, buffersToRequeue, unqueuedBuffers); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to unqueue buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } Al.Sourcei(alSource, Al.Buffer, 0); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to reset buffer for streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } for (int i = 0; i < 4; i++) { Al.DeleteBuffer(streamBuffers[i]); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to delete streamBuffers[" + i.ToString() + "] (" + streamBuffers[i].ToString() + "): " + debugName + ", " + Al.GetErrorString(alError)); } } reachedEndSample = true; } else { Al.Sourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to unbind buffer to non-streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } } ALSourceIndex = -1; debugName += " [DISPOSED]"; } } finally { if (mutex != null) { Monitor.Exit(mutex); } } }
public bool RequestAlBuffers() { if (AlBuffer != 0) { return(false); } int alError; lock (bufferPool) { while (bufferPool.Count < 2 && BuffersGenerated < MaxBuffers) { Al.GenBuffer(out uint newBuffer); alError = Al.GetError(); if (alError != Al.NoError) { DebugConsole.AddWarning($"Error when generating sound buffer: {Al.GetErrorString(alError)}. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated."); BuffersGenerated = MaxBuffers; } else if (!Al.IsBuffer(newBuffer)) { DebugConsole.AddWarning($"Error when generating sound buffer: result is not a valid buffer. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated."); BuffersGenerated = MaxBuffers; } else { bufferPool.Add(newBuffer); BuffersGenerated++; if (BuffersGenerated >= MaxBuffers) { DebugConsole.AddWarning($"{BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated."); } } } if (bufferPool.Count >= 2) { AlBuffer = bufferPool.First(); bufferPool.Remove(AlBuffer); AlMuffledBuffer = bufferPool.First(); bufferPool.Remove(AlMuffledBuffer); return(true); } } //can't generate any more OpenAL buffers! we'll have to steal a buffer from someone... foreach (var otherSound in sound.Owner.LoadedSounds) { if (otherSound == sound) { continue; } if (otherSound.IsPlaying()) { continue; } if (otherSound.Buffers == null) { continue; } if (otherSound.Buffers.AlBuffer == 0) { continue; } // Dispose all channels that are holding // a reference to these buffers, otherwise // an INVALID_OPERATION error will be thrown // when attempting to set the buffer data later. // Having the sources not play is not enough, // as OpenAL assumes that you may want to call // alSourcePlay without reassigning the buffer. otherSound.Owner.KillChannels(otherSound); AlBuffer = otherSound.Buffers.AlBuffer; AlMuffledBuffer = otherSound.Buffers.AlMuffledBuffer; otherSound.Buffers.AlBuffer = 0; otherSound.Buffers.AlMuffledBuffer = 0; // For performance reasons, sift the current sound to // the end of the loadedSounds list, that way it'll // be less likely to have its buffers stolen, which // means less reuploads for frequently played sounds. sound.Owner.MoveSoundToPosition(sound, sound.Owner.LoadedSoundCount - 1); if (!Al.IsBuffer(AlBuffer)) { throw new Exception(sound.Filename + " has an invalid buffer!"); } if (!Al.IsBuffer(AlMuffledBuffer)) { throw new Exception(sound.Filename + " has an invalid muffled buffer!"); } return(true); } return(false); }
public virtual void Dispose() { if (disposed) { return; } Owner.KillChannels(this); if (alBuffer != 0) { if (!Al.IsBuffer(alBuffer)) { throw new Exception("Buffer to delete is invalid!"); } Al.DeleteBuffer(alBuffer); alBuffer = 0; int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } } if (alMuffledBuffer != 0) { if (!Al.IsBuffer(alMuffledBuffer)) { throw new Exception("Buffer to delete is invalid!"); } Al.DeleteBuffer(alMuffledBuffer); alMuffledBuffer = 0; int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError)); } } Owner.RemoveSound(this); disposed = true; }