From e5b43b263c64cf1a3430ee4e79951f8845e332b0 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 12 Aug 2018 17:06:24 +1000 Subject: [PATCH] Simplify SharpWave even more. (and fix a memory leak in C client) --- ClassicalSharp.sln | 4 +- ClassicalSharp/Audio/AudioPlayer.Sounds.cs | 1 - ClassicalSharp/Audio/AudioPlayer.cs | 4 +- Launcher2/Patcher/SoundPatcher.cs | 28 ++++++------- SharpWave/Backends/AL.cs | 3 +- SharpWave/Backends/IAudioOutput.cs | 49 ++++------------------ SharpWave/Backends/OpenALOut.cs | 1 - SharpWave/Backends/WinMM.cs | 6 +-- SharpWave/Backends/WinMmOut.cs | 1 - SharpWave/ICodec.cs | 17 -------- SharpWave/IMediaContainer.cs | 48 --------------------- SharpWave/SharpWave.csproj | 6 +-- SharpWave/{VolumeMixer.cs => Utils.cs} | 33 ++++++++++++++- SharpWave/Utils/MemUtils.cs | 35 ---------------- SharpWave/csvorbis/VorbisCodec.cs | 21 +--------- src/Client/Vorbis.c | 44 ++++++++++++++----- src/Client/Vorbis.h | 4 +- 17 files changed, 98 insertions(+), 207 deletions(-) delete mode 100644 SharpWave/ICodec.cs delete mode 100644 SharpWave/IMediaContainer.cs rename SharpWave/{VolumeMixer.cs => Utils.cs} (60%) delete mode 100644 SharpWave/Utils/MemUtils.cs diff --git a/ClassicalSharp.sln b/ClassicalSharp.sln index 728f84106..bfae6348e 100644 --- a/ClassicalSharp.sln +++ b/ClassicalSharp.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 # SharpDevelop 4.4 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassicalSharp", "ClassicalSharp\ClassicalSharp.csproj", "{BEB1C785-5CAD-48FF-A886-876BF0A318D4}" EndProject diff --git a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs index 9e1ab89c6..111a76579 100644 --- a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs +++ b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs @@ -3,7 +3,6 @@ using System; using System.Threading; using ClassicalSharp.Events; using SharpWave; -using SharpWave.Codecs; namespace ClassicalSharp.Audio { diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs index 0c596d573..05c88f9ad 100644 --- a/ClassicalSharp/Audio/AudioPlayer.cs +++ b/ClassicalSharp/Audio/AudioPlayer.cs @@ -3,7 +3,6 @@ using System; using System.IO; using System.Threading; using SharpWave; -using SharpWave.Codecs.Vorbis; namespace ClassicalSharp.Audio { @@ -79,10 +78,9 @@ namespace ClassicalSharp.Audio { string path = Path.Combine("audio", file); using (Stream fs = Platform.FileOpen(path)) { - OggContainer container = new OggContainer(fs); try { musicOut.SetVolume(game.MusicVolume / 100.0f); - musicOut.PlayStreaming(container); + musicOut.PlayStreaming(fs); } catch (InvalidOperationException ex) { HandleMusicError(ex); try { musicOut.Dispose(); } catch { } diff --git a/Launcher2/Patcher/SoundPatcher.cs b/Launcher2/Patcher/SoundPatcher.cs index 2ec5de426..98e2802b7 100644 --- a/Launcher2/Patcher/SoundPatcher.cs +++ b/Launcher2/Patcher/SoundPatcher.cs @@ -1,10 +1,9 @@ // ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT -using System; -using System.IO; -using ClassicalSharp; -using ClassicalSharp.Network; -using SharpWave; -using SharpWave.Codecs.Vorbis; +using System; +using System.IO; +using ClassicalSharp; +using ClassicalSharp.Network; +using SharpWave; namespace Launcher.Patcher { @@ -60,25 +59,26 @@ namespace Launcher.Patcher { string path = Path.Combine("audio", prefix + name + ".wav"); using (Stream dst = Platform.FileCreate(path)) - using (MemoryStream src = new MemoryStream(rawData)) + using (MemoryStream src = new MemoryStream(rawData)) { dst.SetLength(44); - RawOut output = new RawOut((FileStream)dst, true); - output.Create(1); - OggContainer container = new OggContainer(src); - output.PlayStreaming(container); + VorbisCodec codec = new VorbisCodec(); + AudioFormat format = codec.ReadHeader(src); + + foreach (AudioChunk chunk in codec.StreamData(src)) { + dst.Write(chunk.Data, 0, chunk.Length); + } dst.Position = 0; BinaryWriter w = new BinaryWriter(dst); - WriteWaveHeader(w, dst, output); + WriteWaveHeader(w, dst, format); } } - void WriteWaveHeader(BinaryWriter w, Stream stream, RawOut data) { + void WriteWaveHeader(BinaryWriter w, Stream stream, AudioFormat format) { WriteFourCC(w, "RIFF"); w.Write((int)(stream.Length - 8)); WriteFourCC(w, "WAVE"); - AudioFormat format = data.Format; WriteFourCC(w, "fmt "); w.Write(16); diff --git a/SharpWave/Backends/AL.cs b/SharpWave/Backends/AL.cs index 53947e0df..41ef6c872 100644 --- a/SharpWave/Backends/AL.cs +++ b/SharpWave/Backends/AL.cs @@ -44,9 +44,9 @@ namespace OpenTK.Audio.OpenAL { public static extern void alGenBuffers(int n, uint* bids); [DllImport(lib, CallingConvention = style)] public static extern void alDeleteBuffers(int n, uint* bids); - [DllImport(lib, CallingConvention = style)] public static extern void alBufferData(uint bid, ALFormat format, IntPtr buffer, int size, int freq); + [DllImport(lib, CallingConvention = style)] public static extern IntPtr alcCreateContext(IntPtr device, int* attrlist); [DllImport(lib, CallingConvention = style)] @@ -79,7 +79,6 @@ namespace OpenTK.Audio.OpenAL { public enum ALError { NoError = 0, InvalidName = 0xA001, - IllegalEnum = 0xA002, InvalidEnum = 0xA002, InvalidValue = 0xA003, InvalidOperation = 0xA004, diff --git a/SharpWave/Backends/IAudioOutput.cs b/SharpWave/Backends/IAudioOutput.cs index 149aae62e..9e764e2ec 100644 --- a/SharpWave/Backends/IAudioOutput.cs +++ b/SharpWave/Backends/IAudioOutput.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Threading; -using SharpWave.Codecs; -using SharpWave.Containers; namespace SharpWave { @@ -15,6 +13,11 @@ namespace SharpWave { } } + public sealed class AudioChunk { + public byte[] Data; + public int Length; + } + public delegate void Action(); public abstract class IAudioOutput : IDisposable { @@ -30,14 +33,12 @@ namespace SharpWave { public int NumBuffers; public bool pendingStop; - public void PlayStreaming(IMediaContainer container) { - container.ReadMetadata(); - ICodec codec = container.GetAudioCodec(); - AudioFormat format = codec.ReadHeader(container); + public void PlayStreaming(Stream src) { + VorbisCodec codec = new VorbisCodec(); + AudioFormat format = codec.ReadHeader(src); SetFormat(format); - IEnumerator chunks = - codec.StreamData(container).GetEnumerator(); + IEnumerator chunks = codec.StreamData(src).GetEnumerator(); bool reachedEnd = false; for (;;) { @@ -59,36 +60,4 @@ namespace SharpWave { } } } - - /// Outputs raw audio to the given stream in the constructor. - public unsafe sealed partial class RawOut : IAudioOutput { - public readonly Stream OutStream; - public readonly bool LeaveOpen; - public Action OnGotMetadata; - - public RawOut(FileStream outStream, bool leaveOpen) { - OutStream = outStream; - LeaveOpen = leaveOpen; - } - - public override void Create(int numBuffers) { NumBuffers = numBuffers; } - public override void SetVolume(float volume) { } - - public override void SetFormat(AudioFormat format) { - Format = format; - if (OnGotMetadata != null) OnGotMetadata(); - } - - public override void PlayData(int index, AudioChunk chunk) { - OutStream.Write(chunk.Data, 0, chunk.Length); - } - - public override void Dispose() { - if (LeaveOpen) return; - OutStream.Close(); - } - - public override bool IsCompleted(int index) { return true; } - public override bool IsFinished() { return true; } - } } \ No newline at end of file diff --git a/SharpWave/Backends/OpenALOut.cs b/SharpWave/Backends/OpenALOut.cs index a95c7f822..fc8f9e1e6 100644 --- a/SharpWave/Backends/OpenALOut.cs +++ b/SharpWave/Backends/OpenALOut.cs @@ -1,7 +1,6 @@ using System; using OpenTK.Audio; using OpenTK.Audio.OpenAL; -using SharpWave.Codecs; namespace SharpWave { diff --git a/SharpWave/Backends/WinMM.cs b/SharpWave/Backends/WinMM.cs index 3c757b226..3d485bc2b 100644 --- a/SharpWave/Backends/WinMM.cs +++ b/SharpWave/Backends/WinMM.cs @@ -28,8 +28,7 @@ namespace SharpWave { internal static string GetErrorDescription(uint error) { StringBuilder message = new StringBuilder(1024); uint result = waveOutGetErrorText(error, message, message.Capacity); - if(result == 0) - return message.ToString(); + if (result == 0) return message.ToString(); return "waveOutGetErrorText failed."; } } @@ -61,8 +60,5 @@ namespace SharpWave { public enum WaveHeaderFlags : uint { Done = 0x01, Prepared = 0x02, - BeginLoop = 0x04, - EndLoop = 0x08, - InQueue = 0x10, } } diff --git a/SharpWave/Backends/WinMmOut.cs b/SharpWave/Backends/WinMmOut.cs index e0da38609..2bd4b3d6b 100644 --- a/SharpWave/Backends/WinMmOut.cs +++ b/SharpWave/Backends/WinMmOut.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.InteropServices; using System.Threading; -using SharpWave.Codecs; namespace SharpWave { diff --git a/SharpWave/ICodec.cs b/SharpWave/ICodec.cs deleted file mode 100644 index 3eb89e284..000000000 --- a/SharpWave/ICodec.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace SharpWave.Codecs { - - public interface ICodec { - AudioFormat ReadHeader(Stream source); - IEnumerable StreamData(Stream source); - string Name { get; } - } - - public sealed class AudioChunk { - public byte[] Data; - public int Length; - } -} diff --git a/SharpWave/IMediaContainer.cs b/SharpWave/IMediaContainer.cs deleted file mode 100644 index e0b20483d..000000000 --- a/SharpWave/IMediaContainer.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.IO; -using SharpWave.Codecs; - -namespace SharpWave.Containers { - - public abstract class IMediaContainer : Stream { - protected Stream stream; - public IMediaContainer(Stream source) { stream = source; } - - public abstract void ReadMetadata(); - - public abstract ICodec GetAudioCodec(); - - #region Stream implementation - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return false; } } - public override void Flush() { stream.Flush(); } - public override long Length { get { return stream.Length; } } - - public override long Position { - get { return stream.Position; } - set { stream.Position = value; } - } - - public override long Seek( long offset, SeekOrigin origin ) { - return stream.Seek( offset, origin ); - } - - public override void SetLength( long value ) { - throw new NotImplementedException( "SharpWave is only a decoder" ); - } - - public override int Read(byte[] buffer, int offset, int count) { - return stream.Read(buffer, offset, count); - } - - public override int ReadByte() { return stream.ReadByte(); } - - public override void Write( byte[] buffer, int offset, int count ) { - throw new NotImplementedException( "SharpWave is only a decoder" ); - } - - #endregion - } -} diff --git a/SharpWave/SharpWave.csproj b/SharpWave/SharpWave.csproj index b74cf9377..b13f7b098 100644 --- a/SharpWave/SharpWave.csproj +++ b/SharpWave/SharpWave.csproj @@ -61,21 +61,17 @@ - - + - - - diff --git a/SharpWave/VolumeMixer.cs b/SharpWave/Utils.cs similarity index 60% rename from SharpWave/VolumeMixer.cs rename to SharpWave/Utils.cs index ec980917c..c89cd3647 100644 --- a/SharpWave/VolumeMixer.cs +++ b/SharpWave/Utils.cs @@ -2,6 +2,37 @@ namespace SharpWave { + public static class MemUtils { + + static MemUtils() { + use64Bit = IntPtr.Size == 8; + } + static bool use64Bit; + + public static unsafe void memcpy( IntPtr srcPtr, IntPtr dstPtr, int bytes ) { + byte* srcByte, dstByte; + if( use64Bit ) { + ulong* srcLong = (ulong*)srcPtr, dstLong = (ulong*)dstPtr; + while( bytes >= 8 ) { + *dstLong++ = *srcLong++; + bytes -= 8; + } + srcByte = (byte*)srcLong; dstByte = (byte*)dstLong; + } else { + uint* srcInt = (uint*)srcPtr, dstInt = (uint*)dstPtr; + while( bytes >= 4 ) { + *dstInt++ = *srcInt++; + bytes -= 4; + } + srcByte = (byte*)srcInt; dstByte = (byte*)dstInt; + } + + for( int i = 0; i < bytes; i++ ) { + *dstByte++ = *srcByte++; + } + } + } + public unsafe static class VolumeMixer { public static void Mix16( short* samples, int numSamples, int volumePercent ) { @@ -36,4 +67,4 @@ namespace SharpWave { } } } -} +} \ No newline at end of file diff --git a/SharpWave/Utils/MemUtils.cs b/SharpWave/Utils/MemUtils.cs deleted file mode 100644 index 962e147b5..000000000 --- a/SharpWave/Utils/MemUtils.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; - -namespace SharpWave { - - public static class MemUtils { - - static MemUtils() { - use64Bit = IntPtr.Size == 8; - } - static bool use64Bit; - - public static unsafe void memcpy( IntPtr srcPtr, IntPtr dstPtr, int bytes ) { - byte* srcByte, dstByte; - if( use64Bit ) { - ulong* srcLong = (ulong*)srcPtr, dstLong = (ulong*)dstPtr; - while( bytes >= 8 ) { - *dstLong++ = *srcLong++; - bytes -= 8; - } - srcByte = (byte*)srcLong; dstByte = (byte*)dstLong; - } else { - uint* srcInt = (uint*)srcPtr, dstInt = (uint*)dstPtr; - while( bytes >= 4 ) { - *dstInt++ = *srcInt++; - bytes -= 4; - } - srcByte = (byte*)srcInt; dstByte = (byte*)dstInt; - } - - for( int i = 0; i < bytes; i++ ) { - *dstByte++ = *srcByte++; - } - } - } -} \ No newline at end of file diff --git a/SharpWave/csvorbis/VorbisCodec.cs b/SharpWave/csvorbis/VorbisCodec.cs index 02a6f3e03..9f27097db 100644 --- a/SharpWave/csvorbis/VorbisCodec.cs +++ b/SharpWave/csvorbis/VorbisCodec.cs @@ -3,27 +3,10 @@ using System.Collections.Generic; using System.IO; using csogg; using csvorbis; -using SharpWave.Containers; -namespace SharpWave.Codecs.Vorbis { +namespace SharpWave { - public sealed class OggContainer : IMediaContainer { - - public OggContainer( Stream source ) : base( source ) { - } - - public override void ReadMetadata() { - // this would be a good place to read vorbis headers - } - - public override ICodec GetAudioCodec() { - return new VorbisCodec(); - } - } - - public sealed class VorbisCodec : ICodec { - public string Name { get { return "Xiph.org Vorbis"; } } - + public sealed class VorbisCodec { public VorbisCodec() { chunk = new AudioChunk(); } diff --git a/src/Client/Vorbis.c b/src/Client/Vorbis.c index 9347f1b72..16b92865f 100644 --- a/src/Client/Vorbis.c +++ b/src/Client/Vorbis.c @@ -147,6 +147,13 @@ struct Codebook { UInt16* Multiplicands; }; +static void Codebook_Free(struct Codebook* c) { + Mem_Free(&c->Codewords); + Mem_Free(&c->CodewordLens); + Mem_Free(&c->Values); + Mem_Free(&c->Multiplicands); +} + static UInt32 Codebook_Pow(UInt32 base, UInt32 exp) { UInt32 result = 1; /* exponentiation by squaring */ while (exp) { @@ -267,6 +274,7 @@ static ReturnCode Codebook_DecodeSetup(struct VorbisState* ctx, struct Codebook* Mem_Free(&codewordLens); c->LookupType = Vorbis_ReadBits(ctx, 4); + c->Multiplicands = NULL; if (c->LookupType == 0) return 0; if (c->LookupType > 2) return VORBIS_ERR_CODEBOOK_LOOKUP; @@ -704,7 +712,7 @@ static void Residue_DecodeFrame(struct VorbisState* ctx, struct Residue* r, Int3 bool decodeAny = false; Int32 i, j; - /* type 2 decodes all channel vectors 2, if at least 1 channel to decode */ + /* type 2 decodes all channel vectors, if at least 1 channel to decode */ for (i = 0; i < ch; i++) { if (!doNotDecode[i]) decodeAny = true; } @@ -976,17 +984,25 @@ static void Vorbis_CalcWindow(struct VorbisState* ctx, UInt32* offset, bool long } void Vorbis_Free(struct VorbisState* ctx) { + Int32 i; + for (i = 0; i < ctx->NumCodebooks; i++) { + Codebook_Free(&ctx->Codebooks[i]); + } + Mem_Free(&ctx->Codebooks); Mem_Free(&ctx->Floors); Mem_Free(&ctx->Residues); Mem_Free(&ctx->Mappings); Mem_Free(&ctx->Modes); Mem_Free(&ctx->WindowShort); - /* TODO: free memory in codebooks, other bits, etc*/ + + Mem_Free(&ctx->Values[0]); + Mem_Free(&ctx->Values[1]); + /* TODO: free other temp memory, etc*/ } -static bool Vorbis_ValidBlockSize(UInt32 blockSize) { - return blockSize >= 64 && blockSize <= 8192 && Math_IsPowOf2(blockSize); +static bool Vorbis_ValidBlockSize(UInt32 size) { + return size >= 64 && size <= VORBIS_MAX_BLOCK_SIZE && Math_IsPowOf2(size); } static ReturnCode Vorbis_DecodeHeader(struct VorbisState* ctx, UInt8 type) { @@ -1045,6 +1061,7 @@ static ReturnCode Vorbis_DecodeSetup(struct VorbisState* ctx) { result = Codebook_DecodeSetup(ctx, &ctx->Codebooks[i]); if (result) return result; } + ctx->NumCodebooks = count; count = Vorbis_ReadBits(ctx, 6); count++; for (i = 0; i < count; i++) { @@ -1113,8 +1130,8 @@ ReturnCode Vorbis_DecodeHeaders(struct VorbisState* ctx) { if (result) return result; /* window calculations can be pre-computed here */ - UInt32 size = ctx->BlockSizes[0] + ctx->BlockSizes[1] * 4, offset = 0; - ctx->WindowShort = Mem_Alloc(size, sizeof(Real32), "Vorbis windows"); + UInt32 count = ctx->BlockSizes[0] + ctx->BlockSizes[1] * 4, offset = 0; + ctx->WindowShort = Mem_Alloc(count, sizeof(Real32), "Vorbis windows"); Vorbis_CalcWindow(ctx, &offset, false, false, false); ctx->WindowLong[0][0] = ctx->WindowShort + offset; @@ -1126,6 +1143,10 @@ ReturnCode Vorbis_DecodeHeaders(struct VorbisState* ctx) { ctx->WindowLong[1][1] = ctx->WindowShort + offset; Vorbis_CalcWindow(ctx, &offset, true, true, true); + count = ctx->Channels * ctx->BlockSizes[1]; + ctx->Values[0] = Mem_AllocCleared(count, sizeof(Real32), "Vorbis values"); + ctx->Values[1] = Mem_AllocCleared(count, sizeof(Real32), "Vorbis values"); + imdct_init(&ctx->imdct[0], ctx->BlockSizes[0]); imdct_init(&ctx->imdct[1], ctx->BlockSizes[1]); return 0; @@ -1155,9 +1176,13 @@ ReturnCode Vorbis_DecodeFrame(struct VorbisState* ctx) { next_window = Vorbis_ReadBits(ctx, 1); } - ctx->Values = Mem_AllocCleared(ctx->Channels * ctx->CurBlockSize, sizeof(Real32), "audio values"); + /* swap prev and cur outputs around */ + Real32* tmp = ctx->Values[1]; ctx->Values[1] = ctx->Values[0]; ctx->Values[0] = tmp; + Mem_Set(ctx->Values[0], 0, ctx->Channels * ctx->CurBlockSize); + for (i = 0; i < ctx->Channels; i++) { - ctx->CurOutput[i] = ctx->Values + i * ctx->CurBlockSize; + ctx->CurOutput[i] = ctx->Values[0] + i * ctx->CurBlockSize; + ctx->PrevOutput[i] = ctx->Values[1] + i * ctx->PrevBlockSize; } /* decode floor */ @@ -1292,9 +1317,6 @@ Int32 Vorbis_OutputFrame(struct VorbisState* ctx, Int16* data) { finish: ctx->PrevBlockSize = ctx->CurBlockSize; - for (i = 0; i < VORBIS_MAX_CHANS; i++) { - ctx->PrevOutput[i] = ctx->CurOutput[i]; - } return size; } diff --git a/src/Client/Vorbis.h b/src/Client/Vorbis.h index 51e3d3523..cebac6cb6 100644 --- a/src/Client/Vorbis.h +++ b/src/Client/Vorbis.h @@ -27,9 +27,9 @@ struct VorbisState { struct Stream* Source; /* Source for filling Input buffer */ UInt8 Channels, ModeNumBits; - UInt16 CurBlockSize, PrevBlockSize, DataSize; + UInt16 CurBlockSize, PrevBlockSize, DataSize, NumCodebooks; Int32 SampleRate; Int32 BlockSizes[2]; - Real32* Values; + Real32* Values[2]; /* swapped each frame */ Real32* PrevOutput[VORBIS_MAX_CHANS]; Real32* CurOutput[VORBIS_MAX_CHANS];