Unstable 1.1.14.0
This commit is contained in:
@@ -2,21 +2,89 @@
|
||||
using OpenAL;
|
||||
using NVorbis;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Sounds
|
||||
{
|
||||
class OggSound : Sound
|
||||
sealed class OggSound : Sound
|
||||
{
|
||||
private VorbisReader reader;
|
||||
private VorbisReader streamReader;
|
||||
|
||||
//key = sample rate, value = filter
|
||||
private static readonly Dictionary<int, BiQuad> muffleFilters = new Dictionary<int, BiQuad>();
|
||||
|
||||
private static List<float> playbackAmplitude;
|
||||
private List<float> playbackAmplitude;
|
||||
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) { }
|
||||
private short[] sampleBuffer = Array.Empty<short>();
|
||||
private short[] muffleBuffer = Array.Empty<short>();
|
||||
public OggSound(SoundManager owner, string filename, bool stream, XElement xElement) : base(owner, filename,
|
||||
stream, true, xElement)
|
||||
{
|
||||
var reader = new VorbisReader(Filename);
|
||||
|
||||
ALFormat = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16;
|
||||
SampleRate = reader.SampleRate;
|
||||
|
||||
if (stream)
|
||||
{
|
||||
streamReader = reader;
|
||||
return;
|
||||
}
|
||||
|
||||
TaskPool.Add(
|
||||
$"LoadSamples {filename}",
|
||||
LoadSamples(reader),
|
||||
t =>
|
||||
{
|
||||
reader.Dispose();
|
||||
if (!t.TryGetResult(out TaskResult result))
|
||||
{
|
||||
return;
|
||||
}
|
||||
sampleBuffer = result.SampleBuffer;
|
||||
muffleBuffer = result.MuffleBuffer;
|
||||
playbackAmplitude = result.PlaybackAmplitude;
|
||||
Owner.KillChannels(this); // prevents INVALID_OPERATION error
|
||||
buffers?.Dispose(); buffers = null;
|
||||
});
|
||||
}
|
||||
|
||||
private readonly record struct TaskResult(
|
||||
short[] SampleBuffer,
|
||||
short[] MuffleBuffer,
|
||||
List<float> PlaybackAmplitude);
|
||||
|
||||
private static async Task<TaskResult> LoadSamples(VorbisReader reader)
|
||||
{
|
||||
reader.DecodedPosition = 0;
|
||||
|
||||
int bufferSize = (int)reader.TotalSamples * reader.Channels;
|
||||
|
||||
float[] floatBuffer = new float[bufferSize];
|
||||
var sampleBuffer = new short[bufferSize];
|
||||
var muffledBuffer = new short[bufferSize];
|
||||
|
||||
int readSamples = await Task.Run(() => reader.ReadSamples(floatBuffer, 0, bufferSize));
|
||||
|
||||
var 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, sampleBuffer, readSamples);
|
||||
|
||||
MuffleBuffer(floatBuffer, reader.SampleRate);
|
||||
|
||||
CastBuffer(floatBuffer, muffledBuffer, readSamples);
|
||||
|
||||
return new TaskResult(sampleBuffer, muffledBuffer, playbackAmplitude);
|
||||
}
|
||||
|
||||
public override float GetAmplitudeAtPlaybackPos(int playbackPos)
|
||||
{
|
||||
@@ -27,101 +95,65 @@ namespace Barotrauma.Sounds
|
||||
return playbackAmplitude[index];
|
||||
}
|
||||
|
||||
private float[] streamFloatBuffer = null;
|
||||
public override int FillStreamBuffer(int samplePos, short[] buffer)
|
||||
{
|
||||
if (!Stream) { throw new Exception("Called FillStreamBuffer on a non-streamed sound!"); }
|
||||
if (reader == null) { throw new Exception("Called FillStreamBuffer when the reader is null!"); }
|
||||
if (streamReader == null) { throw new Exception("Called FillStreamBuffer when the reader is null!"); }
|
||||
|
||||
if (samplePos >= reader.TotalSamples * reader.Channels * 2) return 0;
|
||||
if (samplePos >= streamReader.TotalSamples * streamReader.Channels * 2) return 0;
|
||||
|
||||
samplePos /= reader.Channels * 2;
|
||||
reader.DecodedPosition = samplePos;
|
||||
samplePos /= streamReader.Channels * 2;
|
||||
streamReader.DecodedPosition = samplePos;
|
||||
|
||||
float[] floatBuffer = new float[buffer.Length];
|
||||
int readSamples = reader.ReadSamples(floatBuffer, 0, buffer.Length / 2);
|
||||
if (streamFloatBuffer is null || streamFloatBuffer.Length < buffer.Length)
|
||||
{
|
||||
streamFloatBuffer = new float[buffer.Length];
|
||||
}
|
||||
int readSamples = streamReader.ReadSamples(streamFloatBuffer, 0, buffer.Length);
|
||||
//MuffleBuffer(floatBuffer, reader.Channels);
|
||||
CastBuffer(floatBuffer, buffer, readSamples);
|
||||
CastBuffer(streamFloatBuffer, buffer, readSamples);
|
||||
|
||||
return readSamples;
|
||||
}
|
||||
|
||||
static void MuffleBuffer(float[] buffer, int sampleRate, int channelCount)
|
||||
static void MuffleBuffer(float[] buffer, int sampleRate)
|
||||
{
|
||||
if (!muffleFilters.TryGetValue(sampleRate, out BiQuad filter))
|
||||
{
|
||||
filter = new LowpassFilter(sampleRate, 1600);
|
||||
muffleFilters.Add(sampleRate, filter);
|
||||
}
|
||||
var filter = new LowpassFilter(sampleRate, 1600);
|
||||
filter.Process(buffer);
|
||||
}
|
||||
|
||||
public override void InitializeALBuffers()
|
||||
public override void InitializeAlBuffers()
|
||||
{
|
||||
base.InitializeALBuffers();
|
||||
|
||||
reader ??= new VorbisReader(Filename);
|
||||
|
||||
ALFormat = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16;
|
||||
SampleRate = reader.SampleRate;
|
||||
|
||||
if (Buffers != null && SoundBuffers.BuffersGenerated < SoundBuffers.MaxBuffers)
|
||||
if (buffers != null && SoundBuffers.BuffersGenerated < SoundBuffers.MaxBuffers)
|
||||
{
|
||||
Buffers.RequestAlBuffers(); FillBuffers();
|
||||
FillAlBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillBuffers()
|
||||
public override void FillAlBuffers()
|
||||
{
|
||||
if (!Stream)
|
||||
if (Stream) { return; }
|
||||
if (sampleBuffer.Length == 0 || muffleBuffer.Length == 0) { return; }
|
||||
buffers ??= new SoundBuffers(this);
|
||||
if (!buffers.RequestAlBuffers()) { return; }
|
||||
|
||||
Al.BufferData(buffers.AlBuffer, ALFormat, sampleBuffer,
|
||||
sampleBuffer.Length * sizeof(short), SampleRate);
|
||||
|
||||
int alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
reader ??= new VorbisReader(Filename);
|
||||
throw new Exception("Failed to set regular buffer data for non-streamed audio! " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
reader.DecodedPosition = 0;
|
||||
Al.BufferData(buffers.AlMuffledBuffer, ALFormat, muffleBuffer,
|
||||
muffleBuffer.Length * sizeof(short), SampleRate);
|
||||
|
||||
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(Buffers.AlBuffer, ALFormat, shortBuffer,
|
||||
readSamples * sizeof(short), SampleRate);
|
||||
|
||||
int alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to set regular buffer data for non-streamed audio! " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
MuffleBuffer(floatBuffer, SampleRate, reader.Channels);
|
||||
|
||||
CastBuffer(floatBuffer, shortBuffer, readSamples);
|
||||
|
||||
Al.BufferData(Buffers.AlMuffledBuffer, ALFormat, shortBuffer,
|
||||
readSamples * sizeof(short), SampleRate);
|
||||
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to set muffled buffer data for non-streamed audio! " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
reader.Dispose(); reader = null;
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to set muffled buffer data for non-streamed audio! " + Al.GetErrorString(alError));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +161,7 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
if (Stream)
|
||||
{
|
||||
reader?.Dispose();
|
||||
streamReader?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose();
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
|
||||
private SoundBuffers buffers;
|
||||
protected SoundBuffers buffers;
|
||||
public SoundBuffers Buffers
|
||||
{
|
||||
get { return !Stream ? buffers : null; }
|
||||
@@ -72,8 +72,6 @@ namespace Barotrauma.Sounds
|
||||
BaseGain = 1.0f;
|
||||
BaseNear = 100.0f;
|
||||
BaseFar = 200.0f;
|
||||
|
||||
InitializeALBuffers();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@@ -141,21 +139,11 @@ namespace Barotrauma.Sounds
|
||||
|
||||
public abstract float GetAmplitudeAtPlaybackPos(int playbackPos);
|
||||
|
||||
public virtual void InitializeALBuffers()
|
||||
{
|
||||
if (!Stream)
|
||||
{
|
||||
buffers = new SoundBuffers(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffers = null;
|
||||
}
|
||||
}
|
||||
public virtual void InitializeAlBuffers() { }
|
||||
|
||||
public virtual void FillBuffers() { }
|
||||
public virtual void FillAlBuffers() { }
|
||||
|
||||
public virtual void DeleteALBuffers()
|
||||
public virtual void DeleteAlBuffers()
|
||||
{
|
||||
Owner.KillChannels(this);
|
||||
buffers?.Dispose();
|
||||
@@ -165,7 +153,7 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
if (disposed) { return; }
|
||||
|
||||
DeleteALBuffers();
|
||||
DeleteAlBuffers();
|
||||
|
||||
Owner.RemoveSound(this);
|
||||
disposed = true;
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Text;
|
||||
|
||||
namespace Barotrauma.Sounds
|
||||
{
|
||||
class SoundBuffers : IDisposable
|
||||
sealed class SoundBuffers : IDisposable
|
||||
{
|
||||
private static readonly HashSet<uint> bufferPool = new HashSet<uint>();
|
||||
#if OSX
|
||||
|
||||
@@ -312,54 +312,52 @@ namespace Barotrauma.Sounds
|
||||
|
||||
if (!IsPlaying) { return; }
|
||||
|
||||
if (!IsStream)
|
||||
if (IsStream) { return; }
|
||||
|
||||
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
|
||||
Al.GetSourcei(alSource, Al.SampleOffset, out int playbackPos);
|
||||
int alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
|
||||
Al.GetSourcei(alSource, Al.SampleOffset, out int playbackPos);
|
||||
int alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to get source's playback position: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
DebugConsole.ThrowError("Failed to get source's playback position: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
|
||||
Al.SourceStop(alSource);
|
||||
Al.SourceStop(alSource);
|
||||
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to stop source: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to stop source: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Sound.Buffers.RequestAlBuffers())
|
||||
{
|
||||
Sound.FillBuffers();
|
||||
}
|
||||
Al.Sourcei(alSource, Al.Buffer, muffled ? (int)Sound.Buffers.AlMuffledBuffer : (int)Sound.Buffers.AlBuffer);
|
||||
Sound.FillAlBuffers();
|
||||
if (Sound.Buffers is not { AlBuffer: not 0, AlMuffledBuffer: not 0 }) { return; }
|
||||
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to bind buffer to source: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
Al.Sourcei(alSource, Al.Buffer, muffled ? (int)Sound.Buffers.AlMuffledBuffer : (int)Sound.Buffers.AlBuffer);
|
||||
|
||||
Al.SourcePlay(alSource);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to replay source: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to bind buffer to source: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
|
||||
Al.Sourcei(alSource, Al.SampleOffset, playbackPos);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to reset playback position: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
Al.SourcePlay(alSource);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to replay source: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
|
||||
Al.Sourcei(alSource, Al.SampleOffset, playbackPos);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to reset playback position: " + debugName + ", " + Al.GetErrorString(alError), appendStackTrace: true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -509,10 +507,8 @@ namespace Barotrauma.Sounds
|
||||
throw new Exception("Failed to reset source buffer: " + debugName + ", " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
if (Sound.Buffers.RequestAlBuffers())
|
||||
{
|
||||
Sound.FillBuffers();
|
||||
}
|
||||
Sound.FillAlBuffers();
|
||||
if (Sound.Buffers is not { AlBuffer: not 0, AlMuffledBuffer: not 0 }) { return; }
|
||||
|
||||
uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffled ? Sound.Buffers.AlMuffledBuffer : Sound.Buffers.AlBuffer;
|
||||
Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer);
|
||||
|
||||
@@ -64,14 +64,15 @@ namespace Barotrauma.Sounds
|
||||
/// The b2 value.
|
||||
/// </summary>
|
||||
protected double B2;
|
||||
|
||||
/// <summary>
|
||||
/// The q value.
|
||||
/// </summary>
|
||||
private double _q;
|
||||
protected readonly double _q;
|
||||
/// <summary>
|
||||
/// The gain value in dB.
|
||||
/// </summary>
|
||||
private double _gainDB;
|
||||
protected readonly double _gainDB;
|
||||
/// <summary>
|
||||
/// The z1 value.
|
||||
/// </summary>
|
||||
@@ -81,77 +82,15 @@ namespace Barotrauma.Sounds
|
||||
/// </summary>
|
||||
protected double Z2;
|
||||
|
||||
private double _frequency;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the frequency.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">value;The samplerate has to be bigger than 2 * frequency.</exception>
|
||||
public double Frequency
|
||||
{
|
||||
get { return _frequency; }
|
||||
set
|
||||
{
|
||||
if (SampleRate < value * 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value", "The samplerate has to be bigger than 2 * frequency.");
|
||||
}
|
||||
_frequency = value;
|
||||
CalculateBiQuadCoefficients();
|
||||
}
|
||||
}
|
||||
protected readonly double _frequency;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate.
|
||||
/// </summary>
|
||||
public int SampleRate { get; private set; }
|
||||
protected readonly int _sampleRate;
|
||||
|
||||
/// <summary>
|
||||
/// The q value.
|
||||
/// </summary>
|
||||
public double Q
|
||||
{
|
||||
get { return _q; }
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
_q = value;
|
||||
CalculateBiQuadCoefficients();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the gain value in dB.
|
||||
/// </summary>
|
||||
public double GainDB
|
||||
{
|
||||
get { return _gainDB; }
|
||||
set
|
||||
{
|
||||
_gainDB = value;
|
||||
CalculateBiQuadCoefficients();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BiQuad"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sampleRate">The sample rate.</param>
|
||||
/// <param name="frequency">The frequency.</param>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// sampleRate
|
||||
/// or
|
||||
/// frequency
|
||||
/// or
|
||||
/// q
|
||||
/// </exception>
|
||||
protected BiQuad(int sampleRate, double frequency)
|
||||
: this(sampleRate, frequency, 1.0 / Math.Sqrt(2))
|
||||
{
|
||||
}
|
||||
protected static readonly double DefaultQ = 1.0 / Math.Sqrt(2);
|
||||
protected const double DefaultGainDb = 6.0;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BiQuad"/> class.
|
||||
@@ -166,18 +105,29 @@ namespace Barotrauma.Sounds
|
||||
/// or
|
||||
/// q
|
||||
/// </exception>
|
||||
protected BiQuad(int sampleRate, double frequency, double q)
|
||||
protected BiQuad(int sampleRate, double frequency, double q, double gainDb)
|
||||
{
|
||||
if (sampleRate <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sampleRate");
|
||||
}
|
||||
if (frequency <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("frequency");
|
||||
}
|
||||
if (q <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("q");
|
||||
SampleRate = sampleRate;
|
||||
Frequency = frequency;
|
||||
Q = q;
|
||||
GainDB = 6;
|
||||
}
|
||||
if (sampleRate < frequency * 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("sampleRate", "The sample rate has to be greater than or equal to 2 * frequency.");
|
||||
}
|
||||
_sampleRate = sampleRate;
|
||||
_frequency = frequency;
|
||||
_q = q;
|
||||
_gainDB = gainDb;
|
||||
CalculateBiQuadCoefficients();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -215,7 +165,7 @@ namespace Barotrauma.Sounds
|
||||
/// <summary>
|
||||
/// Used to apply a lowpass-filter to a signal.
|
||||
/// </summary>
|
||||
public class LowpassFilter : BiQuad
|
||||
public sealed class LowpassFilter : BiQuad
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LowpassFilter"/> class.
|
||||
@@ -223,7 +173,7 @@ namespace Barotrauma.Sounds
|
||||
/// <param name="sampleRate">The sample rate.</param>
|
||||
/// <param name="frequency">The filter's corner frequency.</param>
|
||||
public LowpassFilter(int sampleRate, double frequency)
|
||||
: base(sampleRate, frequency)
|
||||
: base(sampleRate, frequency, DefaultQ, DefaultGainDb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -232,20 +182,20 @@ namespace Barotrauma.Sounds
|
||||
/// </summary>
|
||||
protected override void CalculateBiQuadCoefficients()
|
||||
{
|
||||
double k = Math.Tan(Math.PI * Frequency / SampleRate);
|
||||
var norm = 1 / (1 + k / Q + k * k);
|
||||
double k = Math.Tan(Math.PI * _frequency / _sampleRate);
|
||||
var norm = 1 / (1 + k / _q + k * k);
|
||||
A0 = k * k * norm;
|
||||
A1 = 2 * A0;
|
||||
A2 = A0;
|
||||
B1 = 2 * (k * k - 1) * norm;
|
||||
B2 = (1 - k / Q + k * k) * norm;
|
||||
B2 = (1 - k / _q + k * k) * norm;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to apply a highpass-filter to a signal.
|
||||
/// </summary>
|
||||
public class HighpassFilter : BiQuad
|
||||
public sealed class HighpassFilter : BiQuad
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HighpassFilter"/> class.
|
||||
@@ -253,7 +203,7 @@ namespace Barotrauma.Sounds
|
||||
/// <param name="sampleRate">The sample rate.</param>
|
||||
/// <param name="frequency">The filter's corner frequency.</param>
|
||||
public HighpassFilter(int sampleRate, double frequency)
|
||||
: base(sampleRate, frequency)
|
||||
: base(sampleRate, frequency, DefaultQ, DefaultGainDb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -262,20 +212,20 @@ namespace Barotrauma.Sounds
|
||||
/// </summary>
|
||||
protected override void CalculateBiQuadCoefficients()
|
||||
{
|
||||
double k = Math.Tan(Math.PI * Frequency / SampleRate);
|
||||
var norm = 1 / (1 + k / Q + k * k);
|
||||
double k = Math.Tan(Math.PI * _frequency / _sampleRate);
|
||||
var norm = 1 / (1 + k / _q + k * k);
|
||||
A0 = 1 * norm;
|
||||
A1 = -2 * A0;
|
||||
A2 = A0;
|
||||
B1 = 2 * (k * k - 1) * norm;
|
||||
B2 = (1 - k / Q + k * k) * norm;
|
||||
B2 = (1 - k / _q + k * k) * norm;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to apply a bandpass-filter to a signal.
|
||||
/// </summary>
|
||||
public class BandpassFilter : BiQuad
|
||||
public sealed class BandpassFilter : BiQuad
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BandpassFilter"/> class.
|
||||
@@ -283,7 +233,7 @@ namespace Barotrauma.Sounds
|
||||
/// <param name="sampleRate">The sample rate.</param>
|
||||
/// <param name="frequency">The filter's corner frequency.</param>
|
||||
public BandpassFilter(int sampleRate, double frequency)
|
||||
: base(sampleRate, frequency)
|
||||
: base(sampleRate, frequency, DefaultQ, DefaultGainDb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -292,20 +242,20 @@ namespace Barotrauma.Sounds
|
||||
/// </summary>
|
||||
protected override void CalculateBiQuadCoefficients()
|
||||
{
|
||||
double k = Math.Tan(Math.PI * Frequency / SampleRate);
|
||||
double norm = 1 / (1 + k / Q + k * k);
|
||||
A0 = k / Q * norm;
|
||||
double k = Math.Tan(Math.PI * _frequency / _sampleRate);
|
||||
double norm = 1 / (1 + k / _q + k * k);
|
||||
A0 = k / _q * norm;
|
||||
A1 = 0;
|
||||
A2 = -A0;
|
||||
B1 = 2 * (k * k - 1) * norm;
|
||||
B2 = (1 - k / Q + k * k) * norm;
|
||||
B2 = (1 - k / _q + k * k) * norm;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to apply a notch-filter to a signal.
|
||||
/// </summary>
|
||||
public class NotchFilter : BiQuad
|
||||
public sealed class NotchFilter : BiQuad
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NotchFilter"/> class.
|
||||
@@ -313,7 +263,7 @@ namespace Barotrauma.Sounds
|
||||
/// <param name="sampleRate">The sample rate.</param>
|
||||
/// <param name="frequency">The filter's corner frequency.</param>
|
||||
public NotchFilter(int sampleRate, double frequency)
|
||||
: base(sampleRate, frequency)
|
||||
: base(sampleRate, frequency, DefaultQ, DefaultGainDb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -322,20 +272,20 @@ namespace Barotrauma.Sounds
|
||||
/// </summary>
|
||||
protected override void CalculateBiQuadCoefficients()
|
||||
{
|
||||
double k = Math.Tan(Math.PI * Frequency / SampleRate);
|
||||
double norm = 1 / (1 + k / Q + k * k);
|
||||
double k = Math.Tan(Math.PI * _frequency / _sampleRate);
|
||||
double norm = 1 / (1 + k / _q + k * k);
|
||||
A0 = (1 + k * k) * norm;
|
||||
A1 = 2 * (k * k - 1) * norm;
|
||||
A2 = A0;
|
||||
B1 = A1;
|
||||
B2 = (1 - k / Q + k * k) * norm;
|
||||
B2 = (1 - k / _q + k * k) * norm;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to apply a lowshelf-filter to a signal.
|
||||
/// </summary>
|
||||
public class LowShelfFilter : BiQuad
|
||||
public sealed class LowShelfFilter : BiQuad
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LowShelfFilter"/> class.
|
||||
@@ -344,10 +294,8 @@ namespace Barotrauma.Sounds
|
||||
/// <param name="frequency">The filter's corner frequency.</param>
|
||||
/// <param name="gainDB">Gain value in dB.</param>
|
||||
public LowShelfFilter(int sampleRate, double frequency, double gainDB)
|
||||
: base(sampleRate, frequency)
|
||||
{
|
||||
GainDB = gainDB;
|
||||
}
|
||||
: base(sampleRate, frequency, DefaultQ, gainDB)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates all coefficients.
|
||||
@@ -355,10 +303,10 @@ namespace Barotrauma.Sounds
|
||||
protected override void CalculateBiQuadCoefficients()
|
||||
{
|
||||
const double sqrt2 = 1.4142135623730951;
|
||||
double k = Math.Tan(Math.PI * Frequency / SampleRate);
|
||||
double v = Math.Pow(10, Math.Abs(GainDB) / 20.0);
|
||||
double k = Math.Tan(Math.PI * _frequency / _sampleRate);
|
||||
double v = Math.Pow(10, Math.Abs(_gainDB) / 20.0);
|
||||
double norm;
|
||||
if (GainDB >= 0)
|
||||
if (_gainDB >= 0)
|
||||
{ // boost
|
||||
norm = 1 / (1 + sqrt2 * k + k * k);
|
||||
A0 = (1 + Math.Sqrt(2 * v) * k + v * k * k) * norm;
|
||||
@@ -382,7 +330,7 @@ namespace Barotrauma.Sounds
|
||||
/// <summary>
|
||||
/// Used to apply a highshelf-filter to a signal.
|
||||
/// </summary>
|
||||
public class HighShelfFilter : BiQuad
|
||||
public sealed class HighShelfFilter : BiQuad
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HighShelfFilter"/> class.
|
||||
@@ -391,10 +339,8 @@ namespace Barotrauma.Sounds
|
||||
/// <param name="frequency">The filter's corner frequency.</param>
|
||||
/// <param name="gainDB">Gain value in dB.</param>
|
||||
public HighShelfFilter(int sampleRate, double frequency, double gainDB)
|
||||
: base(sampleRate, frequency)
|
||||
{
|
||||
GainDB = gainDB;
|
||||
}
|
||||
: base(sampleRate, frequency, DefaultQ, gainDB)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates all coefficients.
|
||||
@@ -402,10 +348,10 @@ namespace Barotrauma.Sounds
|
||||
protected override void CalculateBiQuadCoefficients()
|
||||
{
|
||||
const double sqrt2 = 1.4142135623730951;
|
||||
double k = Math.Tan(Math.PI * Frequency / SampleRate);
|
||||
double v = Math.Pow(10, Math.Abs(GainDB) / 20.0);
|
||||
double k = Math.Tan(Math.PI * _frequency / _sampleRate);
|
||||
double v = Math.Pow(10, Math.Abs(_gainDB) / 20.0);
|
||||
double norm;
|
||||
if (GainDB >= 0)
|
||||
if (_gainDB >= 0)
|
||||
{ // boost
|
||||
norm = 1 / (1 + sqrt2 * k + k * k);
|
||||
A0 = (v + Math.Sqrt(2 * v) * k + k * k) * norm;
|
||||
@@ -429,22 +375,8 @@ namespace Barotrauma.Sounds
|
||||
/// <summary>
|
||||
/// Used to apply an peak-filter to a signal.
|
||||
/// </summary>
|
||||
public class PeakFilter : BiQuad
|
||||
public sealed class PeakFilter : BiQuad
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the bandwidth.
|
||||
/// </summary>
|
||||
public double BandWidth
|
||||
{
|
||||
get { return Q; }
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
Q = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PeakFilter"/> class.
|
||||
/// </summary>
|
||||
@@ -453,10 +385,8 @@ namespace Barotrauma.Sounds
|
||||
/// <param name="bandWidth">The bandWidth.</param>
|
||||
/// <param name="peakGainDB">The gain value in dB.</param>
|
||||
public PeakFilter(int sampleRate, double frequency, double bandWidth, double peakGainDB)
|
||||
: base(sampleRate, frequency, bandWidth)
|
||||
{
|
||||
GainDB = peakGainDB;
|
||||
}
|
||||
: base(sampleRate, frequency, bandWidth, peakGainDB)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates all coefficients.
|
||||
@@ -464,11 +394,11 @@ namespace Barotrauma.Sounds
|
||||
protected override void CalculateBiQuadCoefficients()
|
||||
{
|
||||
double norm;
|
||||
double v = Math.Pow(10, Math.Abs(GainDB) / 20.0);
|
||||
double k = Math.Tan(Math.PI * Frequency / SampleRate);
|
||||
double q = Q;
|
||||
double v = Math.Pow(10, Math.Abs(_gainDB) / 20.0);
|
||||
double k = Math.Tan(Math.PI * _frequency / _sampleRate);
|
||||
double q = _q;
|
||||
|
||||
if (GainDB >= 0) //boost
|
||||
if (_gainDB >= 0) //boost
|
||||
{
|
||||
norm = 1 / (1 + 1 / q * k + k * k);
|
||||
A0 = (1 + v / q * k + k * k) * norm;
|
||||
|
||||
@@ -812,7 +812,7 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
for (int i = loadedSounds.Count - 1; i >= 0; i--)
|
||||
{
|
||||
loadedSounds[i].InitializeALBuffers();
|
||||
loadedSounds[i].InitializeAlBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,7 +834,7 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
if (keepSounds)
|
||||
{
|
||||
loadedSounds[i].DeleteALBuffers();
|
||||
loadedSounds[i].DeleteAlBuffers();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -156,6 +156,12 @@ namespace Barotrauma
|
||||
insideSubFactor = 1.0f;
|
||||
}
|
||||
|
||||
if (Character.Controlled != null && Character.Controlled.PressureTimer > 0.0f && !Character.Controlled.IsDead)
|
||||
{
|
||||
//make the sound lerp to the "outside" sound when under pressure
|
||||
insideSubFactor -= Character.Controlled.PressureTimer / 100.0f;
|
||||
}
|
||||
|
||||
movementSoundVolume = Math.Max(movementSoundVolume, movementFactor);
|
||||
if (!MathUtils.IsValid(movementSoundVolume))
|
||||
{
|
||||
@@ -183,7 +189,7 @@ namespace Barotrauma
|
||||
if (chn is null || !chn.IsPlaying)
|
||||
{
|
||||
if (volume < 0.01f) { return; }
|
||||
if (!(chn is null)) { waterAmbienceChannels.Remove(chn); }
|
||||
if (chn is not null) { waterAmbienceChannels.Remove(chn); }
|
||||
chn = sound.Play(volume, "waterambience");
|
||||
chn.Looping = true;
|
||||
waterAmbienceChannels.Add(chn);
|
||||
@@ -195,6 +201,15 @@ namespace Barotrauma
|
||||
{
|
||||
chn.FadeOutAndDispose();
|
||||
}
|
||||
if (Character.Controlled != null && Character.Controlled.PressureTimer > 0.0f && !Character.Controlled.IsDead)
|
||||
{
|
||||
//make the sound decrease in pitch when under pressure
|
||||
chn.FrequencyMultiplier = MathHelper.Clamp(Character.Controlled.PressureTimer / 200.0f, 0.75f, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
chn.FrequencyMultiplier = Math.Min(chn.frequencyMultiplier + deltaTime, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,6 +667,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
LogCurrentMusic();
|
||||
updateMusicTimer = UpdateMusicInterval;
|
||||
}
|
||||
|
||||
@@ -715,6 +731,26 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static double lastMusicLogTime;
|
||||
const double MusicLogInterval = 60.0;
|
||||
private static void LogCurrentMusic()
|
||||
{
|
||||
if (Screen.Selected != GameMain.GameScreen) { return; }
|
||||
if (Timing.TotalTime < lastMusicLogTime + MusicLogInterval) { return; }
|
||||
for (int i = 0; i < musicChannel.Length; i++)
|
||||
{
|
||||
if (musicChannel[i] != null &&
|
||||
musicChannel[i].IsPlaying &&
|
||||
musicChannel[i].Sound?.Filename != null)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent(
|
||||
"BackgroundMusic:" +
|
||||
Path.GetFileNameWithoutExtension(musicChannel[i].Sound.Filename.Replace(":", string.Empty).Replace(" ", string.Empty)));
|
||||
}
|
||||
}
|
||||
lastMusicLogTime = Timing.TotalTime;
|
||||
}
|
||||
|
||||
private static void DisposeMusicChannel(int index)
|
||||
{
|
||||
var clip = musicClips.FirstOrDefault(m => m.Sound == musicChannel[index]?.Sound);
|
||||
|
||||
Reference in New Issue
Block a user