ClassiCube/ClassicalSharp/Audio/AudioPlayer.Sounds.cs
2016-08-30 12:49:24 +10:00

130 lines
3.4 KiB
C#

// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
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 SetSound( bool enabled ) {
if( enabled )
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( game.BlockInfo.DigSounds[e.OldBlock] );
else
PlayDigSound( game.BlockInfo.StepSounds[e.Block] );
}
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.PickRandomSound( type );
if( snd == null ) return;
chunk.Channels = snd.Channels;
chunk.Frequency = snd.SampleRate;
chunk.BitsPerSample = snd.BitsPerSample;
chunk.BytesOffset = 0;
chunk.BytesUsed = snd.Data.Length;
chunk.Data = snd.Data;
if( snd.Channels == 1 ) {
PlayCurrentSound( monoOutputs );
} else if( snd.Channels == 2 ) {
PlayCurrentSound( stereoOutputs );
}
}
IAudioOutput firstSoundOut;
void PlayCurrentSound( IAudioOutput[] outputs ) {
for( int i = 0; i < monoOutputs.Length; i++ ) {
IAudioOutput output = outputs[i];
if( output == null ) {
output = GetPlatformOut();
output.Create( 1, firstSoundOut );
if( firstSoundOut == null )
firstSoundOut = output;
outputs[i] = output;
}
if( !output.DoneRawAsync() ) continue;
try {
output.PlayRawAsync( chunk );
} catch( InvalidOperationException ex ) {
HandleSoundError( ex );
}
return;
}
}
void HandleSoundError( 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." );
SetSound( false );
game.UseSound = false;
}
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;
}
}
}