ClassiCube/ClassicalSharp/Audio/AudioPlayer.Sounds.cs

132 lines
3.7 KiB
C#

// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Threading;
using SharpWave;
using BlockID = System.UInt16;
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(Vector3I coords, BlockID old, BlockID now) {
if (now == Block.Air) {
PlayDigSound(BlockInfo.DigSounds[old]);
} else if (!game.ClassicMode) {
PlayDigSound(BlockInfo.StepSounds[now]);
}
}
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);
}
}
void PlayCurrentSound(IAudioOutput[] outputs, float volume) {
for (int i = 0; i < outputs.Length; i++) {
IAudioOutput output = outputs[i];
if (output == null) {
output = MakeOutput(1);
outputs[i] = output;
} else {
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 < outputs.Length; i++) {
IAudioOutput output = outputs[i];
if (!output.IsFinished()) continue;
PlaySound(output, volume); return;
}
}
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);
}
void DisposeOutputs(ref IAudioOutput[] outputs) {
if (outputs == null) return;
for (int i = 0; i < outputs.Length; i++) {
if (outputs[i] == null) continue;
outputs[i].Stop();
outputs[i].IsFinished(); // unqueue buffers
outputs[i].Dispose();
}
outputs = null;
}
}
}