diff --git a/ClassicalSharp.sln b/ClassicalSharp.sln
index 7dffc9c28..728f84106 100644
--- a/ClassicalSharp.sln
+++ b/ClassicalSharp.sln
@@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteropPatcher", "InteropPa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher2", "Launcher2\Launcher2.csproj", "{3E84ACC1-27B4-401B-A359-6AAE4DF6C9B5}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpWave", "SharpWave\SharpWave.csproj", "{77EA9D1E-4995-4D05-A9C7-29173CB5DC72}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -40,6 +42,14 @@ Global
{3E84ACC1-27B4-401B-A359-6AAE4DF6C9B5}.Debug_DX|Any CPU.ActiveCfg = Debug|Any CPU
{3E84ACC1-27B4-401B-A359-6AAE4DF6C9B5}.Release_DX|Any CPU.Build.0 = Release|Any CPU
{3E84ACC1-27B4-401B-A359-6AAE4DF6C9B5}.Release_DX|Any CPU.ActiveCfg = Release|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Release|Any CPU.Build.0 = Release|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Debug_DX|Any CPU.Build.0 = Debug|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Debug_DX|Any CPU.ActiveCfg = Debug|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Release_DX|Any CPU.Build.0 = Debug|Any CPU
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}.Release_DX|Any CPU.ActiveCfg = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs
index 5bf8c160d..08cd25a09 100644
--- a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs
+++ b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs
@@ -1,156 +1,153 @@
-// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
-using System;
-using System.Threading;
-using ClassicalSharp.Events;
-using SharpWave;
-using SharpWave.Codecs;
-
-namespace ClassicalSharp.Audio {
-
- public sealed partial class AudioPlayer {
-
- Soundboard digBoard, stepBoard;
- const int maxSounds = 6;
-
- public void SetSounds(int volume) {
- if (volume > 0) InitSound();
- else DisposeSound();
- }
-
- void InitSound() {
- if (digBoard == null) InitSoundboards();
- monoOutputs = new IAudioOutput[maxSounds];
- stereoOutputs = new IAudioOutput[maxSounds];
- }
-
- void InitSoundboards() {
- digBoard = new Soundboard();
- digBoard.Init("dig_", files);
- stepBoard = new Soundboard();
- stepBoard.Init("step_", files);
- }
-
- void PlayBlockSound(object sender, BlockChangedEventArgs e) {
- if (e.Block == 0) {
- PlayDigSound(BlockInfo.DigSounds[e.OldBlock]);
- } else if (!game.ClassicMode) {
- PlayDigSound(BlockInfo.StepSounds[e.Block]);
- }
- }
-
- public void PlayDigSound(byte type) { PlaySound(type, digBoard); }
-
- public void PlayStepSound(byte type) { PlaySound(type, stepBoard); }
-
- AudioChunk chunk = new AudioChunk();
- void PlaySound(byte type, Soundboard board) {
- if (type == SoundType.None || monoOutputs == null) return;
- Sound snd = board.PickRandomSound(type);
- if (snd == null) return;
-
- chunk.Channels = snd.Channels;
- chunk.BitsPerSample = snd.BitsPerSample;
- chunk.BytesOffset = 0;
- chunk.BytesUsed = snd.Data.Length;
- chunk.Data = snd.Data;
-
- float volume = game.SoundsVolume / 100.0f;
- if (board == digBoard) {
- if (type == SoundType.Metal) chunk.SampleRate = (snd.SampleRate * 6) / 5;
- else chunk.SampleRate = (snd.SampleRate * 4) / 5;
- } else {
- volume *= 0.50f;
-
- if (type == SoundType.Metal) chunk.SampleRate = (snd.SampleRate * 7) / 5;
- else chunk.SampleRate = snd.SampleRate;
- }
-
- if (snd.Channels == 1) {
- PlayCurrentSound(monoOutputs, volume);
- } else if (snd.Channels == 2) {
- PlayCurrentSound(stereoOutputs, volume);
- }
- }
-
- IAudioOutput firstSoundOut;
- void PlayCurrentSound(IAudioOutput[] outputs, float volume) {
- for (int i = 0; i < monoOutputs.Length; i++) {
- IAudioOutput output = outputs[i];
- if (output == null) output = MakeSoundOutput(outputs, i);
- if (!output.DoneRawAsync()) continue;
-
- LastChunk l = output.Last;
- if (l.Channels == 0 || (l.Channels == chunk.Channels && l.BitsPerSample == chunk.BitsPerSample
- && l.SampleRate == chunk.SampleRate)) {
- PlaySound(output, volume); return;
- }
- }
-
- // This time we try to play the sound on all possible devices,
- // even if it requires the expensive case of recreating a device
- for (int i = 0; i < monoOutputs.Length; i++) {
- IAudioOutput output = outputs[i];
- if (!output.DoneRawAsync()) continue;
-
- PlaySound(output, volume); return;
- }
- }
-
-
- IAudioOutput MakeSoundOutput(IAudioOutput[] outputs, int i) {
- IAudioOutput output = GetPlatformOut();
- output.Create(1, firstSoundOut);
- if (firstSoundOut == null)
- firstSoundOut = output;
-
- outputs[i] = output;
- return output;
- }
-
- void PlaySound(IAudioOutput output, float volume) {
- try {
- output.SetVolume(volume);
- output.PlayRawAsync(chunk);
- } catch (InvalidOperationException ex) {
- ErrorHandler.LogError("AudioPlayer.PlayCurrentSound()", ex);
- if (ex.Message == "No audio devices found")
- game.Chat.Add("&cNo audio devices found, disabling sounds.");
- else
- game.Chat.Add("&cAn error occured when trying to play sounds, disabling sounds.");
-
- SetSounds(0);
- game.SoundsVolume = 0;
- }
- }
-
- void DisposeSound() {
- DisposeOutputs(ref monoOutputs);
- DisposeOutputs(ref stereoOutputs);
- if (firstSoundOut != null) {
- firstSoundOut.Dispose();
- firstSoundOut = null;
- }
- }
-
- void DisposeOutputs(ref IAudioOutput[] outputs) {
- if (outputs == null) return;
- bool soundPlaying = true;
-
- while (soundPlaying) {
- soundPlaying = false;
- for (int i = 0; i < outputs.Length; i++) {
- if (outputs[i] == null) continue;
- soundPlaying |= !outputs[i].DoneRawAsync();
- }
- if (soundPlaying)
- Thread.Sleep(1);
- }
-
- for (int i = 0; i < outputs.Length; i++) {
- if (outputs[i] == null || outputs[i] == firstSoundOut) continue;
- outputs[i].Dispose();
- }
- outputs = null;
- }
- }
-}
+// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
+using System;
+using System.Threading;
+using ClassicalSharp.Events;
+using SharpWave;
+using SharpWave.Codecs;
+
+namespace ClassicalSharp.Audio {
+
+ public sealed partial class AudioPlayer {
+
+ Soundboard digBoard, stepBoard;
+ const int maxSounds = 6;
+
+ public void SetSounds(int volume) {
+ if (volume > 0) InitSound();
+ else DisposeSound();
+ }
+
+ void InitSound() {
+ if (digBoard == null) InitSoundboards();
+ monoOutputs = new IAudioOutput[maxSounds];
+ stereoOutputs = new IAudioOutput[maxSounds];
+ }
+
+ void InitSoundboards() {
+ digBoard = new Soundboard();
+ digBoard.Init("dig_", files);
+ stepBoard = new Soundboard();
+ stepBoard.Init("step_", files);
+ }
+
+ void PlayBlockSound(object sender, BlockChangedEventArgs e) {
+ if (e.Block == 0) {
+ PlayDigSound(BlockInfo.DigSounds[e.OldBlock]);
+ } else if (!game.ClassicMode) {
+ PlayDigSound(BlockInfo.StepSounds[e.Block]);
+ }
+ }
+
+ public void PlayDigSound(byte type) { PlaySound(type, digBoard); }
+
+ public void PlayStepSound(byte type) { PlaySound(type, stepBoard); }
+
+ AudioFormat format;
+ AudioChunk chunk = new AudioChunk();
+ void PlaySound(byte type, Soundboard board) {
+ if (type == SoundType.None || monoOutputs == null) return;
+ Sound snd = board.PickRandomSound(type);
+ if (snd == null) return;
+
+ format = snd.Format;
+ chunk.Data = snd.Data;
+ chunk.Length = snd.Data.Length;
+
+ float volume = game.SoundsVolume / 100.0f;
+ if (board == digBoard) {
+ if (type == SoundType.Metal) format.SampleRate = (format.SampleRate * 6) / 5;
+ else format.SampleRate = (format.SampleRate * 4) / 5;
+ } else {
+ volume *= 0.50f;
+ if (type == SoundType.Metal) format.SampleRate = (format.SampleRate * 7) / 5;
+ }
+
+ if (format.Channels == 1) {
+ PlayCurrentSound(monoOutputs, volume);
+ } else if (format.Channels == 2) {
+ PlayCurrentSound(stereoOutputs, volume);
+ }
+ }
+
+ IAudioOutput firstSoundOut;
+ void PlayCurrentSound(IAudioOutput[] outputs, float volume) {
+ for (int i = 0; i < monoOutputs.Length; i++) {
+ IAudioOutput output = outputs[i];
+ if (output == null) {
+ outputs[i] = GetPlatformOut();
+ output = outputs[i];
+ }
+
+ if (!output.IsFinished()) continue;
+ AudioFormat fmt = output.Format;
+ if (fmt.Channels == 0 || fmt.Equals(format)) {
+ PlaySound(output, volume); return;
+ }
+ }
+
+ // This time we try to play the sound on all possible devices,
+ // even if it requires the expensive case of recreating a device
+ for (int i = 0; i < monoOutputs.Length; i++) {
+ IAudioOutput output = outputs[i];
+ if (!output.IsFinished()) continue;
+
+ PlaySound(output, volume); return;
+ }
+ }
+
+
+ IAudioOutput MakeSoundOutput(IAudioOutput[] outputs, int i) {
+ IAudioOutput output = GetPlatformOut();
+ output.Create(1);
+ outputs[i] = output;
+ return output;
+ }
+
+ void PlaySound(IAudioOutput output, float volume) {
+ try {
+ output.SetVolume(volume);
+ output.SetFormat(format);
+ output.PlayData(0, chunk);
+ } catch (InvalidOperationException ex) {
+ ErrorHandler.LogError("AudioPlayer.PlayCurrentSound()", ex);
+ if (ex.Message == "No audio devices found")
+ game.Chat.Add("&cNo audio devices found, disabling sounds.");
+ else
+ game.Chat.Add("&cAn error occured when trying to play sounds, disabling sounds.");
+
+ SetSounds(0);
+ game.SoundsVolume = 0;
+ }
+ }
+
+ void DisposeSound() {
+ DisposeOutputs(ref monoOutputs);
+ DisposeOutputs(ref stereoOutputs);
+ if (firstSoundOut != null) {
+ firstSoundOut.Dispose();
+ firstSoundOut = null;
+ }
+ }
+
+ void DisposeOutputs(ref IAudioOutput[] outputs) {
+ if (outputs == null) return;
+ bool soundPlaying = true;
+
+ while (soundPlaying) {
+ soundPlaying = false;
+ for (int i = 0; i < outputs.Length; i++) {
+ if (outputs[i] == null) continue;
+ soundPlaying |= !outputs[i].IsFinished();
+ }
+ if (soundPlaying)
+ Thread.Sleep(1);
+ }
+
+ for (int i = 0; i < outputs.Length; i++) {
+ if (outputs[i] == null) continue;
+ outputs[i].Dispose();
+ }
+ outputs = null;
+ }
+ }
+}
diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs
index e9573b84b..488bd0a14 100644
--- a/ClassicalSharp/Audio/AudioPlayer.cs
+++ b/ClassicalSharp/Audio/AudioPlayer.cs
@@ -139,7 +139,7 @@ namespace ClassicalSharp.Audio {
void DisposeOf(ref IAudioOutput output, ref Thread thread) {
if (output == null) return;
- output.Stop();
+ output.pendingStop = true;
thread.Join();
output.Dispose();
diff --git a/ClassicalSharp/Audio/Soundboard.cs b/ClassicalSharp/Audio/Soundboard.cs
index 6655ab002..7745facd0 100644
--- a/ClassicalSharp/Audio/Soundboard.cs
+++ b/ClassicalSharp/Audio/Soundboard.cs
@@ -2,11 +2,12 @@
using System;
using System.Collections.Generic;
using System.IO;
+using SharpWave;
namespace ClassicalSharp.Audio {
public class Sound {
- public int SampleRate, BitsPerSample, Channels;
+ public AudioFormat Format;
public byte[] Data;
}
@@ -97,12 +98,12 @@ namespace ClassicalSharp.Audio {
static void HandleFormat(BinaryReader r, ref int size, Sound snd) {
if (r.ReadUInt16() != 1)
throw new InvalidDataException("Only PCM audio is supported.");
- size -= 2;
- snd.Channels = r.ReadUInt16(); size -= 2;
- snd.SampleRate = r.ReadInt32(); size -= 4;
- r.ReadInt32(); r.ReadUInt16(); size -= 6;
- snd.BitsPerSample = r.ReadUInt16(); size -= 2;
+ snd.Format.Channels = r.ReadUInt16();
+ snd.Format.SampleRate = r.ReadInt32();
+ r.ReadInt32(); r.ReadUInt16();
+ snd.Format.BitsPerSample = r.ReadUInt16();
+ size -= 16;
}
unsafe string GetFourCC(BinaryReader r) {
diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj
index 41247d31b..29fcb6b44 100644
--- a/ClassicalSharp/ClassicalSharp.csproj
+++ b/ClassicalSharp/ClassicalSharp.csproj
@@ -69,9 +69,6 @@
-
- SharpWave.dll
-
@@ -450,6 +447,10 @@
{4A4110EE-21CA-4715-AF67-0C8B7CE0642F}
InteropPatcher
+
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}
+ SharpWave
+
diff --git a/ClassicalSharp/SharpWave.dll b/ClassicalSharp/SharpWave.dll
index db9479d36..8ee223677 100644
Binary files a/ClassicalSharp/SharpWave.dll and b/ClassicalSharp/SharpWave.dll differ
diff --git a/Launcher2/Launcher2.csproj b/Launcher2/Launcher2.csproj
index 6e895e1a2..d6dc99c66 100644
--- a/Launcher2/Launcher2.csproj
+++ b/Launcher2/Launcher2.csproj
@@ -48,9 +48,6 @@
Project
-
- ..\ClassicalSharp\SharpWave.dll
-
@@ -265,5 +262,11 @@
+
+
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}
+ SharpWave
+
+
\ No newline at end of file
diff --git a/Launcher2/Patcher/SoundPatcher.cs b/Launcher2/Patcher/SoundPatcher.cs
index 136ad5bf1..02007534c 100644
--- a/Launcher2/Patcher/SoundPatcher.cs
+++ b/Launcher2/Patcher/SoundPatcher.cs
@@ -77,15 +77,16 @@ namespace Launcher.Patcher {
WriteFourCC(w, "RIFF");
w.Write((int)(stream.Length - 8));
WriteFourCC(w, "WAVE");
+ AudioFormat format = data.Format;
WriteFourCC(w, "fmt ");
w.Write(16);
w.Write((ushort)1); // audio format, PCM
- w.Write((ushort)data.Last.Channels);
- w.Write(data.Last.SampleRate);
- w.Write((data.Last.SampleRate * data.Last.Channels * data.Last.BitsPerSample) / 8); // byte rate
- w.Write((ushort)((data.Last.Channels * data.Last.BitsPerSample) / 8)); // block align
- w.Write((ushort)data.Last.BitsPerSample);
+ w.Write((ushort)format.Channels);
+ w.Write(format.SampleRate);
+ w.Write((format.SampleRate * format.Channels * format.BitsPerSample) / 8); // byte rate
+ w.Write((ushort)((format.Channels * format.BitsPerSample) / 8)); // block align
+ w.Write((ushort)format.BitsPerSample);
WriteFourCC(w, "data");
w.Write((int)(stream.Length - 44));
diff --git a/SharpWave/ICodec.cs b/SharpWave/ICodec.cs
new file mode 100644
index 000000000..3eb89e284
--- /dev/null
+++ b/SharpWave/ICodec.cs
@@ -0,0 +1,17 @@
+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
new file mode 100644
index 000000000..e0b20483d
--- /dev/null
+++ b/SharpWave/IMediaContainer.cs
@@ -0,0 +1,48 @@
+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/Properties/AssemblyInfo.cs b/SharpWave/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..f37b6f27c
--- /dev/null
+++ b/SharpWave/Properties/AssemblyInfo.cs
@@ -0,0 +1,31 @@
+#region Using directives
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+#endregion
+
+// 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("SharpWave")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SharpWave")]
+[assembly: AssemblyCopyright("Copyright 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// This sets the default COM visibility of types in the assembly to invisible.
+// If you need to expose a type to COM, use [ComVisible(true)] on that type.
+[assembly: ComVisible(false)]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all the values or you can use the default the Revision and
+// Build Numbers by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.*")]
diff --git a/SharpWave/SharpWave.csproj b/SharpWave/SharpWave.csproj
new file mode 100644
index 000000000..a87ad73e6
--- /dev/null
+++ b/SharpWave/SharpWave.csproj
@@ -0,0 +1,87 @@
+
+
+
+ {77EA9D1E-4995-4D05-A9C7-29173CB5DC72}
+ Debug
+ AnyCPU
+ Library
+ SharpWave
+ SharpWave
+ v2.0
+ Properties
+ True
+ False
+ 4
+ false
+
+
+
+
+ AnyCPU
+ False
+ Auto
+ 4194304
+ 4096
+
+
+ bin\Debug\
+ true
+ Full
+ False
+ False
+ DEBUG;TRACE
+
+
+ bin\Release\
+ False
+ None
+ True
+ False
+ TRACE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
\ No newline at end of file
diff --git a/SharpWave/SharpWave.dll.config b/SharpWave/SharpWave.dll.config
new file mode 100644
index 000000000..b2d99e8d2
--- /dev/null
+++ b/SharpWave/SharpWave.dll.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/SharpWave/Utils/MemUtils.cs b/SharpWave/Utils/MemUtils.cs
new file mode 100644
index 000000000..962e147b5
--- /dev/null
+++ b/SharpWave/Utils/MemUtils.cs
@@ -0,0 +1,35 @@
+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/VolumeMixer.cs b/SharpWave/VolumeMixer.cs
new file mode 100644
index 000000000..ec980917c
--- /dev/null
+++ b/SharpWave/VolumeMixer.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace SharpWave {
+
+ public unsafe static class VolumeMixer {
+
+ public static void Mix16( short* samples, int numSamples, int volumePercent ) {
+ int numBulkSamples = numSamples & ~0x07;
+
+ // Unrolled loop, do 8 samples per iteration
+ for( int i = 0; i < numBulkSamples; i += 8 ) {
+ samples[0] = (short)(samples[0] * volumePercent / 100);
+ samples[1] = (short)(samples[1] * volumePercent / 100);
+ samples[2] = (short)(samples[2] * volumePercent / 100);
+ samples[3] = (short)(samples[3] * volumePercent / 100);
+
+ samples[4] = (short)(samples[4] * volumePercent / 100);
+ samples[5] = (short)(samples[5] * volumePercent / 100);
+ samples[6] = (short)(samples[6] * volumePercent / 100);
+ samples[7] = (short)(samples[7] * volumePercent / 100);
+
+ samples += 8;
+ }
+
+ // Fixup the few last samples
+ for( int i = numBulkSamples; i < numSamples; i++ ) {
+ samples[0] = (short)(samples[0] * volumePercent / 100);
+ samples++;
+ }
+ }
+
+ public static void Mix8( byte* samples, int numSamples, int volumePercent ) {
+ for( int i = 0; i < numSamples; i++ ) {
+ samples[0] = (byte)(127 + (samples[0] - 127) * volumePercent / 100);
+ samples++;
+ }
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/Block.cs b/SharpWave/csvorbis/Block.cs
new file mode 100644
index 000000000..db6f0ee1b
--- /dev/null
+++ b/SharpWave/csvorbis/Block.cs
@@ -0,0 +1,90 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using csogg;
+
+namespace csvorbis
+{
+ public class Block
+ {
+ //necessary stream state for linking to the framing abstraction
+ internal float[][] pcm = new float[0][]; // this is a pointer into local storage
+ internal csBuffer opb = new csBuffer();
+
+ internal int lW;
+ internal int W;
+ internal int nW;
+ internal int pcmend;
+ internal int mode;
+
+ internal int eofflag;
+ internal long granulepos;
+ internal long sequence;
+ internal DspState vd; // For read-only access of configuration
+
+ public void init(DspState vd) {
+ this.vd = vd;
+ }
+
+ public int synthesis(Packet op)
+ {
+ Info vi = vd.vi;
+ opb.readinit(op.packet_base, op.packet, op.bytes);
+ opb.read(1);
+ // read our mode and pre/post windowsize
+ mode = opb.read(vd.modebits);
+ W = vi.mode_param[mode].blockflag;
+ if(W != 0) {
+ lW = opb.read(1); nW = opb.read(1);
+ } else {
+ lW = 0; nW = 0;
+ }
+
+ // more setup
+ granulepos = op.granulepos;
+ sequence = op.packetno-3; // first block is third packet
+ eofflag = op.e_o_s;
+
+ // alloc pcm passback storage
+ pcmend = vi.blocksizes[W];
+ if(pcm.Length
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using System.Runtime.CompilerServices;
+using csogg;
+
+namespace csvorbis
+{
+ class CodeBook
+ {
+ internal int dim; // codebook dimensions (elements per vector)
+ internal int entries; // codebook entries
+ internal StaticCodeBook c = new StaticCodeBook();
+
+ internal float[] valuelist; // list of dim*entries actual entry values
+ internal DecodeAux decode_tree;
+
+ internal int[] t = new int[15]; // decodevs_add is synchronized for re-using t.
+
+ internal int decodevs_add(float[]a, int offset, csBuffer b, int n)
+ {
+ int step = n/dim;
+ int entry;
+ int i,j,o;
+
+ if(t.Length8)
+ {
+ for(i = 0;i declarative (set the value)
+ // stage == 1 -> additive
+ // stage == 2 -> multiplicitive
+
+ // returns the entry number or -1 on eof
+ internal int decode(csBuffer b)
+ {
+ int ptr = 0;
+ DecodeAux t = decode_tree;
+ int lok = b.look(t.tabn);
+ //System.err.println(this+" "+t+" lok = "+lok+", tabn = "+t.tabn);
+
+ if(lok >= 0)
+ {
+ ptr = t.tab[lok];
+ b.adv(t.tabl[lok]);
+ if(ptr <= 0)
+ {
+ return -ptr;
+ }
+ }
+ do
+ {
+ switch(b.read1())
+ {
+ case 0:
+ ptr = t.ptr0[ptr];
+ break;
+ case 1:
+ ptr = t.ptr1[ptr];
+ break;
+ case -1:
+ default:
+ return(-1);
+ }
+ }
+ while(ptr>0);
+ return(-ptr);
+ }
+
+ // returns the entry number or -1 on eof
+ internal int decodevs(float[] a, int index, csBuffer b, int step,int addmul)
+ {
+ int entry = decode(b);
+ if(entry == -1)return(-1);
+ switch(addmul)
+ {
+ case -1:
+ for(int i = 0,o = 0;i0)
+ {
+ int entry = marker[length];
+
+ // when we claim a node for an entry, we also claim the nodes
+ // below it (pruning off the imagined tree that may have dangled
+ // from it) as well as blocking the use of any nodes directly
+ // above for leaves
+
+ // update ourself
+ if(length<32 && ((uint)entry>>length) != 0)
+ {
+ // error condition; the lengths must specify an overpopulated tree
+ //free(r);
+ return(null);
+ }
+ r[i] = entry;
+
+ // Look to see if the next shorter marker points to the node
+ // above. if so, update it and repeat.
+ {
+ for(int j = length;j>0;j--)
+ {
+ if((marker[j]&1) != 0)
+ {
+ // have to jump branches
+ if(j == 1)marker[1]++;
+ else marker[j] = marker[j-1]<<1;
+ break; // invariant says next upper marker would already
+ // have been moved if it was on the same path
+ }
+ marker[j]++;
+ }
+ }
+
+ // prune the tree; the implicit invariant says all the longer
+ // markers were dangling from our just-taken node. Dangle them
+ // from our *new* node.
+ for(int j = length+1;j<33;j++)
+ {
+ if(((uint)marker[j]>>1) == entry)
+ {
+ entry = marker[j];
+ marker[j] = marker[j-1]<<1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ // bitreverse the words because our bitwise packer/unpacker is LSb
+ // endian
+ for(int i = 0;i>j)&1);
+ }
+ r[i] = temp;
+ }
+
+ return(r);
+ }
+
+ // build the decode helper tree from the codewords
+ internal DecodeAux make_decode_tree()
+ {
+ int top = 0;
+ DecodeAux t = new DecodeAux();
+ int[] ptr0 = t.ptr0 = new int[entries*2];
+ int[] ptr1 = t.ptr1 = new int[entries*2];
+ int[] codelist = make_words(c.lengthlist, c.entries);
+
+ if(codelist == null)return(null);
+ t.aux = entries*2;
+
+ for(int i = 0;i0)
+ {
+ int ptr = 0;
+ int j;
+ for(j = 0;j>j)&1);
+ if(bit == 0)
+ {
+ if(ptr0[ptr] == 0)
+ {
+ ptr0[ptr] = ++top;
+ }
+ ptr = ptr0[ptr];
+ }
+ else
+ {
+ if(ptr1[ptr] == 0)
+ {
+ ptr1[ptr] = ++top;
+ }
+ ptr = ptr1[ptr];
+ }
+ }
+
+ if((((uint)codelist[i]>>j)&1) == 0){ ptr0[ptr] = -i; }
+ else{ ptr1[ptr] = -i; }
+
+ }
+ }
+ //free(codelist);
+
+ t.tabn = VUtils.ilog(entries)-4;
+
+ if(t.tabn<5)t.tabn = 5;
+ int n = 1< 0 || j == 0); j++)
+ {
+ if ((i&(1<
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using System.Text;
+using csogg;
+
+namespace csvorbis
+{
+ public class Comment
+ {
+ // unlimited user comment fields. libvorbis writes 'libvorbis'
+ // whatever vendor is set to in encode
+ public byte[][] user_comments;
+ public int comments;
+ public byte[] vendor;
+
+ public void init()
+ {
+ user_comments = null;
+ comments = 0;
+ vendor = null;
+ }
+
+ internal int unpack(csBuffer opb)
+ {
+ int vendorlen = opb.read(32);
+ vendor = new byte[vendorlen + 1];
+ opb.read(vendor, vendorlen);
+ comments = opb.read(32);
+ user_comments = new byte[comments + 1][];
+
+ for(int i = 0; i < comments; i++) {
+ int len = opb.read(32);
+ user_comments[i] = new byte[len+1];
+ opb.read(user_comments[i], len);
+ }
+
+ opb.read(1);
+ return(0);
+ }
+
+ internal void clear()
+ {
+ user_comments = null;
+ vendor = null;
+ }
+
+ public string getVendor()
+ {
+ return Encoding.UTF8.GetString(vendor);
+ }
+
+ public string getComment(int i)
+ {
+ Encoding AE = Encoding.UTF8;
+ if(comments <= i)return null;
+ return Encoding.UTF8.GetString(user_comments[i]);
+ }
+
+ public string toString()
+ {
+ String sum = "Vendor: " + getVendor();
+ for(int i = 0; i < comments; i++)
+ sum = sum + "\nComment: " + getComment(i);
+ sum = sum + "\n";
+ return sum;
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/DspState.cs b/SharpWave/csvorbis/DspState.cs
new file mode 100644
index 000000000..260da89d8
--- /dev/null
+++ b/SharpWave/csvorbis/DspState.cs
@@ -0,0 +1,319 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using csogg;
+using csvorbis;
+
+namespace csvorbis
+{
+ public class DspState
+ {
+ static float M_PI = 3.1415926539f;
+
+ internal Info vi;
+ internal int modebits;
+
+ float[][] pcm;
+ //float[][] pcmret;
+ int pcm_storage;
+ int pcm_current;
+ int pcm_returned;
+
+ int lW;
+ int W;
+ int centerW;
+
+ long granulepos;
+ public long sequence;
+
+ // local lookup storage
+ //!! Envelope ve = new Envelope(); // envelope
+ internal float[][][][] wnd; // block, leadin, leadout
+ //vorbis_look_transform **transform[2]; // block, type
+ internal Object[] transform;
+ internal CodeBook[] fullbooks;
+ // backend lookups are tied to the mode, not the backend or naked mapping
+ internal Object[] mode;
+
+ public DspState()
+ {
+ transform = new Object[2];
+ wnd = new float[2][][][];
+ wnd[0] = new float[2][][];
+ wnd[0][0] = new float[2][];
+ wnd[0][1] = new float[2][];
+ wnd[0][0][0] = new float[2];
+ wnd[0][0][1] = new float[2];
+ wnd[0][1][0] = new float[2];
+ wnd[0][1][1] = new float[2];
+ wnd[1] = new float[2][][];
+ wnd[1][0] = new float[2][];
+ wnd[1][1] = new float[2][];
+ wnd[1][0][0] = new float[2];
+ wnd[1][0][1] = new float[2];
+ wnd[1][1][0] = new float[2];
+ wnd[1][1][1] = new float[2];
+ }
+
+ internal static float[] window(int wnd, int left, int right)
+ {
+ float[] ret = new float[wnd];
+ // The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
+
+ int leftbegin = wnd/4-left/2;
+ int rightbegin = wnd-wnd/4-right/2;
+
+ for(int i = 0;ivi.blocksizes[1]/2 && pcm_returned>8192)
+ {
+ // don't shift too much; we need to have a minimum PCM buffer of
+ // 1/2 long block
+
+ int shiftPCM = centerW-vi.blocksizes[1]/2;
+ shiftPCM = (pcm_returnedpcm_storage)
+ {
+ // expand the storage
+ pcm_storage = endW+vi.blocksizes[1];
+ for(int i = 0;igranulepos.
+ //
+ // This is not foolproof! It will be confused if we begin
+ // decoding at the last page after a seek or hole. In that case,
+ // we don't have a starting point to judge where the last frame
+ // is. For this reason, vorbisfile will always try to make sure
+ // it reads the last two marked pages in proper sequence
+
+ if(granulepos == -1)
+ {
+ granulepos = vb.granulepos;
+ }
+ else
+ {
+ granulepos += (_centerW-centerW);
+ if(vb.granulepos != -1 && granulepos != vb.granulepos)
+ {
+ if(granulepos>vb.granulepos && vb.eofflag != 0)
+ {
+ // partial last frame. Strip the padding off
+ _centerW = _centerW - (int)(granulepos-vb.granulepos);
+ }// else{ Shouldn't happen *unless* the bitstream is out of
+ // spec. Either way, believe the bitstream }
+ granulepos = vb.granulepos;
+ }
+ }
+
+ // Update, cleanup
+ centerW = _centerW;
+ pcm_current = endW;
+ }
+
+ public int synthesis_pcmout(ref float[][] _pcm, int[] index)
+ {
+ if(pcm_returnedcenterW)
+ return;
+ pcm_returned += bytes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SharpWave/csvorbis/FuncFloor.cs b/SharpWave/csvorbis/FuncFloor.cs
new file mode 100644
index 000000000..94c991095
--- /dev/null
+++ b/SharpWave/csvorbis/FuncFloor.cs
@@ -0,0 +1,560 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using csogg;
+
+namespace csvorbis
+{
+ abstract class FuncFloor
+ {
+ public static FuncFloor[] floor_P = {null,new Floor1()};
+
+ public abstract Object unpack(Info vi, csBuffer opb);
+ public abstract Object look(DspState vd, InfoMode mi, Object i);
+ public abstract Object inverse1(Block vb, Object i, Object memo);
+ public abstract int inverse2(Block vb, Object i, Object memo, float[] fout);
+ }
+
+ class Floor1 : FuncFloor
+ {
+ static int VIF_POSIT = 63;
+
+ public override Object unpack(Info vi , csBuffer opb)
+ {
+ int count = 0,maxclass = -1,rangebits;
+ InfoFloor1 info = new InfoFloor1();
+
+ /* read partitions */
+ info.partitions = opb.read(5); /* only 0 to 31 legal */
+ for(int j = 0;j= vi.books)
+ {
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ for(int k = 0;k<(1<= vi.books)
+ {
+ //goto err_out;
+ info.free();
+ return(null);
+ }
+ }
+ }
+
+ /* read the post list */
+ info.mult = opb.read(2)+1; /* only 1,2,3,4 legal now */
+ rangebits = opb.read(4);
+
+ for(int j = 0,k = 0;j= (1<info.postlist[sortpointer[k]])
+ {
+ foo = sortpointer[k];
+ sortpointer[k] = sortpointer[j];
+ sortpointer[j] = foo;
+ }
+ }
+ }
+
+ /* points from sort order back to range number */
+ for(int j = 0;j<_n;j++)
+ {
+ look.forward_index[j] = sortpointer[j];
+ }
+ /* points from range order to sorted position */
+ for(int j = 0;j<_n;j++)
+ {
+ look.reverse_index[look.forward_index[j]] = j;
+ }
+ /* we actually need the post values too */
+ for(int j = 0;j<_n;j++)
+ {
+ look.sorted_index[j] = info.postlist[look.forward_index[j]];
+ }
+
+
+ /* quantize values to multiplier spec */
+ switch(info.mult)
+ {
+ case 1: /* 1024 -> 256 */
+ look.quant_q = 256;
+ break;
+ case 2: /* 1024 -> 128 */
+ look.quant_q = 128;
+ break;
+ case 3: /* 1024 -> 86 */
+ look.quant_q = 86;
+ break;
+ case 4: /* 1024 -> 64 */
+ look.quant_q = 64;
+ break;
+ default:
+ look.quant_q = -1;
+ break;
+ }
+
+ /* discover our neighbors for decode where we don't use fit flags
+ (that would push the neighbors outward) */
+ for(int j = 0;j<_n-2;j++)
+ {
+ int lo = 0;
+ int hi = 1;
+ int lx = 0;
+ int hx = look.n;
+ int currentx = info.postlist[j+2];
+ for(int k = 0;klx && xcurrentx)
+ {
+ hi = k;
+ hx = x;
+ }
+ }
+ look.loneighbor[j] = lo;
+ look.hineighbor[j] = hi;
+ }
+
+ return look;
+ }
+
+ public override Object inverse1(Block vb, Object ii, Object memo)
+ {
+ LookFloor1 look = (LookFloor1)ii;
+ InfoFloor1 info = look.vi;
+ CodeBook[] books = vb.vd.fullbooks;
+
+ /* unpack wrapped/predicted values from stream */
+ if(vb.opb.read(1) == 1)
+ {
+ int[] fit_value = null;
+ if(memo is int[])
+ {
+ fit_value = (int[])memo;
+ }
+ if(fit_value == null || fit_value.Length> csubbits);
+ if(book >= 0)
+ {
+ if((fit_value[j+k] = books[book].decode(vb.opb)) == -1)
+ {
+ return(null);
+ }
+ }
+ else
+ {
+ fit_value[j+k] = 0;
+ }
+ }
+ j += cdim;
+ }
+
+ /* unwrap positive values and reconsitute via linear interpolation */
+ for(int i = 2;i= room)
+ {
+ if(hiroom>loroom)
+ {
+ val = val-loroom;
+ }
+ else
+ {
+ val = -1-(val-hiroom);
+ }
+ }
+ else
+ {
+ if((val&1) != 0)
+ {
+ val = (int)(-((uint)(val+1) >> 1));
+ }
+ else
+ {
+ val >>= 1;
+ }
+ }
+
+ fit_value[i] = val+predicted;
+ fit_value[look.loneighbor[i-2]] &= 0x7fff;
+ fit_value[look.hineighbor[i-2]] &= 0x7fff;
+ }
+ else
+ {
+ fit_value[i] = predicted|0x8000;
+ }
+ }
+ return(fit_value);
+ }
+
+ // eop:
+ // return(NULL);
+ return(null);
+ }
+
+ private static int render_point(int x0,int x1,int y0,int y1,int x)
+ {
+ y0 &= 0x7fff; /* mask off flag */
+ y1 &= 0x7fff;
+
+ int dy = y1-y0;
+ int adx = x1-x0;
+ int ady = Math.Abs(dy);
+ int err = ady*(x-x0);
+
+ int off = (int)(err/adx);
+ if(dy<0)return(y0-off);
+ return(y0+off);
+ }
+
+ public override int inverse2(Block vb, Object i, Object memo, float[] fout)
+ {
+ LookFloor1 look = (LookFloor1)i;
+ InfoFloor1 info = look.vi;
+ int n = vb.vd.vi.blocksizes[vb.mode]/2;
+
+ if(memo != null)
+ {
+ /* render the lines */
+ int[] fit_value = (int[] )memo;
+ int hx = 0, lx = 0;
+ int ly = fit_value[0]*info.mult;
+ for(int j = 1;j= adx)
+ {
+ err -= adx;
+ y += sy;
+ }
+ else
+ {
+ y += bbase;
+ }
+ d[x] *= FLOOR_fromdB_LOOKUP[y];
+ }
+ }
+ }
+
+ class InfoFloor1
+ {
+ const int VIF_POSIT = 63;
+ const int VIF_CLASS = 16;
+ const int VIF_PARTS = 31;
+
+ internal int partitions; /* 0 to 31 */
+ internal int[] partitionclass = new int[VIF_PARTS]; /* 0 to 15 */
+
+ internal int[] class_dim = new int[VIF_CLASS]; /* 1 to 8 */
+ internal int[] class_subs = new int[VIF_CLASS]; /* 0,1,2,3 (bits: 1<
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using csogg;
+
+namespace csvorbis
+{
+ abstract class FuncMapping
+ {
+ public static FuncMapping[] mapping_P = {new Mapping0()};
+
+ public abstract Object unpack(Info info , csBuffer buffer);
+ public abstract Object look(DspState vd, InfoMode vm, Object m);
+ public abstract int inverse(Block vd, Object lm);
+ }
+
+ class Mapping0 : FuncMapping
+ {
+ public override Object look(DspState vd, InfoMode vm, Object m)
+ {
+ Info vi = vd.vi;
+ LookMapping0 looks = new LookMapping0();
+ InfoMapping0 info = looks.map = (InfoMapping0)m;
+ looks.mode = vm;
+
+ looks.floor_look = new Object[info.submaps];
+ looks.residue_look = new Object[info.submaps];
+
+ looks.floor_func = new FuncFloor[info.submaps];
+ looks.residue_func = new FuncResidue[info.submaps];
+
+ for(int i = 0;i1) {
+ for(int i = 0;i= 0; i-- ) {
+ float[] pcmM = vb.pcm[info.coupling_mag[i]];
+ float[] pcmA = vb.pcm[info.coupling_ang[i]];
+
+ for( int j = 0; j < n / 2; j++ ) {
+ float mag = pcmM[j];
+ float ang = pcmA[j];
+
+ if( mag > 0 ) {
+ if( ang > 0 ) {
+ pcmM[j] = mag;
+ pcmA[j] = mag-ang;
+ } else {
+ pcmA[j] = mag;
+ pcmM[j] = mag+ang;
+ }
+ } else {
+ if( ang > 0 ) {
+ pcmM[j] = mag;
+ pcmA[j] = mag+ang;
+ } else {
+ pcmA[j] = mag;
+ pcmM[j] = mag-ang;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ class InfoMapping0
+ {
+ internal int submaps; // <= 16
+ internal int[] chmuxlist = new int[256]; // up to 256 channels in a Vorbis stream
+
+ internal int[] timesubmap = new int[16]; // [mux]
+ internal int[] floorsubmap = new int[16]; // [mux] submap to floors
+ internal int[] residuesubmap = new int[16];// [mux] submap to residue
+ internal int[] psysubmap = new int[16]; // [mux]; encode only
+
+ internal int coupling_steps;
+ internal int[] coupling_mag = new int[256];
+ internal int[] coupling_ang = new int[256];
+
+ internal void free()
+ {
+ chmuxlist = null;
+ timesubmap = null;
+ floorsubmap = null;
+ residuesubmap = null;
+ psysubmap = null;
+
+ coupling_mag = null;
+ coupling_ang = null;
+ }
+ }
+
+ class LookMapping0
+ {
+ internal InfoMode mode;
+ internal InfoMapping0 map;
+ internal Object[] floor_look;
+ internal Object[] residue_look;
+
+ internal FuncFloor[] floor_func;
+ internal FuncResidue[] residue_func;
+
+ internal int ch;
+ }
+}
\ No newline at end of file
diff --git a/SharpWave/csvorbis/FuncResidue.cs b/SharpWave/csvorbis/FuncResidue.cs
new file mode 100644
index 000000000..985b0ed00
--- /dev/null
+++ b/SharpWave/csvorbis/FuncResidue.cs
@@ -0,0 +1,312 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using csogg;
+
+namespace csvorbis
+{
+ abstract class FuncResidue
+ {
+ public static FuncResidue[] residue_P = {new Residue0(), new Residue1(), new Residue2()};
+
+ public abstract Object unpack(Info vi, csBuffer opb);
+ public abstract Object look(DspState vd, InfoMode vm, Object vr);
+
+ public abstract int inverse(Block vb, Object vl, float[][] fin, int[] nonzero,int ch);
+ }
+
+ class Residue0 : FuncResidue
+ {
+ public override Object unpack(Info vi, csBuffer opb)
+ {
+ int acc = 0;
+ InfoResidue0 info = new InfoResidue0();
+
+ info.begin = opb.read(24);
+ info.end = opb.read(24);
+ info.grouping = opb.read(24)+1;
+ info.partitions = opb.read(6)+1;
+ info.groupbook = opb.read(8);
+
+ for(int j = 0;jmaxstage)maxstage = stages;
+ look.partbooks[j] = new int[stages];
+ for(int k = 0; k
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using System.Text;
+using csogg;
+
+namespace csvorbis
+{
+ class InfoMode
+ {
+ internal int blockflag;
+ internal int windowtype;
+ internal int transformtype;
+ internal int mapping;
+ }
+
+ public class Info
+ {
+ private static int OV_ENOTAUDIO = -135;
+
+ public int version, channels, rate;
+
+ // Vorbis supports only short and long blocks, but allows the
+ // encoder to choose the sizes
+ internal int[] blocksizes = new int[2];
+
+ // modes are the primary means of supporting on-the-fly different
+ // blocksizes, different channel mappings (LR or mid-side),
+ // different residue backends, etc. Each mode consists of a
+ // blocksize flag and a mapping (along with the mapping setup
+
+ internal int modes, maps, times, floors, residues, books;
+
+ internal InfoMode[] mode_param = null;
+
+ internal int[] map_type = null;
+ internal Object[] map_param = null;
+
+ internal int[] floor_type = null;
+ internal Object[] floor_param = null;
+
+ internal int[] residue_type = null;
+ internal Object[] residue_param = null;
+
+ internal StaticCodeBook[] book_param = null;
+
+ // used by synthesis, which has a full, alloced vi
+ public void init() {
+ rate = 0;
+ }
+
+ public void clear() {
+ mode_param = null;
+ map_param = null;
+ floor_param = null;
+ residue_param = null;
+ book_param = null;
+ }
+
+ // Header packing/unpacking
+ void unpack_info(csBuffer opb) {
+ version = opb.read(32);
+ channels = opb.read(8);
+ rate = opb.read(32);
+
+ opb.read(32); // bitrate_upper
+ opb.read(32); // bitrate_nominal
+ opb.read(32); // bitrate_lower
+
+ blocksizes[0] = 1<(ref T[] array, int count) {
+ if(array == null || array.Length != count) {
+ array = new T[count];
+ }
+ }
+
+ void CheckEntries(ref T[] array, ref int[] types, int count) {
+ if(array == null || array.Length != count) {
+ array = new T[count];
+ types = new int[count];
+ }
+ }
+
+ public void synthesis_headerin(Comment vc, Packet op) {
+ if(op == null) return;
+
+ csBuffer opb = new csBuffer();
+ opb.readinit(op.packet_base, op.packet, op.bytes);
+ byte[] buffer = new byte[6];
+ int packtype = opb.read(8);
+ opb.read(buffer, 6);
+
+ if(buffer[0] != 'v' || buffer[1] != 'o' || buffer[2] != 'r' ||
+ buffer[3] != 'b' || buffer[4] != 'i' || buffer[5] != 's') {
+ throw new InvalidOperationException("Expected vorbis header");
+ }
+
+ switch(packtype) {
+ case 0x01: // least significant *bit* is read first
+ unpack_info(opb);
+ break;
+ case 0x03: // least significant *bit* is read first
+ vc.unpack(opb);
+ break;
+ case 0x05: // least significant *bit* is read first
+ unpack_books(opb);
+ break;
+ default:
+ // Not a valid vorbis header type
+ break;
+ }
+ }
+
+ public int blocksize(Packet op) {
+ csBuffer opb = new csBuffer();
+ opb.readinit(op.packet_base, op.packet, op.bytes);
+
+ /* Check the packet type */
+ if(opb.read(1) != 0)
+ return(OV_ENOTAUDIO);
+
+ int modebits = VUtils.ilog2(modes);
+ int mode = opb.read(modebits);
+ return blocksizes[mode_param[mode].blockflag];
+ }
+
+ public String toString()
+ {
+ return "version:" + version + ", channels:" + channels
+ + ", rate:" + rate;
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/Mdct.cs b/SharpWave/csvorbis/Mdct.cs
new file mode 100644
index 000000000..304a41e03
--- /dev/null
+++ b/SharpWave/csvorbis/Mdct.cs
@@ -0,0 +1,249 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using System.Runtime.CompilerServices;
+using csogg;
+
+namespace csvorbis
+{
+ class Mdct
+ {
+
+ //static private float cPI3_8 = 0.38268343236508977175f;
+ //static private float cPI2_8 = 0.70710678118654752441f;
+ //static private float cPI1_8 = 0.92387953251128675613f;
+
+ int n;
+ int log2n;
+
+ float[] trig;
+ int[] bitrev;
+
+ float scale;
+
+ internal void init(int n)
+ {
+ bitrev = new int[n/4];
+ trig = new float[n+n/4];
+
+ int n2 = (int)((uint)n >> 1);
+ log2n = (int)Math.Round(Math.Log(n)/Math.Log(2));
+ this.n = n;
+
+
+ int AE = 0;
+ int AO = 1;
+ int BE = AE+n/2;
+ int BO = BE+1;
+ int CE = BE+n/2;
+ int CO = CE+1;
+ // trig lookups...
+ for(int i = 0;i> j) != 0; j++)
+ if(((((uint)msb>>j))&i) != 0)
+ acc |= 1 << j;
+ bitrev[i*2] = ((~acc)&mask);
+ // bitrev[i*2] = ((~acc)&mask)-1;
+ bitrev[i*2+1] = acc;
+ }
+ }
+ scale = 4.0f/n;
+ }
+
+ float[] _x = new float[1024];
+ float[] _w = new float[1024];
+
+ internal void backward(float[] fin, float[] fout)
+ {
+ if(_x.Length < n/2){_x = new float[n/2];}
+ if(_w.Length < n/2){_w = new float[n/2];}
+ float[] x = _x;
+ float[] w = _w;
+ int n2 = (int)((uint)n >> 1);
+ int n4 = (int)((uint)n >> 2);
+ int n8 = (int)((uint)n >> 3);
+
+ // rotate + step 1
+ int inO = 1;
+ int xO = 0;
+ int A = n2;
+
+ for(int i = 0;i> (i+2));
+ int k1 = 1 << (i+3);
+ int wbase = n2-2;
+
+ A = 0;
+ float[] temp;
+
+ for(int r = 0; r<((uint)k0>>2); r++)
+ {
+ int w1 = wbase;
+ w2 = w1-(k0>>1);
+ float AEv = trig[A],wA;
+ float AOv = trig[A+1],wB;
+ wbase -= 2;
+
+ k0++;
+ for(int s = 0;s<(2<
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+
+namespace csogg
+{
+ public class csBuffer
+ {
+ private static uint[] mask={
+ 0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
+ 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
+ 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
+ 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
+ 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
+ 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
+ 0x3fffffff,0x7fffffff,0xffffffff
+ };
+ int ptr = 0;
+ byte[] buffer = null;
+ int endbit = 0;
+ int endbyte = 0;
+ int storage = 0;
+
+ public void read (byte[] s, int bytes)
+ {
+ int i = 0;
+ while(bytes--!=0)
+ {
+ s[i++]=(byte)(read(8));
+ }
+ }
+
+ void reset()
+ {
+ ptr = 0;
+ buffer[0] = (byte)'\0';
+ endbit = endbyte = 0;
+ }
+
+ public void readinit(byte[] buf, int start, int bytes)
+ {
+ ptr = start;
+ buffer = buf;
+ endbit = endbyte = 0;
+ storage = bytes;
+ }
+
+ public int look(int bits)
+ {
+ int ret;
+ uint m = mask[bits];
+
+ bits += endbit;
+
+ if(endbyte + 4 >= storage)
+ {
+ if(endbyte+(bits-1)/8 >= storage)
+ return (-1);
+ }
+
+ ret = ((buffer[ptr]) & 0xff) >> endbit;
+
+ if(bits > 8)
+ {
+ ret |= ((buffer[ptr+1]) & 0xff) << (8 - endbit);
+ if(bits > 16)
+ {
+ ret |= ((buffer[ptr+2])&0xff) << (16-endbit);
+ if(bits > 24)
+ {
+ ret |= ((buffer[ptr+3])&0xff) << (24-endbit);
+ if((bits > 32) && (endbit != 0))
+ {
+ ret |= ((buffer[ptr+4])&0xff) << (32-endbit);
+ }
+ }
+ }
+ }
+ ret = (int)(m & ret);
+ return (ret);
+ }
+
+ public int look1()
+ {
+ if(endbyte >= storage)
+ return(-1);
+ return((buffer[ptr] >> endbit) & 1);
+ }
+
+ public void adv(int bits)
+ {
+ bits += endbit;
+ ptr += bits / 8;
+ endbyte += bits / 8;
+ endbit = bits & 7;
+ }
+
+ public void adv1()
+ {
+ ++endbit;
+ if(endbit > 7)
+ {
+ endbit = 0;
+ ptr++;
+ endbyte++;
+ }
+ }
+
+ public int read(int bits)
+ {
+ int ret;
+ uint m=mask[bits];
+
+ bits += endbit;
+
+ if(endbyte+4 >= storage)
+ {
+ ret = -1;
+ if(endbyte + (bits-1)/8 >= storage)
+ {
+ ptr += bits/8;
+ endbyte += bits/8;
+ endbit = bits&7;
+ return(ret);
+ }
+ }
+
+ ret = ((buffer[ptr]) & 0xff) >> endbit;
+ if(bits > 8)
+ {
+ ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
+ if(bits > 16)
+ {
+ ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
+ if(bits > 24)
+ {
+ ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
+
+ if((bits > 32) && (endbit != 0))
+ {
+ ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
+ }
+ }
+ }
+ }
+
+ ret &= (int)m;
+
+ ptr += bits/8;
+ endbyte += bits/8;
+ endbit = bits&7;
+ return(ret);
+ }
+
+ public int read1()
+ {
+ int ret;
+ if(endbyte>=storage)
+ {
+ ret = -1;
+ endbit++;
+ if(endbit > 7)
+ {
+ endbit = 0;
+ ptr++;
+ endbyte++;
+ }
+ return(ret);
+ }
+
+ ret=(buffer[ptr] >> endbit) & 1;
+
+ endbit++;
+ if(endbit > 7)
+ {
+ endbit = 0;
+ ptr++;
+ endbyte++;
+ }
+ return(ret);
+ }
+
+ public int bytes()
+ {
+ return(endbyte+(endbit+7)/8);
+ }
+
+ public int bits()
+ {
+ return(endbyte*8+endbit);
+ }
+
+ public byte[] buf()
+ {
+ return(buffer);
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/Ogg/Packet.cs b/SharpWave/csvorbis/Ogg/Packet.cs
new file mode 100644
index 000000000..47da039b9
--- /dev/null
+++ b/SharpWave/csvorbis/Ogg/Packet.cs
@@ -0,0 +1,42 @@
+/* csogg
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+
+namespace csogg
+{
+ public class Packet
+ {
+ public byte[] packet_base;
+ public int packet, bytes;
+ public int b_o_s, e_o_s;
+
+ public long granulepos;
+ public long packetno; // sequence number for decode; the framing
+ // knows where there's a hole in the data,
+ // but we need coupling so that the codec
+ // (which is in a seperate abstraction
+ // layer) also knows about the gap
+ }
+}
diff --git a/SharpWave/csvorbis/Ogg/Page.cs b/SharpWave/csvorbis/Ogg/Page.cs
new file mode 100644
index 000000000..2b4b27ae2
--- /dev/null
+++ b/SharpWave/csvorbis/Ogg/Page.cs
@@ -0,0 +1,137 @@
+/* csogg
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+
+namespace csogg
+{
+ public class Page
+ {
+ private static uint[] crc_lookup=new uint[256];
+
+ private static uint crc_entry(uint index)
+ {
+ uint r = index << 24;
+ for(int i=0; i<8; i++)
+ {
+ if((r& 0x80000000)!=0)
+ {
+ r=(r << 1)^0x04c11db7; /* The same as the ethernet generator
+ polynomial, although we use an
+ unreflected alg and an init/final
+ of 0, not 0xffffffff */
+ }
+ else
+ {
+ r <<= 1;
+ }
+ }
+ return (r & 0xffffffff);
+ }
+
+ public byte[] header_base;
+ public int header;
+ public int header_len;
+ public byte[] body_base;
+ public int body;
+ public int body_len;
+
+ internal int version()
+ {
+ return header_base[header+4]&0xff;
+ }
+ internal int continued()
+ {
+ return (header_base[header+5]&0x01);
+ }
+ public int bos()
+ {
+ return (header_base[header+5]&0x02);
+ }
+ public int eos()
+ {
+ return (header_base[header+5]&0x04);
+ }
+ public long granulepos()
+ {
+ long foo = header_base[header+13]&0xff;
+ foo = (foo<<8) | (uint)(header_base[header+12]&0xff);
+ foo = (foo<<8) | (uint)(header_base[header+11]&0xff);
+ foo = (foo<<8) | (uint)(header_base[header+10]&0xff);
+ foo = (foo<<8) | (uint)(header_base[header+9]&0xff);
+ foo = (foo<<8) | (uint)(header_base[header+8]&0xff);
+ foo = (foo<<8) | (uint)(header_base[header+7]&0xff);
+ foo = (foo<<8) | (uint)(header_base[header+6]&0xff);
+ return(foo);
+ }
+ public int serialno()
+ {
+ return (header_base[header+14]&0xff)|
+ ((header_base[header+15]&0xff)<<8)|
+ ((header_base[header+16]&0xff)<<16)|
+ ((header_base[header+17]&0xff)<<24);
+ }
+ internal int pageno()
+ {
+ return (header_base[header+18]&0xff)|
+ ((header_base[header+19]&0xff)<<8)|
+ ((header_base[header+20]&0xff)<<16)|
+ ((header_base[header+21]&0xff)<<24);
+ }
+
+ internal void checksum()
+ {
+ uint crc_reg=0;
+ uint a, b;
+
+ for(int i=0;i> 24) & 0xff;
+ crc_reg = (crc_reg<<8)^crc_lookup[a^b];
+ //crc_reg = (crc_reg<<8)^(uint)(crc_lookup[((crc_reg >> 24)&0xff)^(header_base[header+i]&0xff)]);
+ }
+ for(int i=0;i> 24) & 0xff;
+ crc_reg = (crc_reg<<8)^crc_lookup[a^b];
+
+ //crc_reg = (crc_reg<<8)^(uint)(crc_lookup[((crc_reg >> 24)&0xff)^(body_base[body+i]&0xff)]);
+ }
+ header_base[header+22]=(byte)crc_reg/*&0xff*/;
+ header_base[header+23]=(byte)(crc_reg>>8)/*&0xff*/;
+ header_base[header+24]=(byte)(crc_reg>>16)/*&0xff*/;
+ header_base[header+25]=(byte)(crc_reg>>24)/*&0xff*/;
+ }
+
+ public Page()
+ {
+ for(uint i=0; i
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using System.Text;
+
+namespace csogg
+{
+ public class StreamState
+ {
+ byte[] body_data; /* bytes from packet bodies */
+ int body_storage; /* storage elements allocated */
+ int body_fill; /* elements stored; fill mark */
+ private int body_returned; /* elements of fill returned */
+
+
+ int[] lacing_vals; /* The values that will go to the segment table */
+ long[] granule_vals; /* pcm_pos values for headers. Not compact
+ this way, but it is simple coupled to the
+ lacing fifo */
+ int lacing_storage;
+ int lacing_fill;
+ int lacing_packet;
+ int lacing_returned;
+
+ public int e_o_s; /* set when we have buffered the last packet in the
+ logical bitstream */
+ int serialno;
+ int pageno;
+ long packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a seperate abstraction
+ layer) also knows about the gap */
+ long granulepos;
+
+ StreamState(int serialno) : this()
+ {
+ init(serialno);
+ }
+
+ public StreamState()
+ {
+ init();
+ }
+
+ void init()
+ {
+ body_storage=16*1024;
+ body_data=new byte[body_storage];
+ lacing_storage=1024;
+ lacing_vals=new int[lacing_storage];
+ granule_vals=new long[lacing_storage];
+ }
+ public void init(int serialno)
+ {
+ if(body_data==null){ init(); }
+ else
+ {
+ for(int i=0; i0)
+ lacing_vals[lacing_fill-1]|=0x200;
+ }
+
+ pageno=_pageno+1;
+ return(0);
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/Ogg/SyncState.cs b/SharpWave/csvorbis/Ogg/SyncState.cs
new file mode 100644
index 000000000..64008a7ff
--- /dev/null
+++ b/SharpWave/csvorbis/Ogg/SyncState.cs
@@ -0,0 +1,273 @@
+/* csogg
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+
+namespace csogg
+{
+ public class SyncState
+ {
+ public byte[] data;
+ int storage;
+ int fill;
+ int returned;
+
+ int unsynced;
+ int headerbytes;
+ int bodybytes;
+
+ public int clear()
+ {
+ data=null;
+ return(0);
+ }
+
+ // !!!!!!!!!!!!
+ // byte[] buffer(int size){
+ public int buffer(int size)
+ {
+ // first, clear out any space that has been previously returned
+ if(returned!=0)
+ {
+ fill-=returned;
+ if(fill>0)
+ {
+ Array.Copy(data, returned, data, 0, fill);
+ }
+ returned=0;
+ }
+
+ if(size>storage-fill)
+ {
+ // We need to extend the internal buffer
+ int newsize=size+fill+4096; // an extra page to be nice
+ if(data!=null)
+ {
+ byte[] foo=new byte[newsize];
+ Array.Copy(data, 0, foo, 0, data.Length);
+ data=foo;
+ }
+ else
+ {
+ data=new byte[newsize];
+ }
+ storage=newsize;
+ }
+
+ // expose a segment at least as large as requested at the fill mark
+ // return((char *)oy->data+oy->fill);
+ // return(data);
+ return(fill);
+ }
+
+ public int wrote(int bytes)
+ {
+ if(fill+bytes>storage)return(-1);
+ fill+=bytes;
+ return(0);
+ }
+
+ // sync the stream. This is meant to be useful for finding page
+ // boundaries.
+ //
+ // return values for this:
+ // -n) skipped n bytes
+ // 0) page not ready; more data (no bytes skipped)
+ // n) page synced at current location; page length n bytes
+ private Page pageseek_p=new Page();
+ private byte[] chksum=new byte[4];
+ public int pageseek(Page og)
+ {
+ int page=returned;
+ int next;
+ int bytes=fill-returned;
+
+ if(headerbytes==0)
+ {
+ int _headerbytes,i;
+ if(bytes<27)return(0); // not enough for a header
+
+ /* verify capture pattern */
+ //!!!!!!!!!!!
+ if(data[page]!='O' || data[page+1]!='g' || data[page+2]!='g' || data[page+3]!='S')
+ {
+ headerbytes=0;
+ bodybytes=0;
+
+ // search for possible capture
+ next=0;
+ for(int ii=0; iibytes)return(0);
+
+ // The whole test page is buffered. Verify the checksum
+ lock(chksum)
+ {
+ // Grab the checksum bytes, set the header field to zero
+
+ Array.Copy(data, page+22, chksum, 0, 4);
+ data[page+22]=0;
+ data[page+23]=0;
+ data[page+24]=0;
+ data[page+25]=0;
+
+ // set up a temp page struct and recompute the checksum
+ Page log=pageseek_p;
+ log.header_base=data;
+ log.header=page;
+ log.header_len=headerbytes;
+
+ log.body_base=data;
+ log.body=page+headerbytes;
+ log.body_len=bodybytes;
+ log.checksum();
+
+ // Compare
+ if(chksum[0]!=data[page+22] ||
+ chksum[1]!=data[page+23] ||
+ chksum[2]!=data[page+24] ||
+ chksum[3]!=data[page+25])
+ {
+ // D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
+ // replace the computed checksum with the one actually read in
+ Array.Copy(chksum, 0, data, page+22, 4);
+ // Bad checksum. Lose sync */
+
+ headerbytes=0;
+ bodybytes=0;
+ // search for possible capture
+ next=0;
+ for(int ii=0; ii0)
+ {
+ // have a page
+ return(1);
+ }
+ if(ret==0)
+ {
+ // need more data
+ return(0);
+ }
+
+ // head did not start a synced page... skipped some bytes
+ if(unsynced==0)
+ {
+ unsynced=1;
+ return(-1);
+ }
+ // loop. keep looking
+ }
+ }
+
+ // clear things to an initial state. Good to call, eg, before seeking
+ public int reset()
+ {
+ fill=0;
+ returned=0;
+ unsynced=0;
+ headerbytes=0;
+ bodybytes=0;
+ return(0);
+ }
+ public void init(){}
+
+ public SyncState()
+ {
+ // No constructor needed
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/StaticCodeBook.cs b/SharpWave/csvorbis/StaticCodeBook.cs
new file mode 100644
index 000000000..eea33f114
--- /dev/null
+++ b/SharpWave/csvorbis/StaticCodeBook.cs
@@ -0,0 +1,290 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+using csogg;
+
+namespace csvorbis
+{
+ class StaticCodeBook
+ {
+ internal int dim; // codebook dimensions (elements per vector)
+ internal int entries; // codebook entries
+ internal int[] lengthlist; // codeword lengths in bits
+
+ // mapping
+ internal int maptype; // 0 = none
+ // 1 = implicitly populated values from map column
+ // 2 = listed arbitrary values
+
+ // The below does a linear, single monotonic sequence mapping.
+ internal int q_min; // packed 32 bit float; quant value 0 maps to minval
+ internal int q_delta; // packed 32 bit float; val 1 - val 0 = = delta
+ internal int q_quant; // bits: 0 < quant <= 16
+ internal int q_sequencep; // bitflag
+
+ // additional information for log (dB) mapping; the linear mapping
+ // is assumed to actually be values in dB. encodebias is used to
+ // assign an error weight to 0 dB. We have two additional flags:
+ // zeroflag indicates if entry zero is to represent -Inf dB; negflag
+ // indicates if we're to represent negative linear values in a
+ // mirror of the positive mapping.
+
+ internal int[] quantlist; // map = = 1: (int)(entries/dim) element column map
+ // map = = 2: list of dim*entries quantized entry vals
+
+ internal StaticCodeBook(){}
+ internal StaticCodeBook(int dim, int entries, int[] lengthlist,
+ int maptype, int q_min, int q_delta,
+ int q_quant, int q_sequencep, int[] quantlist,
+ //EncodeAuxNearestmatch nearest_tree,
+ Object nearest_tree,
+ // EncodeAuxThreshmatch thresh_tree,
+ Object thresh_tree
+ ) : this()
+ {
+ this.dim = dim; this.entries = entries; this.lengthlist = lengthlist;
+ this.maptype = maptype; this.q_min = q_min; this.q_delta = q_delta;
+ this.q_quant = q_quant; this.q_sequencep = q_sequencep;
+ this.quantlist = quantlist;
+ }
+
+ // unpacks a codebook from the packet buffer into the codebook struct,
+ // readies the codebook auxiliary structures for decode
+ internal int unpack(csBuffer opb)
+ {
+ int i;
+ opb.read(24);
+ // first the basic parameters
+ dim = opb.read(16);
+ entries = opb.read(24);
+
+ // codeword ordering.... length ordered or unordered?
+ switch(opb.read(1))
+ {
+ case 0:
+ // unordered
+ lengthlist = new int[entries];
+
+ // allocated but unused entries?
+ if(opb.read(1) != 0)
+ {
+ // yes, unused entries
+
+ for(i = 0;ibim <= b->entries
+ // treat the above as an initial guess
+ while(true)
+ {
+ int acc = 1;
+ int acc1 = 1;
+ for(int i = 0;ientries){ return(vals); }
+ else
+ {
+ if(acc>entries){ vals--; }
+ else{ vals++; }
+ }
+ }
+ }
+
+ // unpack the quantized list of values for encode/decode
+ // we need to deal with two map types: in map type 1, the values are
+ // generated algorithmically (each column of the vector counts through
+ // the values in the quant vector). in map type 2, all the values came
+ // in in an explicit list. Both value lists must be unpacked
+ internal float[] unquantize()
+ {
+
+ if(maptype == 1 || maptype == 2)
+ {
+ int quantvals;
+ float mindel = float32_unpack(q_min);
+ float delta = float32_unpack(q_delta);
+ float[] r = new float[entries*dim];
+
+ //System.err.println("q_min = "+q_min+", mindel = "+mindel);
+
+ // maptype 1 and 2 both use a quantized value vector, but
+ // different sizes
+ switch(maptype)
+ {
+ case 1:
+ // most of the time, entries%dimensions = = 0, but we need to be
+ // well defined. We define that the possible vales at each
+ // scalar is values = = entries/dim. If entries%dim != 0, we'll
+ // have 'too few' values (values*dim> 21;
+ if((val&0x80000000) != 0)
+ mant = -mant;
+ return ldexp(mant, (int)exp - 788);
+ }
+
+ internal static float ldexp(float foo, int e)
+ {
+ return (float)(foo*Math.Pow(2, e));
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/VUtils.cs b/SharpWave/csvorbis/VUtils.cs
new file mode 100644
index 000000000..4d117cf5e
--- /dev/null
+++ b/SharpWave/csvorbis/VUtils.cs
@@ -0,0 +1,58 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+
+namespace csvorbis {
+
+ public static class VUtils {
+
+ public static int ilog(int v) {
+ int ret = 0;
+ while(v != 0) {
+ ret++;
+ v = (int)((uint)v >> 1);
+ }
+ return ret;
+ }
+
+ public static int ilog2(int v) {
+ int ret = 0;
+ while(v > 1) {
+ ret++;
+ v = (int)((uint)v >> 1);
+ }
+ return ret;
+ }
+
+ public static int icount(int v) {
+ int ret = 0;
+ while(v != 0) {
+ ret += (v&1);
+ v = (int)((uint)v >> 1);
+ }
+ return ret;
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/VorbisCodec.cs b/SharpWave/csvorbis/VorbisCodec.cs
new file mode 100644
index 000000000..02a6f3e03
--- /dev/null
+++ b/SharpWave/csvorbis/VorbisCodec.cs
@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using csogg;
+using csvorbis;
+using SharpWave.Containers;
+
+namespace SharpWave.Codecs.Vorbis {
+
+ 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 VorbisCodec() {
+ chunk = new AudioChunk();
+ }
+
+ AudioChunk chunk, rawChunk;
+ Stream input;
+ byte[] rawPcm;
+ int rawIndex;
+
+ 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(); // local working space for packet->PCM decode
+
+ byte[] buffer;
+ int bytes = 0;
+
+ public AudioFormat ReadHeader(Stream source) {
+ input = source;
+ oy.init(); // Now we can read pages
+
+ // 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;
+ bytes = input.Read(buffer, 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) return default(AudioFormat);
+ }
+
+ // 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();
+ os.pagein(og);
+ os.packetout(op);
+ vi.synthesis_headerin(vc, op);
+
+ // 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 packets, 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;
+ vi.synthesis_headerin(vc, op);
+ i++;
+ }
+ }
+ }
+
+ // no harm in not checking before adding more
+ index = oy.buffer(4096);
+ buffer = oy.data;
+ bytes = input.Read(buffer, index, 4096);
+ oy.wrote(bytes);
+ }
+
+ // 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
+
+ AudioFormat format;
+ format.Channels = vi.channels;
+ format.BitsPerSample = 16;
+ format.SampleRate = vi.rate;
+ return format;
+ }
+
+ public IEnumerable StreamData( Stream source ) {
+ // the original iterator may not always return enough samples,
+ // so we will do our own buffering here.
+
+ rawChunk = new AudioChunk();
+ foreach( AudioChunk chunk in StreamDataCore( source ) ) {
+ if( rawPcm == null )
+ InitRaw( chunk );
+ if( rawIndex + chunk.Length > rawPcm.Length )
+ ResizeRaw( rawIndex + chunk.Length );
+
+ Buffer.BlockCopy( chunk.Data, 0, rawPcm, rawIndex, chunk.Length );
+ rawIndex += chunk.Length;
+ if( rawIndex >= (vi.rate / 4) ) {
+ rawChunk.Length = rawIndex;
+ rawIndex = 0;
+ yield return rawChunk;
+ }
+ }
+
+ rawChunk.Length = rawIndex;
+ yield return rawChunk;
+ yield break;
+ }
+
+ void InitRaw(AudioChunk chunk) {
+ rawPcm = new byte[vi.rate / 4];
+ rawChunk.Data = rawPcm;
+ rawChunk.Length = rawPcm.Length;
+ }
+
+ void ResizeRaw(int newLen) {
+ byte[] oldPcm = rawPcm;
+ rawPcm = new byte[rawIndex + chunk.Length];
+ Buffer.BlockCopy( oldPcm, 0, rawPcm, 0, rawIndex );
+ rawChunk.Data = rawPcm;
+ rawChunk.Length = rawPcm.Length;
+ }
+
+ IEnumerable StreamDataCore( Stream source ) {
+ input = source;
+ int convsize = 4096 * 2;
+ byte[] convbuffer = new byte[convsize]; // take 8k out of the data segment, not the stack
+ convsize = 4096 / vi.channels;
+ oy.init(); // Now we can read pages
+
+ int eos = 0;
+ // so multiple block decodes can
+ // proceed in parallel. We could init
+ // multiple vorbis_block structures for vd here
+
+ float[][] pcm = null;
+ 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
+
+ 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) continue;
+ // missing or corrupt data at this page position
+ // no reason to complain; already complained above
+
+ // 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(ref pcm, _index)) > 0) {
+ int bout = (samples < convsize ? samples : convsize);
+
+ // convert floats to 16 bit signed ints (host order) and interleave
+ for (int ch = 0; ch < vi.channels; ch++) {
+ int ptr = ch * 2;
+ int offset = _index[ch];
+ float[] chPcm = pcm[ch];
+
+ for (int j = 0; j < bout; j++) {
+ int val = (int)(chPcm[offset + j] * 32767);
+ if (val > 32767) val = 32767;
+ if (val < -32768) val = -32768;
+ if (val < 0) val = val | 0x8000;
+
+ convbuffer[ptr] = (byte)(val);
+ convbuffer[ptr + 1] = (byte)((uint)val >> 8);
+ ptr += 2 * (vi.channels);
+ }
+ }
+
+ chunk.Data = convbuffer;
+ chunk.Length = 2 * vi.channels * bout;
+ vd.synthesis_read(bout);
+ yield return chunk;
+ }
+ }
+ if (og.eos() != 0) eos = 1;
+ }
+
+ if (eos == 0) {
+ int index = oy.buffer(4096);
+ buffer = oy.data;
+ bytes = input.Read(buffer, 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
+ vi.clear(); // must be called last
+
+ // OK, clean up the framer
+ oy.clear();
+ yield break;
+ }
+ }
+}
diff --git a/SharpWave/csvorbis/csorbisException.cs b/SharpWave/csvorbis/csorbisException.cs
new file mode 100644
index 000000000..0e039f080
--- /dev/null
+++ b/SharpWave/csvorbis/csorbisException.cs
@@ -0,0 +1,36 @@
+/* csvorbis
+ * Copyright (C) 2000 ymnk, JCraft,Inc.
+ *
+ * Written by: 2000 ymnk
+ * Ported to C# from JOrbis by: Mark Crichton
+ *
+ * Thanks go to the JOrbis team, for licencing the code under the
+ * LGPL, making my job a lot easier.
+ *
+ * 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;
+
+namespace csvorbis
+{
+ public class csorbisException : Exception
+ {
+ public csorbisException ()
+ :base(){}
+ public csorbisException (String s)
+ :base("csorbis: "+s){}
+ }
+}
diff --git a/src/Client/Platform.h b/src/Client/Platform.h
index 8c503145e..de752551d 100644
--- a/src/Client/Platform.h
+++ b/src/Client/Platform.h
@@ -117,10 +117,11 @@ ReturnCode Platform_HttpFree(void);
struct AudioFormat { UInt8 Channels, BitsPerSample; UInt16 Frequency };
#define AudioFormat_Eq(a, b) (a->Channels == b->Channels && a->BitsPerSample == b->BitsPerSample && a->Frequency == b->Frequency)
-void Platform_AudioInit(Int32* handle, UInt8 buffers);
+void Platform_AudioInit(Int32* handle, Int32 buffers);
void Platform_AudioFree(Int32 handle);
+struct AudioFormat* Platform_AudioGetFormat(Int32 handle);
void Platform_AudioSetFormat(Int32 handle, struct AudioFormat* format);
-void Platform_AudioPlayAsync(Int32 handle, void* data, UInt32 dataSize);
-Int32 Platform_AudioNextFinishedAsync(Int32 handle);
-bool Platform_AudioFinishedAsync(Int32 handle);
+void Platform_AudioPlayData(Int32 handle, Int32 idx, void* data, UInt32 dataSize);
+bool Platform_AudioIsCompleted(Int32 handle, Int32 idx);
+bool Platform_AudioIsFinished(Int32 handle);
#endif
diff --git a/src/Client/WinPlatform.c b/src/Client/WinPlatform.c
index 488e701a2..cbdd1bc3f 100644
--- a/src/Client/WinPlatform.c
+++ b/src/Client/WinPlatform.c
@@ -604,18 +604,22 @@ struct AudioContext {
HWAVEOUT Handle;
WAVEHDR Headers[AUDIO_MAX_CHUNKS];
struct AudioFormat Format;
- UInt8 NumBuffers, PlayingAsync;
+ Int32 NumBuffers;
};
struct AudioContext Audio_Contexts[20];
-void Platform_AudioInit(Int32* handle, UInt8 buffers) {
- Int32 i;
+void Platform_AudioInit(Int32* handle, Int32 buffers) {
+ Int32 i, j;
for (i = 0; i < Array_Elems(Audio_Contexts); i++) {
struct AudioContext* ctx = &Audio_Contexts[i];
if (ctx->NumBuffers) continue;
-
ctx->NumBuffers = buffers;
- *handle = i; return;
+
+ *handle = i;
+ for (j = 0; j < buffers; j++) {
+ ctx->Headers[j].dwFlags = WHDR_DONE;
+ }
+ return;
}
ErrorHandler_Fail("No free audio contexts");
}
@@ -629,6 +633,11 @@ void Platform_AudioFree(Int32 handle) {
ErrorHandler_CheckOrFail(result, "Audio - closing device");
}
+struct AudioFormat* Platform_AudioGetFormat(Int32 handle) {
+ struct AudioContext* ctx = &Audio_Contexts[handle];
+ return &ctx->Format;
+}
+
void Platform_AudioSetFormat(Int32 handle, struct AudioFormat* format) {
struct AudioContext* ctx = &Audio_Contexts[handle];
struct AudioFormat* cur = &ctx->Format;
@@ -646,19 +655,18 @@ void Platform_AudioSetFormat(Int32 handle, struct AudioFormat* format) {
fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
if (waveOutGetNumDevs() == 0u) ErrorHandler_Fail("No audio devices found");
- ReturnCode result = waveOutOpen(&ctx->Handle, UInt32_MaxValue, &fmt, NULL, NULL, CALLBACK_NULL);
+ ReturnCode result = waveOutOpen(&ctx->Handle, WAVE_MAPPER, &fmt, NULL, NULL, CALLBACK_NULL);
ErrorHandler_CheckOrFail(result, "Audio - opening device");
}
-void Platform_AudioPlayAsync(Int32 handle, void* data, UInt32 dataSize) {
+void Platform_AudioPlayData(Int32 handle, Int32 idx, void* data, UInt32 dataSize) {
struct AudioContext* ctx = &Audio_Contexts[handle];
- WAVEHDR* hdr = &ctx->Headers[0];
+ WAVEHDR* hdr = &ctx->Headers[idx];
Platform_MemSet(hdr, 0, sizeof(WAVEHDR));
hdr->lpData = data;
hdr->dwBufferLength = dataSize;
hdr->dwLoops = 1;
- ctx->PlayingAsync = true;
ReturnCode result = waveOutPrepareHeader(ctx->Handle, hdr, sizeof(WAVEHDR));
ErrorHandler_CheckOrFail(result, "Audio - prepare header");
@@ -666,29 +674,24 @@ void Platform_AudioPlayAsync(Int32 handle, void* data, UInt32 dataSize) {
ErrorHandler_CheckOrFail(result, "Audio - write header");
}
-Int32 Platform_AudioNextFinishedAsync(Int32 handle) {
+bool Platform_AudioIsCompleted(Int32 handle, Int32 idx) {
+ struct AudioContext* ctx = &Audio_Contexts[handle];
+ WAVEHDR* hdr = &ctx->Headers[idx];
+ if (!(hdr->dwFlags & WHDR_DONE)) return false;
+
+ if (hdr->dwFlags & WHDR_PREPARED) {
+ ReturnCode result = waveOutUnprepareHeader(ctx->Handle, hdr, sizeof(WAVEHDR));
+ ErrorHandler_CheckOrFail(result, "Audio - unprepare header");
+ }
+ return true;
+}
+
+bool Platform_AudioIsFinished(Int32 handle) {
struct AudioContext* ctx = &Audio_Contexts[handle];
Int32 i;
for (i = 0; i < ctx->NumBuffers; i++) {
- WAVEHDR* hdr = &ctx->Headers[i];
- if (!(hdr->dwFlags & WHDR_DONE)) continue;
-
- if (hdr->dwFlags & WHDR_PREPARED) {
- ReturnCode result = waveOutUnprepareHeader(ctx->Handle, hdr, sizeof(WAVEHDR));
- ErrorHandler_CheckOrFail(result, "Audio - unprepare header");
- }
- return i;
+ if (!Platform_AudioIsCompleted(handle, i)) return false;
}
- return -1;
-}
-
-bool Platform_AudioFinishedAsync(Int32 handle) {
- struct AudioContext* ctx = &Audio_Contexts[handle];
- if (!ctx->PlayingAsync) return true;
- Int32 index = Platform_AudioNextFinishedAsync(handle);
-
- if (index >= 0) return false;
- ctx->PlayingAsync = false;
return true;
}
#endif