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; } }
internal unsafe AudioClip(IResource resource) { Al.GenBuffer(out Buffer); using var reader = new VorbisReader(resource.OpenStream()); var channels = reader.Channels; var sampleRate = reader.SampleRate; var seconds = reader.TotalTime.TotalSeconds; var samples = (int)Math.Ceiling(seconds * sampleRate * channels); var floats = new Span <float>(new float[samples]); if (reader.ReadSamples(floats) <= 0) { throw new Exception("Failed to read OGG stream."); } var shorts = new Span <short>(new short[samples]); // 16 bit for (var i = 0; i < floats.Length; i++) shorts[i] = (short)(short.MaxValue * floats[i]); fixed(void *p = &shorts.GetPinnableReference()) { Al.BufferData(Buffer, channels == 2 ? Al.FormatStereo16 : Al.FormatMono16, p, shorts.Length * sizeof(short), sampleRate); } }
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(); } }
protected override unsafe void CreateInternal(byte[] soundData) { // Load by base SoundFile. base.CreateInternal(soundData); // Upload to the sound manager. ALThread.ExecuteALThread(() => { Al.GenBuffer(out uint buffer); ALBuffer = buffer; fixed(byte *dataBuffer = &soundData[0]) { Al.BufferData(ALBuffer, GetSoundFormat(Channels, BitsPerSample), dataBuffer, soundData.Length, SampleRate); } }).Wait(); }
private int Buffer(short[] data, uint id) { var numSamples = GetDataChunk(data); if (numSamples < 0) { return(numSamples); } unsafe { fixed(short *pData = data) { Al.BufferData(id, Al.FormatMono16, pData, numSamples * 2, _rate); } } return(numSamples); }
/// <summary> /// For some reason you can't use unsafe code in coroutines :) /// </summary> private void UploadDataToBuffer(byte[] data, uint buffer, int byteLengthPerSampleChannel) { Al.BufferData(buffer, _openALFormatId, data, byteLengthPerSampleChannel, _openALAudioFormat.SampleRate); CheckALError(); }
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 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 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); } } } }