From 3a2be63bf3525375ce7b0d496f1679b78e1b340e Mon Sep 17 00:00:00 2001 From: morkt Date: Fri, 7 Nov 2014 02:51:32 +0400 Subject: [PATCH] added Ogg/Vorbis audio format. --- ArcFormats/ArcFormats.csproj | 6 ++ ArcFormats/AudioOGG.cs | 119 +++++++++++++++++++++++++++++++++++ ArcFormats/packages.config | 4 ++ 3 files changed, 129 insertions(+) create mode 100644 ArcFormats/AudioOGG.cs create mode 100644 ArcFormats/packages.config diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 660733ed..9249393e 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -38,6 +38,9 @@ 6291456 + + ..\packages\NVorbis.0.8.3.0\lib\NVorbis.dll + @@ -62,6 +65,7 @@ + @@ -110,6 +114,7 @@ + True @@ -153,6 +158,7 @@ + PublicSettingsSingleFileGenerator Settings.Designer.cs diff --git a/ArcFormats/AudioOGG.cs b/ArcFormats/AudioOGG.cs new file mode 100644 index 00000000..9de15c46 --- /dev/null +++ b/ArcFormats/AudioOGG.cs @@ -0,0 +1,119 @@ +//! \file AudioOGG.cs +//! \date Fri Nov 07 00:32:15 2014 +//! \brief NVorbis wrapper for GameRes. +// +// Copyright (C) 2014 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System; +using System.ComponentModel.Composition; +using System.IO; +using NVorbis; + +namespace GameRes.Formats +{ + public class OggInput : SoundInput + { + VorbisReader m_reader; + + public override long Position + { + get + { + return (long)(m_reader.DecodedTime.TotalSeconds * m_reader.SampleRate * m_reader.Channels * sizeof(float)); + } + set + { + if (value < 0 || value > Length) throw new ArgumentOutOfRangeException("value"); + + m_reader.DecodedTime = TimeSpan.FromSeconds((double)value / m_reader.SampleRate / m_reader.Channels / sizeof(float)); + } + } + + public override bool CanSeek { get { return m_input.CanSeek; } } + + public override int SourceBitrate + { + get { return m_reader.NominalBitrate; } + } + + public OggInput (Stream file) : base (file) + { + m_reader = new VorbisReader (m_input, false); + var format = new GameRes.WaveFormat(); + format.FormatTag = 3; // WAVE_FORMAT_IEEE_FLOAT + format.Channels = (ushort)m_reader.Channels; + format.SamplesPerSecond = (uint)m_reader.SampleRate; + format.BitsPerSample = 32; + format.BlockAlign = (ushort)(4 * format.Channels); + format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign; + this.Format = format; + this.PcmSize = (long)(m_reader.TotalTime.TotalSeconds * format.SamplesPerSecond * format.Channels * sizeof(float)); + } + + public override void Reset () + { + m_reader.DecodedTime = TimeSpan.FromSeconds (0); + } + + // This buffer can be static because it can only be used by 1 instance per thread + [ThreadStatic] + static float[] _conversionBuffer = null; + + public override int Read(byte[] buffer, int offset, int count) + { + // adjust count so it is in floats instead of bytes + count /= sizeof(float); + + // make sure we don't have an odd count + count -= count % m_reader.Channels; + + // get the buffer, creating a new one if none exists or the existing one is too small + var cb = _conversionBuffer ?? (_conversionBuffer = new float[count]); + if (cb.Length < count) + { + cb = (_conversionBuffer = new float[count]); + } + + // let ReadSamples(float[], int, int) do the actual reading; adjust count back to bytes + int cnt = m_reader.ReadSamples (cb, 0, count) * sizeof(float); + + // move the data back to the request buffer + Buffer.BlockCopy (cb, 0, buffer, offset, cnt); + + // done! + return cnt; + } + } + + [Export(typeof(AudioFormat))] + public class OggAudio : AudioFormat + { + public override string Tag { get { return "OGG"; } } + public override string Description { get { return "Ogg/Vorbis audio format"; } } + public override uint Signature { get { return 0x5367674f; } } // 'OggS' + + public override SoundInput TryOpen (Stream file) + { + return new OggInput (file); + } + } +} diff --git a/ArcFormats/packages.config b/ArcFormats/packages.config new file mode 100644 index 00000000..7617a722 --- /dev/null +++ b/ArcFormats/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file