diff --git a/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs b/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs
index 95a402caa..9c2efe8b6 100644
--- a/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs
+++ b/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs
@@ -16,7 +16,7 @@ namespace ClassicalSharp {
buttons = new ButtonWidget[] {
// Column 1
- Make( -140, -100, "Use sound (WIP)", OnWidgetClick,
+ Make( -140, -100, "Use sound", OnWidgetClick,
g => g.UseSound ? "yes" : "no",
(g, v) => { g.UseSound = v == "yes";
g.AudioPlayer.SetSound( g.UseSound );
diff --git a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs
index 47fb75521..ec61300e4 100644
--- a/ClassicalSharp/Audio/AudioPlayer.Sounds.cs
+++ b/ClassicalSharp/Audio/AudioPlayer.Sounds.cs
@@ -11,9 +11,7 @@ namespace ClassicalSharp.Audio {
public sealed partial class AudioPlayer {
Soundboard digBoard, stepBoard;
- const int maxSounds = 10;
- Sound[] pending;
- int pendingCount;
+ const int maxSounds = 6;
public void SetSound( bool enabled ) {
if( enabled )
@@ -23,94 +21,11 @@ namespace ClassicalSharp.Audio {
}
void InitSound() {
- disposingSound = false;
if( digBoard == null )
InitSoundboards();
- int freq = digBoard.rawSounds[0].SampleRate;
- soundContainer = new BinContainer( freq, maxSounds );
- pending = new Sound[maxSounds];
- soundCodec = (BinCodec)soundContainer.GetAudioCodec();
- soundThread = MakeThread( DoSoundThread, ref soundOut,
- "ClassicalSharp.DoSound" );
- }
-
- EventWaitHandle soundHandle = new EventWaitHandle( false, EventResetMode.AutoReset );
- BinContainer soundContainer;
- BinCodec soundCodec;
-
- void DoSoundThread() {
- while( !disposingSound ) {
- soundHandle.WaitOne();
- if( disposingSound ) break;
-
- soundOut.PlayStreaming( soundContainer );
- }
- }
-
- public void Tick( double delta ) {
- if( pendingCount > 0 ) {
- Sound snd = pending[0];
- byte[] data = snd.Metadata == 1 ? digBoard.Data : stepBoard.Data;
-
- soundCodec.AddSound( data, snd.Offset, snd.Length, snd.Channels );
- RemoveFirstPendingSound();
- soundHandle.Set();
- }
- }
-
- DateTime lastDig = DateTime.MinValue;
- public void PlayDigSound( SoundType type ) {
- bool immediate = (DateTime.UtcNow - lastDig).TotalMilliseconds > 100;
- PlaySound( type, digBoard, immediate );
- lastDig = DateTime.UtcNow;
- }
-
- public void PlayStepSound( SoundType type ) {
- PlaySound( type, stepBoard, true );
- }
-
- void PlaySound( SoundType type, Soundboard board, bool immediate ) {
- if( type == SoundType.None || soundOut == null )
- return;
- Sound snd = board.PlayRandomSound( type );
- snd.Metadata = board == digBoard ? (byte)1 : (byte)2;
-
- if( immediate ) {
- byte[] data = board == digBoard ? digBoard.Data : stepBoard.Data;
- soundCodec.AddSound( data, snd.Offset, snd.Length, snd.Channels );
- soundHandle.Set();
- } else {
- if( pendingCount == maxSounds )
- RemoveFirstPendingSound();
- pending[pendingCount++] = snd;
- }
- }
-
- void MakeSound( ref Sound src, ref bool play, AudioChunk target ) {
- if( src == null ) return;
- play = true;
-
- target.Frequency = src.SampleRate;
- target.BitsPerSample = src.BitsPerSample;
- target.Channels = src.Channels;
-
- target.BytesOffset = src.Offset;
- target.BytesUsed = src.Length;
- src = null;
- }
-
- void RemoveFirstPendingSound() {
- for( int i = 1; i < maxSounds - 1; i++ )
- pending[i] = pending[i + 1];
- pending[maxSounds - 1] = null;
- pendingCount--;
- }
-
- void DisposeSound() {
- disposingSound = true;
- soundHandle.Set();
- DisposeOf( ref soundOut, ref soundThread );
+ monoOutputs = new IAudioOutput[maxSounds];
+ stereoOutputs = new IAudioOutput[maxSounds];
}
void InitSoundboards() {
@@ -119,5 +34,73 @@ namespace ClassicalSharp.Audio {
stepBoard = new Soundboard();
stepBoard.Init( "step" );
}
+
+ public void Tick( double delta ) {
+ }
+
+ public void PlayDigSound( SoundType type ) { PlaySound( type, digBoard ); }
+
+ public void PlayStepSound( SoundType type ) { PlaySound( type, stepBoard ); }
+
+ AudioChunk chunk = new AudioChunk();
+ void PlaySound( SoundType type, Soundboard board ) {
+ if( type == SoundType.None || monoOutputs == null )
+ return;
+ Sound snd = board.PlayRandomSound( type );
+ snd.Metadata = board == digBoard ? (byte)1 : (byte)2;
+ chunk.Channels = snd.Channels;
+ chunk.Frequency = snd.SampleRate;
+ chunk.BitsPerSample = snd.BitsPerSample;
+ chunk.BytesOffset = snd.Offset;
+ chunk.BytesUsed = snd.Length;
+ chunk.Data = board.Data;
+
+ if( snd.Channels == 1 )
+ PlayCurrentSound( monoOutputs );
+ else if( snd.Channels == 2 )
+ PlayCurrentSound( stereoOutputs );
+ }
+
+ void PlayCurrentSound( IAudioOutput[] outputs ) {
+ for( int i = 0; i < monoOutputs.Length; i++ ) {
+ IAudioOutput output = outputs[i];
+ if( output == null ) {
+ output = GetPlatformOut();
+ output.Create( 1 );
+ outputs[i] = output;
+ }
+
+ if( output.DoneRawAsync() ) {
+ output.PlayRawAsync( chunk );
+ return;
+ }
+ }
+ }
+
+ void DisposeSound() {
+ DisposeOutputs( ref monoOutputs );
+ DisposeOutputs( ref stereoOutputs );
+ }
+
+ 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 ) continue;
+ outputs[i].Dispose();
+ }
+ outputs = null;
+ }
}
-}
+}
\ No newline at end of file
diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs
index b538a7d14..e9c5af191 100644
--- a/ClassicalSharp/Audio/AudioPlayer.cs
+++ b/ClassicalSharp/Audio/AudioPlayer.cs
@@ -8,9 +8,10 @@ namespace ClassicalSharp.Audio {
public sealed partial class AudioPlayer {
- IAudioOutput musicOut, soundOut;
+ IAudioOutput musicOut;
+ IAudioOutput[] monoOutputs, stereoOutputs;
string[] musicFiles;
- Thread musicThread, soundThread;
+ Thread musicThread;
public AudioPlayer( Game game ) {
game.UseMusic = Options.GetBool( OptionsKey.UseMusic, false );
@@ -50,7 +51,7 @@ namespace ClassicalSharp.Audio {
}
}
- bool disposingMusic, disposingSound;
+ bool disposingMusic;
public void Dispose() {
DisposeMusic();
DisposeSound();
@@ -64,10 +65,7 @@ namespace ClassicalSharp.Audio {
}
Thread MakeThread( ThreadStart func, ref IAudioOutput output, string name ) {
- if( OpenTK.Configuration.RunningOnWindows )
- output = new WinMmOut();
- else
- output = new OpenALOut();
+ output = GetPlatformOut();
output.Create( 5 );
Thread thread = new Thread( func );
@@ -77,6 +75,12 @@ namespace ClassicalSharp.Audio {
return thread;
}
+ IAudioOutput GetPlatformOut() {
+ if( OpenTK.Configuration.RunningOnWindows )
+ return new WinMmOut();
+ return new OpenALOut();
+ }
+
void DisposeOf( ref IAudioOutput output, ref Thread thread ) {
if( output == null ) return;
output.Stop();
diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj
index 52c5cb0ce..78213fc25 100644
--- a/ClassicalSharp/ClassicalSharp.csproj
+++ b/ClassicalSharp/ClassicalSharp.csproj
@@ -4,7 +4,7 @@
{BEB1C785-5CAD-48FF-A886-876BF0A318D4}
Debug
AnyCPU
- WinExe
+ Exe
ClassicalSharp
ClassicalSharp
v2.0
diff --git a/ClassicalSharp/SharpWave.dll b/ClassicalSharp/SharpWave.dll
index f499b6fcb..b532f149c 100644
Binary files a/ClassicalSharp/SharpWave.dll and b/ClassicalSharp/SharpWave.dll differ