Improve audio parsing performance.

- Improve the AudReader and WavReader by performing fewer, larger stream reads to consume bytes more efficiently.
- Improve ImaAdpcmReader.LoadImaAdpcmSound by accepting an output buffer rather than allocating a new array.
- Improve StreamExts.ReadAllBytes by using MemoryStream.CopyTo. This internally rents a much larger buffer from the array pool, allowing for fewer, larger stream reads.
This commit is contained in:
RoosterDragon
2025-11-25 20:42:52 +00:00
committed by Gustas Kažukauskas
parent b429ca7879
commit 8b8651dcf7
5 changed files with 71 additions and 57 deletions

View File

@@ -101,6 +101,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
{
readonly int outputSize;
int dataSize;
byte[] inputBuffer;
int currentSample;
int baseOffset;
@@ -121,9 +122,12 @@ namespace OpenRA.Mods.Cnc.FileFormats
return true;
var chunk = AudChunk.Read(baseStream);
var input = EnsureArraySize(ref inputBuffer, chunk.CompressedSize);
baseStream.ReadBytes(input);
for (var n = 0; n < chunk.CompressedSize; n++)
{
var b = baseStream.ReadUInt8();
var b = input[n];
var t = ImaAdpcmReader.DecodeImaAdpcmSample(b, ref index, ref currentSample);
data.Enqueue((byte)t);
@@ -144,6 +148,13 @@ namespace OpenRA.Mods.Cnc.FileFormats
return dataSize <= 0;
}
static Span<byte> EnsureArraySize(ref byte[] array, int desiredSize)
{
if (array == null || array.Length < desiredSize)
array = new byte[desiredSize];
return array.AsSpan(..desiredSize);
}
}
sealed class WestwoodCompressedAudStream : ReadOnlyAdapterStream

View File

@@ -225,23 +225,25 @@ namespace OpenRA.Mods.Cnc.FileFormats
}
}
static byte[] GetAudioData(bool compressed, MemoryStream audio, ref int adpcmIndex)
{
var audioArray = audio.ToArray();
if (!compressed)
return audioArray;
var result = new byte[audio.Length * 4];
ImaAdpcmReader.LoadImaAdpcmSound(audioArray, ref adpcmIndex, result);
return result;
}
if (AudioChannels == 1)
AudioData = compressed ? ImaAdpcmReader.LoadImaAdpcmSound(audio1.ToArray(), ref adpcmIndex) : audio1.ToArray();
AudioData = GetAudioData(compressed, audio1, ref adpcmIndex);
else
{
byte[] leftData, rightData;
if (!compressed)
{
leftData = audio1.ToArray();
rightData = audio2.ToArray();
}
else
{
adpcmIndex = 0;
leftData = ImaAdpcmReader.LoadImaAdpcmSound(audio1.ToArray(), ref adpcmIndex);
adpcmIndex = 0;
rightData = ImaAdpcmReader.LoadImaAdpcmSound(audio2.ToArray(), ref adpcmIndex);
}
adpcmIndex = 0;
var leftData = GetAudioData(compressed, audio1, ref adpcmIndex);
adpcmIndex = 0;
var rightData = GetAudioData(compressed, audio2, ref adpcmIndex);
AudioData = new byte[rightData.Length + leftData.Length];
var rightIndex = 0;