2f107db...5202af9

This commit is contained in:
Joonas Rikkonen
2019-03-18 21:42:26 +02:00
parent 58c92888b7
commit 044fd3344b
395 changed files with 27417 additions and 19754 deletions
@@ -1,12 +1,86 @@
using System;
using OpenTK.Audio.OpenAL;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
namespace Barotrauma.Sounds
{
public class SoundSourcePool : IDisposable
{
public uint[] ALSources
{
get;
private set;
}
public SoundSourcePool(int sourceCount = SoundManager.SOURCE_COUNT)
{
ALError alError = ALError.NoError;
ALSources = new uint[sourceCount];
for (int i = 0; i < sourceCount; i++)
{
AL.GenSource(out ALSources[i]);
alError = AL.GetError();
if (alError != ALError.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 != ALError.NoError)
{
throw new Exception("Error stopping newly generated alSource[" + i.ToString() + "]: " + AL.GetErrorString(alError));
}
AL.Source(ALSources[i], ALSourcef.MinGain, 0.0f);
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Error setting min gain: " + AL.GetErrorString(alError));
}
AL.Source(ALSources[i], ALSourcef.MaxGain, 1.0f);
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Error setting max gain: " + AL.GetErrorString(alError));
}
AL.Source(ALSources[i], ALSourcef.RolloffFactor, 1.0f);
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Error setting rolloff factor: " + AL.GetErrorString(alError));
}
}
}
public void Dispose()
{
for (int i = 0; i < ALSources.Length; i++)
{
AL.DeleteSource(ref ALSources[i]);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to delete ALSources[" + i.ToString() + "]: " + AL.GetErrorString(alError));
}
}
ALSources = null;
}
}
public class SoundChannel : IDisposable
{
private const int STREAM_BUFFER_SIZE = 65536;
private short[] streamShortBuffer;
private Vector3? position;
public Vector3? Position
@@ -20,7 +94,7 @@ namespace Barotrauma.Sounds
if (position != null)
{
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
AL.Source(alSource, ALSourceb.SourceRelative, false);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
@@ -37,7 +111,7 @@ namespace Barotrauma.Sounds
}
else
{
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
AL.Source(alSource, ALSourceb.SourceRelative, true);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
@@ -65,7 +139,7 @@ namespace Barotrauma.Sounds
if (ALSourceIndex < 0) return;
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
AL.Source(alSource, ALSourcef.ReferenceDistance, near);
ALError alError = AL.GetError();
@@ -86,7 +160,7 @@ namespace Barotrauma.Sounds
if (ALSourceIndex < 0) return;
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
AL.Source(alSource, ALSourcef.MaxDistance, far);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
@@ -106,7 +180,7 @@ namespace Barotrauma.Sounds
if (ALSourceIndex < 0) return;
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
float effectiveGain = gain;
if (category != null) effectiveGain *= Sound.Owner.GetCategoryGainMultiplier(category);
@@ -132,7 +206,7 @@ namespace Barotrauma.Sounds
if (!IsStream)
{
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
AL.Source(alSource, ALSourceb.Looping, looping);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
@@ -143,6 +217,14 @@ namespace Barotrauma.Sounds
}
}
public bool FilledByNetwork
{
get;
private set;
}
private int decayTimer;
private bool muffled;
public bool Muffled
{
@@ -159,7 +241,7 @@ namespace Barotrauma.Sounds
if (!IsStream)
{
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
int playbackPos; AL.GetSource(alSource, ALGetSourcei.SampleOffset, out playbackPos);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
@@ -221,7 +303,7 @@ namespace Barotrauma.Sounds
{
get;
private set;
}
} = -1;
public bool IsStream
{
@@ -231,7 +313,8 @@ namespace Barotrauma.Sounds
private int streamSeekPos;
private bool startedPlaying;
private bool reachedEndSample;
private uint[] streamBuffers;
private readonly uint[] streamBuffers;
private readonly List<uint> emptyBuffers;
private object mutex;
@@ -241,11 +324,11 @@ namespace Barotrauma.Sounds
{
if (ALSourceIndex < 0) return false;
if (IsStream && !reachedEndSample) return true;
bool playing = AL.GetSourceState(Sound.Owner.GetSourceFromIndex(ALSourceIndex)) == ALSourceState.Playing;
bool playing = AL.GetSourceState(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)) == ALSourceState.Playing;
ALError alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to determine playing state from source: "+AL.GetErrorString(alError));
throw new Exception("Failed to determine playing state from source: " + AL.GetErrorString(alError));
}
return playing;
}
@@ -256,87 +339,98 @@ namespace Barotrauma.Sounds
Sound = sound;
IsStream = sound.Stream;
FilledByNetwork = sound is VoipSound;
decayTimer = 0;
streamSeekPos = 0; reachedEndSample = false;
startedPlaying = true;
mutex = new object();
ALSourceIndex = sound.Owner.AssignFreeSourceToChannel(this);
if (ALSourceIndex>=0)
lock (mutex)
{
if (!IsStream)
if (sound.Owner.CountPlayingInstances(sound) < sound.MaxSimultaneousInstances)
{
AL.BindBufferToSource(sound.Owner.GetSourceFromIndex(ALSourceIndex), 0);
ALError alError = AL.GetError();
if (alError != ALError.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.BindBufferToSource(sound.Owner.GetSourceFromIndex(ALSourceIndex), alBuffer);
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to bind buffer to source (" +ALSourceIndex.ToString()+":"+sound.Owner.GetSourceFromIndex(ALSourceIndex)+"," +sound.ALBuffer.ToString()+"): " + AL.GetErrorString(alError));
}
AL.SourcePlay(sound.Owner.GetSourceFromIndex(ALSourceIndex));
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to play source: " + AL.GetErrorString(alError));
}
ALSourceIndex = sound.Owner.AssignFreeSourceToChannel(this);
}
else
if (ALSourceIndex >= 0)
{
AL.BindBufferToSource(sound.Owner.GetSourceFromIndex(ALSourceIndex), (uint)sound.ALBuffer);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
if (!IsStream)
{
throw new Exception("Failed to reset source buffer: " + AL.GetErrorString(alError));
}
AL.Source(sound.Owner.GetSourceFromIndex(ALSourceIndex), ALSourceb.Looping, false);
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to set stream looping state: " + AL.GetErrorString(alError));
}
AL.BindBufferToSource(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), 0);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to reset source buffer: " + AL.GetErrorString(alError));
}
streamBuffers = new uint[4];
for (int i=0;i<4;i++)
{
AL.GenBuffer(out streamBuffers[i]);
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.BindBufferToSource(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), alBuffer);
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to generate stream buffers: " + AL.GetErrorString(alError));
throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + sound.ALBuffer.ToString() + "): " + AL.GetErrorString(alError));
}
if (!AL.IsBuffer(streamBuffers[i]))
AL.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex));
alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Generated streamBuffer[" + i.ToString() + "] is invalid!");
throw new Exception("Failed to play source: " + AL.GetErrorString(alError));
}
}
else
{
AL.BindBufferToSource(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), (uint)sound.ALBuffer);
ALError alError = AL.GetError();
if (alError != ALError.NoError)
{
throw new Exception("Failed to reset source buffer: " + AL.GetErrorString(alError));
}
Sound.Owner.InitStreamThread();
AL.Source(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), ALSourceb.Looping, false);
alError = AL.GetError();
if (alError != ALError.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 != ALError.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;
this.Position = position;
this.Gain = gain;
this.Looping = false;
this.Near = near;
this.Far = far;
this.Category = category;
}
}
public void Dispose()
@@ -345,7 +439,7 @@ namespace Barotrauma.Sounds
{
if (ALSourceIndex >= 0)
{
AL.SourceStop(Sound.Owner.GetSourceFromIndex(ALSourceIndex));
AL.SourceStop(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex));
ALError alError = AL.GetError();
if (alError != ALError.NoError)
{
@@ -354,7 +448,7 @@ namespace Barotrauma.Sounds
if (IsStream)
{
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
AL.SourceStop(alSource);
alError = AL.GetError();
@@ -403,7 +497,7 @@ namespace Barotrauma.Sounds
}
else
{
AL.BindBufferToSource(Sound.Owner.GetSourceFromIndex(ALSourceIndex), 0);
AL.BindBufferToSource(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), 0);
alError = AL.GetError();
if (alError != ALError.NoError)
{
@@ -424,7 +518,7 @@ namespace Barotrauma.Sounds
{
if (!reachedEndSample)
{
uint alSource = Sound.Owner.GetSourceFromIndex(ALSourceIndex);
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
bool playing = AL.GetSourceState(alSource) == ALSourceState.Playing;
ALError alError = AL.GetError();
@@ -432,7 +526,7 @@ namespace Barotrauma.Sounds
{
throw new Exception("Failed to determine playing state from streamed source: " + AL.GetErrorString(alError));
}
int buffersToUnqueue = 0;
int[] unqueuedBuffers = null;
if (!startedPlaying)
@@ -445,8 +539,14 @@ namespace Barotrauma.Sounds
throw new Exception("Failed to determine processed buffers from streamed source: " + AL.GetErrorString(alError));
}
unqueuedBuffers = new int[buffersToUnqueue];
unqueuedBuffers = new int[buffersToUnqueue+emptyBuffers.Count];
AL.SourceUnqueueBuffers((int)alSource, buffersToUnqueue, unqueuedBuffers);
for (int i = 0; i < emptyBuffers.Count; i++)
{
unqueuedBuffers[buffersToUnqueue + i] = (int)emptyBuffers[i];
}
buffersToUnqueue += emptyBuffers.Count;
emptyBuffers.Clear();
alError = AL.GetError();
if (alError != ALError.NoError)
{
@@ -463,23 +563,47 @@ namespace Barotrauma.Sounds
unqueuedBuffers[i] = (int)streamBuffers[i];
}
}
for (int i = 0; i < buffersToUnqueue; i++)
{
short[] buffer = new short[STREAM_BUFFER_SIZE];
short[] buffer = streamShortBuffer;
int readSamples = Sound.FillStreamBuffer(streamSeekPos, buffer);
streamSeekPos += readSamples;
if (readSamples < STREAM_BUFFER_SIZE)
if (FilledByNetwork)
{
if (looping)
if (Sound is VoipSound voipSound)
{
streamSeekPos = 0;
voipSound.ApplyFilters(buffer, readSamples);
}
if (readSamples <= 0)
{
decayTimer++;
if (decayTimer > 120) //TODO: replace magic number
{
reachedEndSample = true;
}
}
else
{
reachedEndSample = true;
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);
@@ -498,6 +622,14 @@ namespace Barotrauma.Sounds
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]);
}
}
if (AL.GetSourceState(alSource) != ALSourceState.Playing)