4 using System.Collections.Generic;
5 using System.Threading.Tasks;
11 private readonly VorbisReader streamReader;
13 public long MaxStreamSamplePos => streamReader ==
null ? 0 : streamReader.TotalSamples * streamReader.Channels * 2;
15 private List<float> playbackAmplitude;
16 private const int AMPLITUDE_SAMPLE_COUNT = 4410;
18 private short[] sampleBuffer = Array.Empty<
short>();
19 private short[] muffleBuffer = Array.Empty<
short>();
21 stream, true, xElement)
23 var reader =
new VorbisReader(
Filename);
30 streamReader = reader;
36 $
"LoadSamples {filename}",
41 if (!t.TryGetResult(out TaskResult result))
45 sampleBuffer = result.SampleBuffer;
46 muffleBuffer = result.MuffleBuffer;
47 playbackAmplitude = result.PlaybackAmplitude;
54 private readonly record
struct TaskResult(
57 List<float> PlaybackAmplitude);
59 private static async Task<TaskResult> LoadSamples(VorbisReader reader)
61 reader.DecodedPosition = 0;
63 int bufferSize = (int)reader.TotalSamples * reader.Channels;
65 float[] floatBuffer =
new float[bufferSize];
66 var sampleBuffer =
new short[bufferSize];
67 var muffledBuffer =
new short[bufferSize];
69 int readSamples = await Task.Run(() => reader.ReadSamples(floatBuffer, 0, bufferSize));
71 var playbackAmplitude =
new List<float>();
72 for (
int i = 0; i < bufferSize; i += reader.Channels * AMPLITUDE_SAMPLE_COUNT)
74 float maxAmplitude = 0.0f;
75 for (
int j = i; j < i + reader.Channels * AMPLITUDE_SAMPLE_COUNT; j++)
77 if (j >= bufferSize) {
break; }
78 maxAmplitude = Math.Max(maxAmplitude, Math.Abs(floatBuffer[j]));
80 playbackAmplitude.Add(maxAmplitude);
83 CastBuffer(floatBuffer, sampleBuffer, readSamples);
85 MuffleBuffer(floatBuffer, reader.SampleRate);
87 CastBuffer(floatBuffer, muffledBuffer, readSamples);
89 return new TaskResult(sampleBuffer, muffledBuffer, playbackAmplitude);
94 if (playbackAmplitude ==
null || playbackAmplitude.Count == 0) {
return 0.0f; }
95 int index = playbackPos / AMPLITUDE_SAMPLE_COUNT;
96 if (index < 0) {
return 0.0f; }
97 if (index >= playbackAmplitude.Count) { index = playbackAmplitude.Count - 1; }
98 return playbackAmplitude[index];
101 private float[] streamFloatBuffer =
null;
104 if (!
Stream) {
throw new Exception(
"Called FillStreamBuffer on a non-streamed sound!"); }
105 if (streamReader ==
null) {
throw new Exception(
"Called FillStreamBuffer when the reader is null!"); }
109 samplePos /= streamReader.Channels * 2;
110 streamReader.DecodedPosition = samplePos;
112 if (streamFloatBuffer is
null || streamFloatBuffer.Length < buffer.Length)
114 streamFloatBuffer =
new float[buffer.Length];
116 int readSamples = streamReader.ReadSamples(streamFloatBuffer, 0, buffer.Length);
118 CastBuffer(streamFloatBuffer, buffer, readSamples);
123 static void MuffleBuffer(
float[] buffer,
int sampleRate)
125 var filter =
new LowpassFilter(sampleRate, SoundPlayer.MuffleFilterFrequency);
126 filter.Process(buffer);
140 if (sampleBuffer.Length == 0 || muffleBuffer.Length == 0) {
return; }
145 sampleBuffer.Length *
sizeof(
short),
SampleRate);
150 throw new Exception(
"Failed to set regular buffer data for non-streamed audio! " +
Al.
GetErrorString(alError));
154 muffleBuffer.Length *
sizeof(
short),
SampleRate);
159 throw new Exception(
"Failed to set muffled buffer data for non-streamed audio! " +
Al.
GetErrorString(alError));
167 streamReader?.Dispose();
Used to apply a lowpass-filter to a signal.
override int FillStreamBuffer(int samplePos, short[] buffer)
override float GetAmplitudeAtPlaybackPos(int playbackPos)
OggSound(SoundManager owner, string filename, bool stream, ContentXElement xElement)
override void InitializeAlBuffers()
override void FillAlBuffers()
static int BuffersGenerated
static void CastBuffer(float[] inBuffer, short[] outBuffer, int length)
readonly SoundManager Owner
void KillChannels(Sound sound)
static string GetErrorString(int error)
static void BufferData(uint bid, int format, IntPtr data, int size, int freq)