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