diff --git a/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs b/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs
index 49da472f6..66124a412 100644
--- a/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs
+++ b/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs
@@ -17,7 +17,8 @@ namespace ClassicalSharp {
// Column 1
Make( -140, -150, "Use sound (WIP)", Anchor.Centre, OnWidgetClick,
g => g.UseSound ? "yes" : "no",
- (g, v) => g.UseSound = v == "yes" ),
+ (g, v) => { g.UseSound = v == "yes";
+ g.AudioManager.SetSound( g.UseSound ); } ),
Make( -140, -100, "Show hover names", Anchor.Centre, OnWidgetClick,
g => g.Players.ShowHoveredNames ? "yes" : "no",
@@ -51,7 +52,7 @@ namespace ClassicalSharp {
Make( 140, -150, "Use music (WIP)", Anchor.Centre, OnWidgetClick,
g => g.UseMusic ? "yes" : "no",
(g, v) => { g.UseMusic = v == "yes";
- g.AudioManager.SetState( g.UseMusic ); } ),
+ g.AudioManager.SetMusic( g.UseMusic ); } ),
Make( 140, -100, "View bobbing", Anchor.Centre, OnWidgetClick,
g => g.ViewBobbing ? "yes" : "no",
diff --git a/ClassicalSharp/Audio/AudioManager.Sounds.cs b/ClassicalSharp/Audio/AudioManager.Sounds.cs
new file mode 100644
index 000000000..f5029e87d
--- /dev/null
+++ b/ClassicalSharp/Audio/AudioManager.Sounds.cs
@@ -0,0 +1,104 @@
+using System;
+using System.IO;
+using System.Threading;
+using OpenTK;
+using SharpWave;
+using SharpWave.Codecs;
+using SharpWave.Codecs.Vorbis;
+
+namespace ClassicalSharp.Audio {
+
+ public sealed partial class AudioManager {
+
+ Soundboard digBoard, stepBoard;
+
+ public void SetSound( bool enabled ) {
+ if( enabled )
+ InitSound();
+ else
+ DisposeSound();
+ }
+
+ void InitSound() {
+ disposingSound = false;
+ if( digBoard == null ) InitSoundboards();
+ soundThread = MakeThread( DoSoundThread, ref soundOut,
+ "ClassicalSharp.DoSound" );
+ }
+
+ AudioChunk soundChunk = new AudioChunk();
+ object soundLock = new object();
+ volatile int soundsCount = 0;
+ const int maxSounds = 5;
+ Sound[] sounds = new Sound[maxSounds];
+ byte[][] soundDatas = new byte[maxSounds][];
+
+ void DoSoundThread() {
+ while( !disposingSound ) {
+ bool playSound = false;
+ lock( soundLock ) {
+ if( soundsCount > 0 ) {
+ soundChunk.Data = soundDatas[0];
+ Sound meta = sounds[0];
+ playSound = true;
+ RemoveOldestSound();
+
+ soundChunk.Frequency = meta.SampleRate;
+ soundChunk.BitsPerSample = meta.BitsPerSample;
+ soundChunk.Channels = meta.Channels;
+ soundChunk.BytesOffset = meta.Offset;
+ soundChunk.BytesUsed = meta.Length;
+ }
+ }
+ if( playSound )
+ soundOut.PlayRaw( soundChunk );
+ Thread.Sleep( 1 );
+ }
+ }
+
+ public void PlayDigSound( SoundType type ) {
+ PlaySound( type, digBoard );
+ }
+
+ public void PlayStepSound( SoundType type ) {
+ PlaySound( type, stepBoard );
+ }
+
+ void PlaySound( SoundType type, Soundboard board ) {
+ if( type == SoundType.None || soundOut == null )
+ return;
+ Sound sound = board.PlayRandomSound( type );
+
+ lock( soundLock ) {
+ if( soundsCount == maxSounds )
+ RemoveOldestSound();
+ sounds[soundsCount] = sound;
+ soundDatas[soundsCount] = board.Data;
+ soundsCount++;
+ }
+ }
+
+ void RemoveOldestSound() {
+ for( int i = 0; i < maxSounds - 1; i++ ) {
+ sounds[i] = sounds[i + 1];
+ soundDatas[i] = soundDatas[i + 1];
+ }
+
+ sounds[maxSounds - 1] = null;
+ soundDatas[maxSounds - 1] = null;
+ soundsCount--;
+ }
+
+ void DisposeSound() {
+ disposingSound = true;
+ DisposeOf( ref soundOut, ref soundThread );
+ }
+
+ void InitSoundboards() {
+ digBoard = new Soundboard();
+ digBoard.Init( "dig" );
+ stepBoard = new Soundboard();
+ stepBoard.Init( "step" );
+ }
+ }
+}
diff --git a/ClassicalSharp/Audio/AudioManager.cs b/ClassicalSharp/Audio/AudioManager.cs
index f64ff3009..3b9afeb4c 100644
--- a/ClassicalSharp/Audio/AudioManager.cs
+++ b/ClassicalSharp/Audio/AudioManager.cs
@@ -1,55 +1,32 @@
using System;
using System.IO;
using System.Threading;
-using OpenTK;
using SharpWave;
using SharpWave.Codecs.Vorbis;
namespace ClassicalSharp.Audio {
- public sealed class AudioManager {
+ public sealed partial class AudioManager {
IAudioOutput musicOut, soundOut;
- Soundboard digBoard, stepBoard;
string[] musicFiles;
+ Thread musicThread, soundThread;
public AudioManager() {
- digBoard = new Soundboard();
- digBoard.Init( "dig" );
- stepBoard = new Soundboard();
- stepBoard.Init( "step" );
musicFiles = Directory.GetFiles( "audio", "*.ogg" );
}
- public void SetState( bool state ) {
- if( state )
- Init();
+ public void SetMusic( bool enabled ) {
+ if( enabled )
+ InitMusic();
else
- Dispose();
+ DisposeMusic();
}
- public void Init() {
- // TODO: why is waveOut crashing?
- if( false/*Configuration.RunningOnWindows*/ ) {
- musicOut = new WinMmOut();
- soundOut = new WinMmOut();
- } else {
- musicOut = new OpenALOut();
- soundOut = new OpenALOut();
- }
-
- musicOut.Create( 5 );
- soundOut.Create( 5, musicOut );
- InitThreads();
- }
-
- Thread musicThread, soundThread;
- void InitThreads() {
+ void InitMusic() {
disposingMusic = false;
- musicThread = new Thread( DoMusicThread );
- musicThread.Name = "ClassicalSharp.DoMusicThread";
- musicThread.IsBackground = true;
- musicThread.Start();
+ musicThread = MakeThread( DoMusicThread, ref musicOut,
+ "ClassicalSharp.DoMusic" );
}
void DoMusicThread() {
@@ -68,22 +45,37 @@ namespace ClassicalSharp.Audio {
}
}
- bool disposingMusic;
+ bool disposingMusic, disposingSound;
public void Dispose() {
DisposeMusic();
DisposeSound();
}
- public void DisposeMusic() {
+ void DisposeMusic() {
disposingMusic = true;
- musicOut.Stop();
- musicThread.Join();
- musicOut.Dispose();
+ DisposeOf( ref musicOut, ref musicThread );
}
- public void DisposeSound() {
- // TODO: stop playing current sound and/or music
- soundOut.Dispose();
+ Thread MakeThread( ThreadStart func, ref IAudioOutput output, string name ) {
+ // TODO: why is waveOut crashing?
+ output = new OpenALOut();
+ output.Create( 5 );
+
+ Thread thread = new Thread( func );
+ thread.Name = name;
+ thread.IsBackground = true;
+ thread.Start();
+ return thread;
+ }
+
+ void DisposeOf( ref IAudioOutput output, ref Thread thread ) {
+ if( output == null ) return;
+ output.Stop();
+ thread.Join();
+
+ output.Dispose();
+ output = null;
+ thread = null;
}
}
}
diff --git a/ClassicalSharp/Audio/Soundboard.cs b/ClassicalSharp/Audio/Soundboard.cs
index 33dd71e31..95de232b0 100644
--- a/ClassicalSharp/Audio/Soundboard.cs
+++ b/ClassicalSharp/Audio/Soundboard.cs
@@ -14,6 +14,8 @@ namespace ClassicalSharp.Audio {
static string[] soundNames;
static Soundboard() {
soundNames = Enum.GetNames( typeof( SoundType ) );
+ for( int i = 0; i < soundNames.Length; i++ )
+ soundNames[i] = soundNames[i].ToLower();
}
public void Init( string group ) {
@@ -43,7 +45,7 @@ namespace ClassicalSharp.Audio {
if( line.Length == 0 || line[0] == '#' ) continue;
string[] parts = line.Split( ',' );
if( parts.Length < 6 ) continue;
- string name = parts[0];
+ string name = parts[0].ToLower();
int sampleRate, bitsPerSample, channels;
int offset, length;
@@ -63,19 +65,24 @@ namespace ClassicalSharp.Audio {
}
void GetGroups() {
- string last = rawSounds[0].Name;
+ string last = Group( rawSounds[0].Name );
int offset = 0, count = 0;
for( int i = 0; i < rawSounds.Count; i++ ) {
- if( rawSounds[i].Name != last ) {
+ string group = Group( rawSounds[i].Name );
+ if( group != last ) {
groupFlags[last] = (count << 12) | offset;
offset = i;
- last = rawSounds[i].Name;
+ last = group;
count = 0;
}
count++;
}
groupFlags[last] = (count << 12) | offset;
}
+
+ string Group( string name ) {
+ return name.Substring( 0, name.Length - 1 );
+ }
}
public class Sound {
diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj
index 6d688ee00..e034162f0 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
@@ -125,6 +125,7 @@
+
diff --git a/ClassicalSharp/Game/InputHandler.cs b/ClassicalSharp/Game/InputHandler.cs
index 146f41a13..823de517f 100644
--- a/ClassicalSharp/Game/InputHandler.cs
+++ b/ClassicalSharp/Game/InputHandler.cs
@@ -94,6 +94,7 @@ namespace ClassicalSharp {
if( game.Map.IsValidPos( pos ) && (block = game.Map.GetBlock( pos )) != 0
&& inv.CanDelete[block] ) {
game.ParticleManager.BreakBlockEffect( pos, block );
+ game.AudioManager.PlayDigSound( game.BlockInfo.DigSounds[block] );
game.UpdateBlock( pos.X, pos.Y, pos.Z, 0 );
game.Network.SendSetBlock( pos.X, pos.Y, pos.Z, false, (byte)inv.HeldBlock );
}