From 4d7ca25459aab60c33c2570342ae4cdef725dff8 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 27 Nov 2015 22:38:43 +1100 Subject: [PATCH] Add partially working dig sounds. --- .../2D/Screens/Menu/OptionsScreen.cs | 5 +- ClassicalSharp/Audio/AudioManager.Sounds.cs | 104 ++++++++++++++++++ ClassicalSharp/Audio/AudioManager.cs | 72 ++++++------ ClassicalSharp/Audio/Soundboard.cs | 15 ++- ClassicalSharp/ClassicalSharp.csproj | 3 +- ClassicalSharp/Game/InputHandler.cs | 1 + 6 files changed, 153 insertions(+), 47 deletions(-) create mode 100644 ClassicalSharp/Audio/AudioManager.Sounds.cs 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 ); }