136 lines
4.7 KiB
C#
136 lines
4.7 KiB
C#
using System;
|
|
using OpenAL;
|
|
using NVorbis;
|
|
using System.Collections.Generic;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Barotrauma.Sounds
|
|
{
|
|
public class OggSound : Sound
|
|
{
|
|
private VorbisReader reader;
|
|
|
|
//key = sample rate, value = filter
|
|
private static Dictionary<int, BiQuad> muffleFilters = new Dictionary<int, BiQuad>();
|
|
|
|
private static 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) { }
|
|
|
|
public override float GetAmplitudeAtPlaybackPos(int playbackPos)
|
|
{
|
|
if (playbackAmplitude == null || playbackAmplitude.Count == 0) { return 0.0f; }
|
|
int index = playbackPos / AMPLITUDE_SAMPLE_COUNT;
|
|
if (index < 0) { return 0.0f; }
|
|
if (index >= playbackAmplitude.Count) { index = playbackAmplitude.Count - 1; }
|
|
return playbackAmplitude[index];
|
|
}
|
|
|
|
public override int FillStreamBuffer(int samplePos, short[] buffer)
|
|
{
|
|
if (!Stream) throw new Exception("Called FillStreamBuffer on a non-streamed sound!");
|
|
|
|
if (samplePos >= reader.TotalSamples * reader.Channels * 2) return 0;
|
|
|
|
samplePos /= reader.Channels * 2;
|
|
reader.DecodedPosition = samplePos;
|
|
|
|
float[] floatBuffer = new float[buffer.Length];
|
|
int readSamples = reader.ReadSamples(floatBuffer, 0, buffer.Length / 2);
|
|
//MuffleBuffer(floatBuffer, reader.Channels);
|
|
CastBuffer(floatBuffer, buffer, readSamples);
|
|
|
|
return readSamples;
|
|
}
|
|
|
|
static void MuffleBuffer(float[] buffer, int sampleRate, int channelCount)
|
|
{
|
|
if (!muffleFilters.TryGetValue(sampleRate, out BiQuad filter))
|
|
{
|
|
filter = new LowpassFilter(sampleRate, 800);
|
|
muffleFilters.Add(sampleRate, filter);
|
|
}
|
|
filter.Process(buffer);
|
|
}
|
|
|
|
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)
|
|
{
|
|
Buffers.RequestAlBuffers(); FillBuffers();
|
|
}
|
|
}
|
|
|
|
public override void FillBuffers()
|
|
{
|
|
if (!Stream)
|
|
{
|
|
reader.DecodedPosition = 0;
|
|
|
|
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 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 buffer data for non-streamed audio! " + Al.GetErrorString(alError));
|
|
}
|
|
|
|
reader.Dispose(); reader = null;
|
|
}
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
if (Stream)
|
|
{
|
|
reader.Dispose();
|
|
}
|
|
|
|
base.Dispose();
|
|
}
|
|
}
|
|
}
|