diff --git a/.gitignore b/.gitignore
index 28e479b..253e96e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,4 @@ obj/
[Rr]elease*/
_ReSharper*/
[Tt]est[Rr]esult*
+*.userprefs
diff --git a/OggDecoder/OggDecodeStream.cs b/OggDecoder/OggDecodeStream.cs
deleted file mode 100644
index b2c930a..0000000
--- a/OggDecoder/OggDecodeStream.cs
+++ /dev/null
@@ -1,436 +0,0 @@
-using System;
-using System.IO;
-using System.Diagnostics;
-using System.Text;
-
-using csogg;
-using csvorbis;
-
-namespace OggDecoder
-{
- public class OggDecodeStream : Stream
- {
- class DebugWriter : TextWriter
- {
- public override Encoding Encoding
- {
- get { return Encoding.UTF8; }
- }
-
- public override void WriteLine()
- {
- Debug.WriteLine(String.Empty);
- }
-
- public override void WriteLine(string s)
- {
- Debug.WriteLine(s);
- }
- }
-
- private Stream decodedStream;
- private const int HEADER_SIZE = 36;
-
- public OggDecodeStream(Stream input, bool skipWavHeader)
- {
- if (input == null)
- throw new ArgumentNullException("input");
- decodedStream = DecodeStream(input, skipWavHeader);
- }
-
- public OggDecodeStream(Stream input):this(input, false)
- {
- }
-
- Stream DecodeStream(Stream input, bool skipWavHeader)
- {
- int convsize=4096*2;
- byte[] convbuffer=new byte[convsize]; // take 8k out of the data segment, not the stack
-
- TextWriter s_err = new DebugWriter();
- Stream output = new MemoryStream();
-
- if(!skipWavHeader)
- output.Seek(HEADER_SIZE, SeekOrigin.Begin); // reserve place for WAV header
-
- SyncState oy = new SyncState(); // sync and verify incoming physical bitstream
- StreamState os = new StreamState(); // take physical pages, weld into a logical stream of packets
- Page og = new Page(); // one Ogg bitstream page. Vorbis packets are inside
- Packet op = new Packet(); // one raw packet of data for decode
-
- Info vi = new Info(); // struct that stores all the static vorbis bitstream settings
- Comment vc = new Comment(); // struct that stores all the bitstream user comments
- DspState vd = new DspState(); // central working state for the packet->PCM decoder
- Block vb = new Block(vd); // local working space for packet->PCM decode
-
- byte[] buffer;
- int bytes = 0;
-
- // Decode setup
-
- oy.init(); // Now we can read pages
-
- while (true)
- { // we repeat if the bitstream is chained
- int eos = 0;
-
- // grab some data at the head of the stream. We want the first page
- // (which is guaranteed to be small and only contain the Vorbis
- // stream initial header) We need the first page to get the stream
- // serialno.
-
- // submit a 4k block to libvorbis' Ogg layer
- int index = oy.buffer(4096);
- buffer = oy.data;
- try
- {
- bytes = input.Read(buffer, index, 4096);
- }
- catch (Exception e)
- {
- s_err.WriteLine(e);
- }
- oy.wrote(bytes);
-
- // Get the first page.
- if (oy.pageout(og) != 1)
- {
- // have we simply run out of data? If so, we're done.
- if (bytes < 4096) break;
-
- // error case. Must not be Vorbis data
- s_err.WriteLine("Input does not appear to be an Ogg bitstream.");
- }
-
- // Get the serial number and set up the rest of decode.
- // serialno first; use it to set up a logical stream
- os.init(og.serialno());
-
- // extract the initial header from the first page and verify that the
- // Ogg bitstream is in fact Vorbis data
-
- // I handle the initial header first instead of just having the code
- // read all three Vorbis headers at once because reading the initial
- // header is an easy way to identify a Vorbis bitstream and it's
- // useful to see that functionality seperated out.
-
- vi.init();
- vc.init();
- if (os.pagein(og) < 0)
- {
- // error; stream version mismatch perhaps
- s_err.WriteLine("Error reading first page of Ogg bitstream data.");
- }
-
- if (os.packetout(op) != 1)
- {
- // no page? must not be vorbis
- s_err.WriteLine("Error reading initial header packet.");
- }
-
- if (vi.synthesis_headerin(vc, op) < 0)
- {
- // error case; not a vorbis header
- s_err.WriteLine("This Ogg bitstream does not contain Vorbis audio data.");
- }
-
- // At this point, we're sure we're Vorbis. We've set up the logical
- // (Ogg) bitstream decoder. Get the comment and codebook headers and
- // set up the Vorbis decoder
-
- // The next two packets in order are the comment and codebook headers.
- // They're likely large and may span multiple pages. Thus we reead
- // and submit data until we get our two pacakets, watching that no
- // pages are missing. If a page is missing, error out; losing a
- // header page is the only place where missing data is fatal. */
-
- int i = 0;
-
- while (i < 2)
- {
- while (i < 2)
- {
-
- int result = oy.pageout(og);
- if (result == 0) break; // Need more data
- // Don't complain about missing or corrupt data yet. We'll
- // catch it at the packet output phase
-
- if (result == 1)
- {
- os.pagein(og); // we can ignore any errors here
- // as they'll also become apparent
- // at packetout
- while (i < 2)
- {
- result = os.packetout(op);
- if (result == 0) break;
- if (result == -1)
- {
- // Uh oh; data at some point was corrupted or missing!
- // We can't tolerate that in a header. Die.
- s_err.WriteLine("Corrupt secondary header. Exiting.");
- }
- vi.synthesis_headerin(vc, op);
- i++;
- }
- }
- }
- // no harm in not checking before adding more
- index = oy.buffer(4096);
- buffer = oy.data;
- try
- {
- bytes = input.Read(buffer, index, 4096);
- }
- catch (Exception e)
- {
- s_err.WriteLine(e);
- }
- if (bytes == 0 && i < 2)
- {
- s_err.WriteLine("End of file before finding all Vorbis headers!");
- }
- oy.wrote(bytes);
- }
-
- // Throw the comments plus a few lines about the bitstream we're
- // decoding
- {
- byte[][] ptr = vc.user_comments;
- for (int j = 0; j < vc.user_comments.Length; j++)
- {
- if (ptr[j] == null) break;
- s_err.WriteLine(vc.getComment(j));
- }
- s_err.WriteLine("\nBitstream is " + vi.channels + " channel, " + vi.rate + "Hz");
- s_err.WriteLine("Encoded by: " + vc.getVendor() + "\n");
- }
-
- convsize = 4096 / vi.channels;
-
- // OK, got and parsed all three headers. Initialize the Vorbis
- // packet->PCM decoder.
- vd.synthesis_init(vi); // central decode state
- vb.init(vd); // local state for most of the decode
-
- // so multiple block decodes can
- // proceed in parallel. We could init
- // multiple vorbis_block structures
- // for vd here
-
- float[][][] _pcm = new float[1][][];
- int[] _index = new int[vi.channels];
- // The rest is just a straight decode loop until end of stream
- while (eos == 0)
- {
- while (eos == 0)
- {
-
- int result = oy.pageout(og);
- if (result == 0) break; // need more data
- if (result == -1)
- { // missing or corrupt data at this page position
- s_err.WriteLine("Corrupt or missing data in bitstream; continuing...");
- }
- else
- {
- os.pagein(og); // can safely ignore errors at
- // this point
- while (true)
- {
- result = os.packetout(op);
-
- if (result == 0) break; // need more data
- if (result == -1)
- { // missing or corrupt data at this page position
- // no reason to complain; already complained above
- }
- else
- {
- // we have a packet. Decode it
- int samples;
- if (vb.synthesis(op) == 0)
- { // test for success!
- vd.synthesis_blockin(vb);
- }
-
- // **pcm is a multichannel float vector. In stereo, for
- // example, pcm[0] is left, and pcm[1] is right. samples is
- // the size of each channel. Convert the float values
- // (-1.<=range<=1.) to whatever PCM format and write it out
-
- while ((samples = vd.synthesis_pcmout(_pcm, _index)) > 0)
- {
- float[][] pcm = _pcm[0];
- bool clipflag = false;
- int bout = (samples < convsize ? samples : convsize);
-
- // convert floats to 16 bit signed ints (host order) and
- // interleave
- for (i = 0; i < vi.channels; i++)
- {
- int ptr = i * 2;
- //int ptr=i;
- int mono = _index[i];
- for (int j = 0; j < bout; j++)
- {
- int val = (int)(pcm[i][mono + j] * 32767.0);
- // short val=(short)(pcm[i][mono+j]*32767.);
- // int val=(int)Math.round(pcm[i][mono+j]*32767.);
- // might as well guard against clipping
- if (val > 32767)
- {
- val = 32767;
- clipflag = true;
- }
- if (val < -32768)
- {
- val = -32768;
- clipflag = true;
- }
- if (val < 0) val = val | 0x8000;
- convbuffer[ptr] = (byte)(val);
- convbuffer[ptr + 1] = (byte)((uint)val >> 8);
- ptr += 2 * (vi.channels);
- }
- }
-
- if (clipflag)
- {
- //s_err.WriteLine("Clipping in frame "+vd.sequence);
- }
-
- output.Write(convbuffer, 0, 2 * vi.channels * bout);
-
- vd.synthesis_read(bout); // tell libvorbis how
- // many samples we
- // actually consumed
- }
- }
- }
- if (og.eos() != 0) eos = 1;
- }
- }
- if (eos == 0)
- {
- index = oy.buffer(4096);
- buffer = oy.data;
- try
- {
- bytes = input.Read(buffer, index, 4096);
- }
- catch (Exception e)
- {
- s_err.WriteLine(e);
- }
- oy.wrote(bytes);
- if (bytes == 0) eos = 1;
- }
- }
-
- // clean up this logical bitstream; before exit we see if we're
- // followed by another [chained]
-
- os.clear();
-
- // ogg_page and ogg_packet structs always point to storage in
- // libvorbis. They're never freed or manipulated directly
-
- vb.clear();
- vd.clear();
- vi.clear(); // must be called last
- }
-
- // OK, clean up the framer
- oy.clear();
- s_err.WriteLine("Done.");
-
- output.Seek(0, SeekOrigin.Begin);
- if (!skipWavHeader)
- {
- WriteHeader(output, (int)(output.Length - HEADER_SIZE), vi.rate, (ushort)16, (ushort)vi.channels);
- output.Seek(0, SeekOrigin.Begin);
- }
- return output;
- }
-
- void WriteHeader(Stream stream, int length, int audioSampleRate, ushort audioBitsPerSample, ushort audioChannels)
- {
- BinaryWriter bw = new BinaryWriter(stream);
-
- bw.Write(new char[4] { 'R', 'I', 'F', 'F' });
- int fileSize = HEADER_SIZE + length;
- bw.Write(fileSize);
- bw.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
- bw.Write((int)16);
- bw.Write((short)1);
- bw.Write((short)audioChannels);
- bw.Write(audioSampleRate);
- bw.Write((int)(audioSampleRate * ((audioBitsPerSample * audioChannels) / 8)));
- bw.Write((short)((audioBitsPerSample * audioChannels) / 8));
- bw.Write((short)audioBitsPerSample);
-
- bw.Write(new char[4] { 'd', 'a', 't', 'a' });
- bw.Write(length);
- }
-
-
- public override bool CanRead
- {
- get { return true; }
- }
-
- public override bool CanSeek
- {
- get { return true; }
- }
-
- public override bool CanWrite
- {
- get { return false; }
- }
-
- public override void Flush()
- {
- throw new NotImplementedException();
- }
-
- public override long Length
- {
- get { return decodedStream.Length; }
- }
-
- public override long Position
- {
- get
- {
- return decodedStream.Position;
- }
- set
- {
- decodedStream.Position = value;
- }
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- return decodedStream.Read(buffer, offset, count);
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- return Seek(offset, origin);
- }
-
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/OggDecoder/OggDecoder.cs b/OggDecoder/OggDecoder.cs
deleted file mode 100644
index 491aec3..0000000
--- a/OggDecoder/OggDecoder.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.IO;
-using csogg;
-using csvorbis;
-
-namespace OggDecoder
-{
- ///
- /// Ogg Vorbis decoder test application.
- ///
- class Decoder
- {
- ///
- /// The main entry point for the application.
- ///
- //[STAThread]
- static void Main(string[] args)
- {
- TextWriter s_err = Console.Error;
- FileStream input = null, output = null;
-
- if(args.Length == 2)
- {
- try
- {
- input = new FileStream(args[0], FileMode.Open, FileAccess.Read);
- output = new FileStream(args[1], FileMode.OpenOrCreate);
- }
- catch(Exception e)
- {
- s_err.WriteLine(e);
- }
- }
- else
- {
- return;
- }
-
- OggDecodeStream decode = new OggDecodeStream(input, true);
-
- byte[] buffer = new byte[4096];
- int read;
- while ((read = decode.Read(buffer, 0, buffer.Length)) > 0)
- {
- output.Write(buffer, 0, read);
- }
-
- // Close some files
- input.Close();
- output.Close();
- }
- }
-}
-
diff --git a/OggDecoder/OggDecoder.csproj.user b/OggDecoder/OggDecoder.csproj.user
deleted file mode 100644
index 4a3636a..0000000
--- a/OggDecoder/OggDecoder.csproj.user
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
- Debug
- AnyCPU
-
-
-
- 0
- ProjectFiles
- 0
-
-
-
-
-
-
- en-US
- false
-
-
- false
- false
- false
- false
- false
-
- Project
-
-
-
-
-
- true
-
-
- false
- false
- false
- false
- false
-
- Project
-
-
-
-
-
- true
-
-
\ No newline at end of file
diff --git a/OggDecoder/OggPlayer.cs b/OggDecoder/OggPlayer.cs
deleted file mode 100644
index 534f81c..0000000
--- a/OggDecoder/OggPlayer.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using System.Text;
-using System.Media;
-using System.IO;
-
-namespace OggDecoder
-{
- class OggPlayer
- {
- static void Main(string[] args)
- {
- using (var file = new FileStream(args[0], FileMode.Open, FileAccess.Read))
- {
- var player = new SoundPlayer(new OggDecodeStream(file));
- player.PlaySync();
- }
- }
- }
-}
diff --git a/OggDecoder/App.ico b/OggTools/App.ico
similarity index 100%
rename from OggDecoder/App.ico
rename to OggTools/App.ico
diff --git a/OggDecoder/AssemblyInfo.cs b/OggTools/AssemblyInfo.cs
similarity index 95%
rename from OggDecoder/AssemblyInfo.cs
rename to OggTools/AssemblyInfo.cs
index 49a78fd..383da1f 100644
--- a/OggDecoder/AssemblyInfo.cs
+++ b/OggTools/AssemblyInfo.cs
@@ -1,78 +1,77 @@
-/* csvorbis
- * Copyright (C) 2002 Mark Crichton
- *
- * Written by: Mark Crichton
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License
- * as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+/* csvorbis
+ * Copyright (C) 2002 Mark Crichton
+ *
+ * Written by: Mark Crichton
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-//
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-//
-[assembly: AssemblyTitle("OggDecode")]
-[assembly: AssemblyDescription("csVorbis Test Application")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("LGPL")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-//
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-
-[assembly: AssemblyVersion("1.0.*")]
-
-//
-// In order to sign your assembly you must specify a key to use. Refer to the
-// Microsoft .NET Framework documentation for more information on assembly signing.
-//
-// Use the attributes below to control which key is used for signing.
-//
-// Notes:
-// (*) If no key is specified, the assembly is not signed.
-// (*) KeyName refers to a key that has been installed in the Crypto Service
-// Provider (CSP) on your machine. KeyFile refers to a file which contains
-// a key.
-// (*) If the KeyFile and the KeyName values are both specified, the
-// following processing occurs:
-// (1) If the KeyName can be found in the CSP, that key is used.
-// (2) If the KeyName does not exist and the KeyFile does exist, the key
-// in the KeyFile is installed into the CSP and used.
-// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
-// When specifying the KeyFile, the location of the KeyFile should be
-// relative to the project output directory which is
-// %Project Directory%\obj\. For example, if your KeyFile is
-// located in the project directory, you would specify the AssemblyKeyFile
-// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
-// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
-// documentation for more information on this.
-//
-[assembly: AssemblyDelaySign(false)]
-[assembly: AssemblyKeyFile("")]
-[assembly: AssemblyKeyName("")]
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("OggTools")]
+[assembly: AssemblyDescription("csVorbis Test Application")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("LGPL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/OggTools/DebugWriter.cs b/OggTools/DebugWriter.cs
new file mode 100644
index 0000000..8242fba
--- /dev/null
+++ b/OggTools/DebugWriter.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Diagnostics;
+
+namespace OggTools
+{
+ class DebugWriter
+ {
+ [Conditional("DEBUG")]
+ public void WriteLine()
+ {
+ Debug.WriteLine(String.Empty);
+ }
+
+ [Conditional("DEBUG")]
+ public void WriteLine(string s)
+ {
+ Debug.WriteLine(s);
+ }
+
+ [Conditional("DEBUG")]
+ public void WriteLine(object o)
+ {
+ Debug.WriteLine(o.ToString());
+ }
+ }
+}
+
diff --git a/OggDecoder/Makefile b/OggTools/Makefile
similarity index 100%
rename from OggDecoder/Makefile
rename to OggTools/Makefile
diff --git a/OggTools/OggDecodeStream.cs b/OggTools/OggDecodeStream.cs
new file mode 100644
index 0000000..9a6c881
--- /dev/null
+++ b/OggTools/OggDecodeStream.cs
@@ -0,0 +1,86 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Text;
+
+using csogg;
+using csvorbis;
+
+namespace OggTools
+{
+ public class OggDecodeStream : Stream
+ {
+ private Stream decodedStream;
+
+ public OggDecodeStream(Stream input, bool skipWavHeader)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+
+ decodedStream = new MemoryStream();
+ OggDecoder.DecodeStream(input, decodedStream, !skipWavHeader);
+ decodedStream.Seek(0, SeekOrigin.Begin);
+ }
+
+ public OggDecodeStream(Stream input) : this(input, false)
+ {
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return true; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return false; }
+ }
+
+ public override void Flush()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override long Length
+ {
+ get { return decodedStream.Length; }
+ }
+
+ public override long Position
+ {
+ get
+ {
+ return decodedStream.Position;
+ }
+ set
+ {
+ decodedStream.Position = value;
+ }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return decodedStream.Read(buffer, offset, count);
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return Seek(offset, origin);
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/OggTools/OggDecoder.cs b/OggTools/OggDecoder.cs
new file mode 100644
index 0000000..62f7d7f
--- /dev/null
+++ b/OggTools/OggDecoder.cs
@@ -0,0 +1,352 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Text;
+
+using csogg;
+using csvorbis;
+
+namespace OggTools
+{
+ public static class OggDecoder
+ {
+ private const int HEADER_SIZE = 36;
+
+ ///
+ /// Decodes a stream of Ogg Vorbis data into wav file format.
+ ///
+ ///
+ /// A MemoryStream with the entire decoded stream.
+ ///
+ ///
+ /// Ogg Vorbis data to be decoded
+ ///
+ ///
+ /// Stream to write wav data.
+ /// If writeWavHeader is true then this stream must be seekable.
+ ///
+ ///
+ /// Write wav header in the beginning of the returned stream.
+ ///
+ public static void DecodeStream(Stream input, Stream output, bool writeWavHeader)
+ {
+ int convsize = 4096 * 2;
+ byte[] convbuffer = new byte[convsize]; // take 8k out of the data segment, not the stack
+ long start = output.Position;
+
+ DebugWriter s_err = new DebugWriter();
+
+ if (writeWavHeader && !output.CanSeek)
+ throw new ArgumentException("To write wav header, the output stream must be seekable.", "output");
+
+ if (writeWavHeader)
+ output.Seek(HEADER_SIZE, SeekOrigin.Current); // reserve place for WAV header
+
+ SyncState oy = new SyncState(); // sync and verify incoming physical bitstream
+ StreamState os = new StreamState(); // take physical pages, weld into a logical stream of packets
+ Page og = new Page(); // one Ogg bitstream page. Vorbis packets are inside
+ Packet op = new Packet(); // one raw packet of data for decode
+
+ Info vi = new Info(); // struct that stores all the static vorbis bitstream settings
+ Comment vc = new Comment(); // struct that stores all the bitstream user comments
+ DspState vd = new DspState(); // central working state for the packet->PCM decoder
+ Block vb = new Block(vd); // local working space for packet->PCM decode
+
+ int bytes = 0;
+
+ // Decode setup
+ oy.init(); // Now we can read pages
+
+ // we repeat if the bitstream is chained
+ while (true)
+ {
+ int eos = 0;
+
+ // grab some data at the head of the stream. We want the first page
+ // (which is guaranteed to be small and only contain the Vorbis
+ // stream initial header) We need the first page to get the stream
+ // serialno.
+
+ // submit a 4k block to libvorbis' Ogg layer
+ int index = oy.buffer(4096);
+ bytes = input.Read(oy.data, index, 4096);
+ oy.wrote(bytes);
+
+ // Get the first page.
+ if (oy.pageout(og) != 1)
+ {
+ // have we simply run out of data? If so, we're done.
+ if (bytes < 4096)
+ break;
+
+ // error case. Must not be Vorbis data
+ s_err.WriteLine("Input does not appear to be an Ogg bitstream.");
+ }
+
+ // Get the serial number and set up the rest of decode.
+ // serialno first; use it to set up a logical stream
+ os.init(og.serialno());
+
+ // extract the initial header from the first page and verify that the
+ // Ogg bitstream is in fact Vorbis data
+
+ // I handle the initial header first instead of just having the code
+ // read all three Vorbis headers at once because reading the initial
+ // header is an easy way to identify a Vorbis bitstream and it's
+ // useful to see that functionality seperated out.
+
+ vi.init();
+ vc.init();
+ if (os.pagein(og) < 0)
+ {
+ // error; stream version mismatch perhaps
+ s_err.WriteLine("Error reading first page of Ogg bitstream data.");
+ }
+
+ if (os.packetout(op) != 1)
+ {
+ // no page? must not be vorbis
+ s_err.WriteLine("Error reading initial header packet.");
+ }
+
+ if (vi.synthesis_headerin(vc, op) < 0)
+ {
+ // error case; not a vorbis header
+ s_err.WriteLine("This Ogg bitstream does not contain Vorbis audio data.");
+ }
+
+ // At this point, we're sure we're Vorbis. We've set up the logical
+ // (Ogg) bitstream decoder. Get the comment and codebook headers and
+ // set up the Vorbis decoder
+
+ // The next two packets in order are the comment and codebook headers.
+ // They're likely large and may span multiple pages. Thus we reead
+ // and submit data until we get our two pacakets, watching that no
+ // pages are missing. If a page is missing, error out; losing a
+ // header page is the only place where missing data is fatal. */
+
+ int i = 0;
+
+ while (i < 2)
+ {
+ while (i < 2)
+ {
+
+ int result = oy.pageout(og);
+ if (result == 0)
+ break; // Need more data
+ // Don't complain about missing or corrupt data yet. We'll
+ // catch it at the packet output phase
+
+ if (result == 1)
+ {
+ os.pagein(og); // we can ignore any errors here
+ // as they'll also become apparent
+ // at packetout
+ while (i < 2)
+ {
+ result = os.packetout(op);
+ if (result == 0)
+ break;
+ if (result == -1)
+ {
+ // Uh oh; data at some point was corrupted or missing!
+ // We can't tolerate that in a header. Die.
+ s_err.WriteLine("Corrupt secondary header. Exiting.");
+ }
+ vi.synthesis_headerin(vc, op);
+ i++;
+ }
+ }
+ }
+ // no harm in not checking before adding more
+ index = oy.buffer(4096);
+ bytes = input.Read(oy.data, index, 4096);
+ if (bytes == 0 && i < 2)
+ {
+ s_err.WriteLine("End of file before finding all Vorbis headers!");
+ }
+ oy.wrote(bytes);
+ }
+
+ // Throw the comments plus a few lines about the bitstream we're
+ // decoding
+ {
+ byte[][] ptr = vc.user_comments;
+ for (int j = 0; j < vc.user_comments.Length; j++)
+ {
+ if (ptr [j] == null)
+ break;
+ s_err.WriteLine(vc.getComment(j));
+ }
+ s_err.WriteLine("\nBitstream is " + vi.channels + " channel, " + vi.rate + "Hz");
+ s_err.WriteLine("Encoded by: " + vc.getVendor() + "\n");
+ }
+
+ convsize = 4096 / vi.channels;
+
+ // OK, got and parsed all three headers. Initialize the Vorbis
+ // packet->PCM decoder.
+ vd.synthesis_init(vi); // central decode state
+ vb.init(vd); // local state for most of the decode
+
+ // so multiple block decodes can
+ // proceed in parallel. We could init
+ // multiple vorbis_block structures
+ // for vd here
+
+ float[][][] _pcm = new float[1][][];
+ int[] _index = new int[vi.channels];
+ // The rest is just a straight decode loop until end of stream
+ while (eos == 0)
+ {
+ while (eos == 0)
+ {
+
+ int result = oy.pageout(og);
+ if (result == 0)
+ break; // need more data
+ if (result == -1)
+ {
+ // missing or corrupt data at this page position
+ s_err.WriteLine("Corrupt or missing data in bitstream; continuing...");
+ } else
+ {
+ os.pagein(og); // can safely ignore errors at
+ // this point
+ while (true)
+ {
+ result = os.packetout(op);
+
+ if (result == 0)
+ break; // need more data
+ if (result == -1)
+ { // missing or corrupt data at this page position
+ // no reason to complain; already complained above
+ } else
+ {
+ // we have a packet. Decode it
+ int samples;
+ if (vb.synthesis(op) == 0)
+ { // test for success!
+ vd.synthesis_blockin(vb);
+ }
+
+ // **pcm is a multichannel float vector. In stereo, for
+ // example, pcm[0] is left, and pcm[1] is right. samples is
+ // the size of each channel. Convert the float values
+ // (-1.<=range<=1.) to whatever PCM format and write it out
+
+ while ((samples = vd.synthesis_pcmout(_pcm, _index)) > 0)
+ {
+ float[][] pcm = _pcm [0];
+ bool clipflag = false;
+ int bout = (samples < convsize ? samples : convsize);
+
+ // convert floats to 16 bit signed ints (host order) and
+ // interleave
+ for (i = 0; i < vi.channels; i++)
+ {
+ int ptr = i * 2;
+ //int ptr=i;
+ int mono = _index [i];
+ for (int j = 0; j < bout; j++)
+ {
+ int val = (int)(pcm [i] [mono + j] * 32767.0);
+ // short val=(short)(pcm[i][mono+j]*32767.);
+ // int val=(int)Math.round(pcm[i][mono+j]*32767.);
+ // might as well guard against clipping
+ if (val > 32767)
+ {
+ val = 32767;
+ clipflag = true;
+ }
+ if (val < -32768)
+ {
+ val = -32768;
+ clipflag = true;
+ }
+ if (val < 0)
+ val = val | 0x8000;
+ convbuffer [ptr] = (byte)(val);
+ convbuffer [ptr + 1] = (byte)((uint)val >> 8);
+ ptr += 2 * (vi.channels);
+ }
+ }
+
+ if (clipflag)
+ {
+ //s_err.WriteLine("Clipping in frame "+vd.sequence);
+ }
+
+ output.Write(convbuffer, 0, 2 * vi.channels * bout);
+
+ vd.synthesis_read(bout); // tell libvorbis how
+ // many samples we
+ // actually consumed
+ }
+ }
+ }
+ if (og.eos() != 0)
+ eos = 1;
+ }
+ }
+ if (eos == 0)
+ {
+ index = oy.buffer(4096);
+ bytes = input.Read(oy.data, index, 4096);
+ oy.wrote(bytes);
+ if (bytes == 0)
+ eos = 1;
+ }
+ }
+
+ // clean up this logical bitstream; before exit we see if we're
+ // followed by another [chained]
+
+ os.clear();
+
+ // ogg_page and ogg_packet structs always point to storage in
+ // libvorbis. They're never freed or manipulated directly
+
+ vb.clear();
+ vd.clear();
+ vi.clear(); // must be called last
+ }
+
+ // OK, clean up the framer
+ oy.clear();
+ s_err.WriteLine("Done.");
+
+ if (writeWavHeader)
+ {
+ long end = output.Position;
+ int length = (int)(end - (start + HEADER_SIZE));
+
+ output.Seek(start, SeekOrigin.Begin);
+ WriteHeader(output, length, vi.rate, (ushort)16, (ushort)vi.channels);
+ output.Seek(end, SeekOrigin.Begin);
+ }
+ }
+
+ static void WriteHeader(Stream stream, int length, int audioSampleRate, ushort audioBitsPerSample, ushort audioChannels)
+ {
+ BinaryWriter bw = new BinaryWriter(stream);
+
+ bw.Write(new char[4] { 'R', 'I', 'F', 'F' });
+ int fileSize = HEADER_SIZE + length;
+ bw.Write(fileSize);
+ bw.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
+ bw.Write((int)16);
+ bw.Write((short)1);
+ bw.Write((short)audioChannels);
+ bw.Write(audioSampleRate);
+ bw.Write((int)(audioSampleRate * ((audioBitsPerSample * audioChannels) / 8)));
+ bw.Write((short)((audioBitsPerSample * audioChannels) / 8));
+ bw.Write((short)audioBitsPerSample);
+
+ bw.Write(new char[4] { 'd', 'a', 't', 'a' });
+ bw.Write(length);
+ }
+ }
+}
diff --git a/OggDecoder/OggDecoder.csproj b/OggTools/OggTools.csproj
similarity index 77%
rename from OggDecoder/OggDecoder.csproj
rename to OggTools/OggTools.csproj
index 948b79f..829aa74 100644
--- a/OggDecoder/OggDecoder.csproj
+++ b/OggTools/OggTools.csproj
@@ -10,14 +10,13 @@
App.ico
OggDecoder
-
JScript
Grid
IE50
false
Exe
- OggDecoder
- OggDecoder.Decoder
+ OggTools
+ OggTools.Program
v2.0
@@ -41,9 +40,7 @@
bin\Debug\
- false
285212672
- false
DEBUG;TRACE
@@ -52,7 +49,6 @@
false
false
false
- false
4
full
prompt
@@ -60,18 +56,14 @@
bin\Release\
- false
285212672
- false
TRACE
- false
4096
true
false
false
- false
4
none
prompt
@@ -81,12 +73,10 @@
csogg
{FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}
- {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
csvorbis
{0087C0AF-E896-4C55-A999-5245560BCBE3}
- {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
System
@@ -96,12 +86,13 @@
Code
-
- Code
-
-
+
+ Code
+
+
+
@@ -125,4 +116,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OggTools/Program.cs b/OggTools/Program.cs
new file mode 100644
index 0000000..ef396ed
--- /dev/null
+++ b/OggTools/Program.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using csogg;
+using csvorbis;
+using System.Media;
+
+namespace OggTools
+{
+ ///
+ /// Ogg Vorbis decoder test application.
+ ///
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ try
+ {
+ if (args.Length == 1)
+ Play(args [0]);
+ else if (args.Length == 2)
+ Decode(args [0], args [1]);
+ } catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ }
+ }
+
+ static void Play(string path)
+ {
+ using (var file = new FileStream(path, FileMode.Open, FileAccess.Read))
+ {
+ var player = new SoundPlayer(new OggDecodeStream(file));
+ player.PlaySync();
+ }
+
+ }
+
+ static void Decode(String inputPath, string outputPath)
+ {
+ using (FileStream input = new FileStream(inputPath, FileMode.Open, FileAccess.Read))
+ using (FileStream output = new FileStream(outputPath, FileMode.OpenOrCreate))
+ {
+ OggDecoder.DecodeStream(input, output, true);
+ }
+ }
+ }
+}
+
diff --git a/csogg/csogg.csproj b/csogg/csogg.csproj
index 126d10a..237278a 100644
--- a/csogg/csogg.csproj
+++ b/csogg/csogg.csproj
@@ -7,17 +7,14 @@
{FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}
Debug
AnyCPU
-
csogg
-
JScript
Grid
IE50
false
Library
csogg
-
v2.0
@@ -41,9 +38,7 @@
bin\Debug\
- false
285212672
- false
DEBUG;TRACE
@@ -52,7 +47,6 @@
false
false
false
- false
4
full
prompt
@@ -60,18 +54,14 @@
bin\Release\
- false
285212672
- false
TRACE
- false
4096
true
false
false
- false
4
none
prompt
@@ -130,4 +120,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/csvorbis.sln b/csvorbis.sln
index a518c05..d6567e3 100644
--- a/csvorbis.sln
+++ b/csvorbis.sln
@@ -1,10 +1,11 @@
+
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csogg", "csogg\csogg.csproj", "{FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csvorbis", "csvorbis\csvorbis.csproj", "{0087C0AF-E896-4C55-A999-5245560BCBE3}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OggDecoder", "OggDecoder\OggDecoder.csproj", "{4CA9EB23-E111-4DAD-9932-F73E8E6C54C5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OggTools", "OggTools\OggTools.csproj", "{4CA9EB23-E111-4DAD-9932-F73E8E6C54C5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -12,10 +13,6 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Release|Any CPU.Build.0 = Release|Any CPU
{0087C0AF-E896-4C55-A999-5245560BCBE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0087C0AF-E896-4C55-A999-5245560BCBE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0087C0AF-E896-4C55-A999-5245560BCBE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -24,6 +21,41 @@ Global
{4CA9EB23-E111-4DAD-9932-F73E8E6C54C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CA9EB23-E111-4DAD-9932-F73E8E6C54C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CA9EB23-E111-4DAD-9932-F73E8E6C54C5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = OggTools\OggTools.csproj
+ Policies = $0
+ $0.TextStylePolicy = $1
+ $1.inheritsSet = VisualStudio
+ $1.inheritsScope = text/plain
+ $1.scope = text/x-csharp
+ $0.CSharpFormattingPolicy = $2
+ $2.IndentSwitchBody = True
+ $2.AnonymousMethodBraceStyle = NextLine
+ $2.PropertyBraceStyle = NextLine
+ $2.PropertyGetBraceStyle = NextLine
+ $2.PropertySetBraceStyle = NextLine
+ $2.EventBraceStyle = NextLine
+ $2.EventAddBraceStyle = NextLine
+ $2.EventRemoveBraceStyle = NextLine
+ $2.StatementBraceStyle = NextLine
+ $2.ArrayInitializerBraceStyle = NextLine
+ $2.BeforeMethodDeclarationParentheses = False
+ $2.BeforeMethodCallParentheses = False
+ $2.BeforeConstructorDeclarationParentheses = False
+ $2.BeforeDelegateDeclarationParentheses = False
+ $2.NewParentheses = False
+ $2.inheritsSet = Mono
+ $2.inheritsScope = text/x-csharp
+ $2.scope = text/x-csharp
+ $0.TextStylePolicy = $3
+ $3.inheritsSet = VisualStudio
+ $3.inheritsScope = text/plain
+ $3.scope = text/plain
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/csvorbis/csvorbis.csproj b/csvorbis/csvorbis.csproj
index f3bdfc8..4546bb5 100644
--- a/csvorbis/csvorbis.csproj
+++ b/csvorbis/csvorbis.csproj
@@ -7,17 +7,14 @@
{0087C0AF-E896-4C55-A999-5245560BCBE3}
Debug
AnyCPU
-
csvorbis
-
JScript
Grid
IE50
false
Library
csvorbis
-
v2.0
@@ -41,9 +38,7 @@
bin\Debug\
- false
285212672
- false
DEBUG;TRACE
@@ -52,7 +47,6 @@
false
false
false
- false
4
full
prompt
@@ -60,18 +54,14 @@
bin\Release\
- false
285212672
- false
TRACE
- false
4096
true
false
false
- false
4
none
prompt
@@ -81,7 +71,6 @@
csogg
{FA4ACE8B-CDEE-41A3-92D7-C73069B84B83}
- {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
System
@@ -210,4 +199,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file