First commit

This commit is contained in:
Regalis
2015-05-25 01:04:03 +03:00
commit fadb89ae9e
320 changed files with 32186 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using Subsurface.Sounds;
namespace Subsurface
{
public enum DamageSoundType { None, StructureBlunt, StructureSlash, LimbBlunt, LimbSlash, Implode }
public struct DamageSound
{
//the range of inflicted damage where the sound can be played
//(10.0f, 30.0f) would be played when the inflicted damage is between 10 and 30
public readonly Vector2 damageRange;
public readonly DamageSoundType damageType;
public readonly Sound sound;
public DamageSound(Sound sound, Vector2 damageRange, DamageSoundType damageType)
{
this.sound = sound;
this.damageRange = damageRange;
this.damageType = damageType;
}
}
static class AmbientSoundManager
{
private static Sound[] music = new Sound[4];
public static Sound[] flowSounds = new Sound[3];
private static Sound waterAmbience;
private static int waterAmbienceIndex;
private static DamageSound[] damageSounds;
public static void Init(string filePath)
{
//Sound.Loop(music[0]);
waterAmbience = Sound.Load("Content/Sounds/Water/WaterAmbience.ogg");
flowSounds[0] = Sound.Load("Content/Sounds/Water/FlowSmall.ogg");
flowSounds[1] = Sound.Load("Content/Sounds/Water/FlowMedium.ogg");
flowSounds[2] = Sound.Load("Content/Sounds/Water/FlowLarge.ogg");
XDocument doc = ToolBox.TryLoadXml(filePath);
if (doc == null) return;
var xDamageSounds = doc.Root.Elements("damagesound");
if (xDamageSounds.Count()>0)
{
damageSounds = new DamageSound[xDamageSounds.Count()];
int i = 0;
foreach (XElement element in xDamageSounds)
{
Sound sound = Sound.Load(ToolBox.GetAttributeString(element, "file", ""));
if (sound == null) continue;
DamageSoundType damageSoundType = DamageSoundType.None;
try
{
damageSoundType = (DamageSoundType)Enum.Parse(typeof(DamageSoundType),
ToolBox.GetAttributeString(element, "damagesoundtype", "None"));
}
catch
{
damageSoundType = DamageSoundType.None;
}
damageSounds[i] = new DamageSound(
sound, ToolBox.GetAttributeVector2(element, "damagerange", new Vector2(0.0f,100.0f)), damageSoundType);
i++;
}
}
//Sound.StartStream("Content/Sounds/Music/Simplex.ogg", 0.3f);
}
public static void Update()
{
float ambienceVolume = 0.5f;
float lowpassHFGain = 1.0f;
if (Character.Controlled != null)
{
AnimController animController = Character.Controlled.animController;
if (animController.HeadInWater)
{
ambienceVolume = 0.5f;
ambienceVolume += animController.limbs[0].LinearVelocity.Length();
lowpassHFGain = 0.2f;
}
}
SoundManager.LowPassHFGain = lowpassHFGain;
waterAmbienceIndex = waterAmbience.Loop(waterAmbienceIndex, ambienceVolume);
}
public static void PlayDamageSound(DamageSoundType damageType, float damage, Body body)
{
Vector2 bodyPosition = ConvertUnits.ToDisplayUnits(body.Position);
bodyPosition.Y = -bodyPosition.Y;
PlayDamageSound(damageType, damage, bodyPosition);
}
public static void PlayDamageSound(DamageSoundType damageType, float damage, Vector2 position)
{
damage = MathHelper.Clamp(damage, 0.0f, 100.0f);
var sounds = damageSounds.Where(x => damage >= x.damageRange.X && damage <= x.damageRange.Y && x.damageType == damageType).ToList();
if (sounds.Count() == 0) return;
int selectedSound = Game1.localRandom.Next(sounds.Count());
int i = 0;
foreach (var s in sounds)
{
if (i == selectedSound)
{
Debug.WriteLine(s.sound.Play(1.0f, 2000.0f, position));
Debug.WriteLine("playing: " + s.sound);
return;
}
i++;
}
}
}
}
+115
View File
@@ -0,0 +1,115 @@
using System;
using NVorbis;
using OpenTK.Audio.OpenAL;
namespace Subsurface.Sounds
{
class OggSound : IDisposable
{
//internal VorbisReader Reader { get; private set; }
//const int DefaultBufferSize = 44100;
//private VorbisReader reader;
//private SoundEffect effect;
//SoundEffectInstance instance;
public const int DefaultBufferCount = 3;
private short[] castBuffer;
private int sampleRate;
private ALFormat format;
private string file;
int alBufferId;
public int AlBufferId
{
get { return alBufferId; }
}
//public bool IsLooped { get; set; }
public static OggSound Load(string oggFile, int bufferCount = DefaultBufferCount)
{
OggSound sound = new OggSound();
sound.file = oggFile;
using (VorbisReader reader = new VorbisReader(oggFile))
{
int bufferSize = (int)reader.TotalSamples;
float[] buffer = new float[bufferSize];
sound.castBuffer = new short[bufferSize];
int readSamples = reader.ReadSamples(buffer, 0, bufferSize);
CastBuffer(buffer, sound.castBuffer, readSamples);
sound.alBufferId = AL.GenBuffer();
sound.format = reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16;
sound.sampleRate = reader.SampleRate;
//alSourceId = AL.GenSource();
AL.BufferData(sound.alBufferId, reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, sound.castBuffer,
readSamples * sizeof(short), reader.SampleRate);
}
//AL.Source(alSourceId, ALSourcei.Buffer, alBufferId);
//if (ALHelper.XRam.IsInitialized)
//{
// ALHelper.XRam.SetBufferMode(bufferCount, ref alBufferId, XRamExtension.XRamStorage.Hardware);
// ALHelper.Check();
//}
//Volume = 1;
//if (ALHelper.Efx.IsInitialized)
//{
// alFilterId = ALHelper.Efx.GenFilter();
// ALHelper.Efx.Filter(alFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass);
// ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGain, 1);
// LowPassHFGain = 1;
//}
return sound;
}
public void SetBufferData(int alBufferId)
{
AL.BufferData(alBufferId, format, castBuffer,
castBuffer.Length * sizeof(short), sampleRate);
}
static void CastBuffer(float[] inBuffer, short[] outBuffer, int length)
{
for (int i = 0; i < length; i++)
{
int temp = (int)(32767f * inBuffer[i]);
if (temp > short.MaxValue) temp = short.MaxValue;
else if (temp < short.MinValue) temp = short.MinValue;
outBuffer[i] = (short)temp;
}
}
public void Dispose()
{
//var state = AL.GetSourceState(alSourceId);
//if (state == ALSourceState.Playing || state == ALSourceState.Paused)
// Stop();
System.Diagnostics.Debug.WriteLine(alBufferId);
//AL.DeleteSource(alSourceId);
AL.DeleteBuffer(alBufferId);
//if (ALHelper.Efx.IsInitialized)
// ALHelper.Efx.DeleteFilter(alFilterId);
ALHelper.Check();
}
}
}
+573
View File
@@ -0,0 +1,573 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using NVorbis;
using OpenTK.Audio.OpenAL;
namespace Subsurface.Sounds
{
internal static class ALHelper
{
public static readonly XRamExtension XRam = new XRamExtension();
public static readonly EffectsExtension Efx = new EffectsExtension();
static ALHelper()
{
try
{
Debug.WriteLine("OpenAL Soft [" + (AL.Get(ALGetString.Version).Contains("SOFT") ? "X" : " ") + "], ");
Debug.WriteLine("X-RAM [" + (XRam.IsInitialized ? "X" : " ") + "], ");
Debug.WriteLine("Effect Extensions [" + (Efx.IsInitialized ? "X" : " ") + "]");
}
catch (Exception e)
{
DebugConsole.ThrowError("OpenAL error!", e);
}
}
[Conditional("TRACE")]
public static void TraceMemoryUsage(Action<string, int, int> logHandler)
{
var usedHeap = (double)GC.GetTotalMemory(true);
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
while (usedHeap >= 1024 && order + 1 < sizes.Length)
{
order++;
usedHeap = usedHeap / 1024;
}
//logHandler(String.Format("Total memory : {0:0.###} {1} ", usedHeap, sizes[order]), 0, 6);
}
public static void Check()
{
ALError error;
if ((error = AL.GetError()) != ALError.NoError)
{
DebugConsole.ThrowError(AL.GetErrorString(error));
}
}
}
public class OggStream : IDisposable
{
public const int DefaultBufferCount = 3;
internal readonly object stopMutex = new object();
internal readonly object prepareMutex = new object();
internal readonly int alSourceId;
internal readonly int[] alBufferIds;
readonly int alFilterId;
readonly Stream underlyingStream;
internal VorbisReader Reader { get; private set; }
internal bool Ready { get; private set; }
internal bool Preparing { get; private set; }
public int BufferCount { get; private set; }
#if TRACE
public int logX, logY;
public Action<string, int, int> LogHandler;
#endif
public OggStream(string filename, int bufferCount = DefaultBufferCount) : this(File.OpenRead(filename), bufferCount) { }
public OggStream(Stream stream, int bufferCount = DefaultBufferCount)
{
BufferCount = bufferCount;
alBufferIds = AL.GenBuffers(bufferCount);
alSourceId = AL.GenSource();
if (ALHelper.XRam.IsInitialized)
{
ALHelper.XRam.SetBufferMode(BufferCount, ref alBufferIds[0], XRamExtension.XRamStorage.Hardware);
ALHelper.Check();
}
if (ALHelper.Efx.IsInitialized)
{
alFilterId = ALHelper.Efx.GenFilter();
ALHelper.Efx.Filter(alFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass);
ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGain, 1);
LowPassHFGain = 1;
}
underlyingStream = stream;
Volume = 1;
IsLooped = true;
}
public void Prepare()
{
if (Preparing) return;
var state = AL.GetSourceState(alSourceId);
lock (stopMutex)
{
switch (state)
{
case ALSourceState.Playing:
case ALSourceState.Paused:
return;
case ALSourceState.Stopped:
lock (prepareMutex)
{
Close();
Empty();
}
break;
}
if (!Ready)
{
lock (prepareMutex)
{
Preparing = true;
//#if TRACE
// logX = 7;
// LogHandler("(*", logX, logY);
// logX += 2;
//#endif
Open(precache: true);
//#if TRACE
// LogHandler(")", logX++, logY);
//#endif
}
}
}
}
public void Play()
{
var state = AL.GetSourceState(alSourceId);
switch (state)
{
case ALSourceState.Playing: return;
case ALSourceState.Paused:
Resume();
return;
}
Prepare();
//#if TRACE
// LogHandler("{", logX++, logY);
//#endif
AL.SourcePlay(alSourceId);
try
{
ALHelper.Check();
}
catch (Exception e)
{
throw new Exception ("AIHElper", e.InnerException);
}
Preparing = false;
OggStreamer.Instance.AddStream(this);
}
public void Pause()
{
if (AL.GetSourceState(alSourceId) != ALSourceState.Playing)
return;
OggStreamer.Instance.RemoveStream(this);
//#if TRACE
// LogHandler("]", logX++, logY);
//#endif
AL.SourcePause(alSourceId);
ALHelper.Check();
}
public void Resume()
{
if (AL.GetSourceState(alSourceId) != ALSourceState.Paused)
return;
OggStreamer.Instance.AddStream(this);
#if TRACE
LogHandler("[", logX++, logY);
#endif
AL.SourcePlay(alSourceId);
ALHelper.Check();
}
public void Stop()
{
var state = AL.GetSourceState(alSourceId);
if (state == ALSourceState.Playing || state == ALSourceState.Paused)
{
//#if TRACE
// LogHandler("}", logX++, logY);
//#endif
StopPlayback();
}
lock (stopMutex)
{
OggStreamer.Instance.RemoveStream(this);
}
}
float lowPassHfGain;
public float LowPassHFGain
{
get { return lowPassHfGain; }
set
{
if (ALHelper.Efx.IsInitialized)
{
ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGainHF, lowPassHfGain = value);
ALHelper.Efx.BindFilterToSource(alSourceId, alFilterId);
ALHelper.Check();
}
}
}
float volume;
public float Volume
{
get { return volume; }
set
{
AL.Source(alSourceId, ALSourcef.Gain, volume = value);
ALHelper.Check();
}
}
public bool IsLooped { get; set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
var state = AL.GetSourceState(alSourceId);
if (state == ALSourceState.Playing || state == ALSourceState.Paused)
StopPlayback();
lock (prepareMutex)
{
OggStreamer.Instance.RemoveStream(this);
if (state != ALSourceState.Initial)
Empty();
Close();
underlyingStream.Dispose();
}
AL.DeleteSource(alSourceId);
AL.DeleteBuffers(alBufferIds);
if (ALHelper.Efx.IsInitialized)
ALHelper.Efx.DeleteFilter(alFilterId);
ALHelper.Check();
#if TRACE
ALHelper.TraceMemoryUsage(LogHandler);
#endif
}
}
void StopPlayback()
{
AL.SourceStop(alSourceId);
ALHelper.Check();
}
void Empty()
{
int queued;
AL.GetSource(alSourceId, ALGetSourcei.BuffersQueued, out queued);
if (queued > 0)
{
try
{
AL.SourceUnqueueBuffers(alSourceId, queued);
ALHelper.Check();
}
catch (InvalidOperationException)
{
// This is a bug in the OpenAL implementation
// Salvage what we can
int processed;
AL.GetSource(alSourceId, ALGetSourcei.BuffersProcessed, out processed);
var salvaged = new int[processed];
if (processed > 0)
{
AL.SourceUnqueueBuffers(alSourceId, processed, salvaged);
ALHelper.Check();
}
// Try turning it off again?
AL.SourceStop(alSourceId);
ALHelper.Check();
Empty();
}
}
//#if TRACE
// logX = 7;
// LogHandler(new string(Enumerable.Repeat(' ', Console.BufferWidth - 6).ToArray()), logX, logY);
//#endif
}
internal void Open(bool precache = false)
{
underlyingStream.Seek(0, SeekOrigin.Begin);
Reader = new VorbisReader(underlyingStream, false);
if (precache)
{
// Fill first buffer synchronously
OggStreamer.Instance.FillBuffer(this, alBufferIds[0]);
AL.SourceQueueBuffer(alSourceId, alBufferIds[0]);
ALHelper.Check();
// Schedule the others asynchronously
OggStreamer.Instance.AddStream(this);
}
Ready = true;
}
internal void Close()
{
if (Reader != null)
{
Reader.Dispose();
Reader = null;
}
Ready = false;
}
}
public class OggStreamer : IDisposable
{
const float DefaultUpdateRate = 10;
const int DefaultBufferSize = 44100;
static readonly object singletonMutex = new object();
readonly object iterationMutex = new object();
readonly object readMutex = new object();
readonly float[] readSampleBuffer;
readonly short[] castBuffer;
readonly HashSet<OggStream> streams = new HashSet<OggStream>();
readonly List<OggStream> threadLocalStreams = new List<OggStream>();
readonly Thread underlyingThread;
volatile bool cancelled;
public float UpdateRate { get; private set; }
public int BufferSize { get; private set; }
static OggStreamer instance;
public static OggStreamer Instance
{
get
{
lock (singletonMutex)
{
if (instance == null)
throw new InvalidOperationException("No instance running");
return instance;
}
}
private set { lock (singletonMutex) instance = value; }
}
public OggStreamer(int bufferSize = DefaultBufferSize, float updateRate = DefaultUpdateRate)
{
lock (singletonMutex)
{
if (instance != null)
throw new InvalidOperationException("Already running");
Instance = this;
underlyingThread = new Thread(EnsureBuffersFilled) { Priority = ThreadPriority.Lowest };
underlyingThread.Start();
}
UpdateRate = updateRate;
BufferSize = bufferSize;
readSampleBuffer = new float[bufferSize];
castBuffer = new short[bufferSize];
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (singletonMutex)
{
Debug.Assert(Instance == this, "Two instances running, somehow...?");
cancelled = true;
lock (iterationMutex)
streams.Clear();
Instance = null;
}
}
}
internal bool AddStream(OggStream stream)
{
lock (iterationMutex)
return streams.Add(stream);
}
internal bool RemoveStream(OggStream stream)
{
lock (iterationMutex)
return streams.Remove(stream);
}
public bool FillBuffer(OggStream stream, int bufferId)
{
int readSamples;
lock (readMutex)
{
readSamples = stream.Reader.ReadSamples(readSampleBuffer, 0, BufferSize);
CastBuffer(readSampleBuffer, castBuffer, readSamples);
}
AL.BufferData(bufferId, stream.Reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, castBuffer,
readSamples * sizeof (short), stream.Reader.SampleRate);
ALHelper.Check();
//#if TRACE
// stream.LogHandler(readSamples == BufferSize ? "." : "|", stream.logX++, stream.logY);
// //ALHelper.TraceMemoryUsage(stream.LogHandler);
//#endif
return readSamples != BufferSize;
}
static void CastBuffer(float[] inBuffer, short[] outBuffer, int length)
{
for (int i = 0; i < length; i++)
{
var temp = (int)(32767f * inBuffer[i]);
if (temp > short.MaxValue) temp = short.MaxValue;
else if (temp < short.MinValue) temp = short.MinValue;
outBuffer[i] = (short)temp;
}
}
void EnsureBuffersFilled()
{
while (!cancelled)
{
Thread.Sleep((int) (1000 / UpdateRate));
if (cancelled) break;
threadLocalStreams.Clear();
lock (iterationMutex) threadLocalStreams.AddRange(streams);
foreach (var stream in threadLocalStreams)
{
lock (stream.prepareMutex)
{
lock (iterationMutex)
if (!streams.Contains(stream))
continue;
bool finished = false;
int queued;
AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersQueued, out queued);
//ALHelper.Check();
int processed;
AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersProcessed, out processed);
//ALHelper.Check();
if (processed == 0 && queued == stream.BufferCount) continue;
int[] tempBuffers;
if (processed > 0)
tempBuffers = AL.SourceUnqueueBuffers(stream.alSourceId, processed);
else
tempBuffers = stream.alBufferIds.Skip(queued).ToArray();
for (int i = 0; i < tempBuffers.Length; i++)
{
finished |= FillBuffer(stream, tempBuffers[i]);
if (finished)
{
if (stream.IsLooped)
{
stream.Close();
stream.Open();
}
else
{
streams.Remove(stream);
i = tempBuffers.Length;
}
}
}
AL.SourceQueueBuffers(stream.alSourceId, tempBuffers.Length, tempBuffers);
//ALHelper.Check();
if (finished && !stream.IsLooped)
continue;
}
lock (stream.stopMutex)
{
if (stream.Preparing) continue;
lock (iterationMutex)
if (!streams.Contains(stream))
continue;
var state = AL.GetSourceState(stream.alSourceId);
if (state == ALSourceState.Stopped)
{
//#if TRACE
// stream.LogHandler("!", stream.logX++, stream.logY);
//#endif
AL.SourcePlay(stream.alSourceId);
ALHelper.Check();
}
}
}
}
}
}
}
+214
View File
@@ -0,0 +1,214 @@
using System.Collections.Generic;
using System.IO;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using Subsurface.Sounds;
namespace Subsurface
{
public class Sound
{
private static List<Sound> loadedSounds = new List<Sound>();
private OggSound oggSound;
string filePath;
public static Vector3 CameraPos;
//public float Volume
//{
// set { SoundManager.Volume(sourceIndex, value); }
//}
public string FilePath
{
get { return filePath; }
}
public int AlBufferId
{
get { return oggSound.AlBufferId; }
}
public static void Init()
{
SoundManager.Init();
}
public static Sound Load(string file)
{
if (!File.Exists(file))
{
DebugConsole.ThrowError("File ''" + file + "'' not found!");
return null;
}
Sound s = new Sound();
s.filePath = file;
foreach (Sound loadedSound in loadedSounds)
{
if (loadedSound.filePath == file) s.oggSound = loadedSound.oggSound;
}
if (s.oggSound == null)
{
s.oggSound = OggSound.Load(file);
}
loadedSounds.Add(s);
return s;
}
public int Play(float volume = 1.0f)
{
return SoundManager.Play(this, volume);
}
public int Play(float volume, float range, Vector2 position)
{
//position = new Vector2(position.X - CameraPos.X, position.Y - CameraPos.Y);
//volume = (range == 0.0f) ? 0.0f : MathHelper.Clamp(volume * (range - position.Length())/range, 0.0f, 1.0f);
int newIndex = SoundManager.Play(this, volume);
if (newIndex == -1) return -1;
return UpdatePosition(newIndex, position, range, volume);
}
public int Play(float volume, float range, Body body)
{
Vector2 bodyPosition = ConvertUnits.ToDisplayUnits(body.Position);
//bodyPosition.Y = -bodyPosition.Y;
return Play(volume, range, bodyPosition);
}
public static int UpdatePosition(int sourceIndex, Vector2 position, float range, float baseVolume = 1.0f)
{
position = new Vector2(position.X - CameraPos.X, position.Y - CameraPos.Y);
float volume = (range == 0.0f) ? 0.0f : MathHelper.Clamp(baseVolume * (range - position.Length())/range, 0.0f, 1.0f);
if (volume <= 0.0f)
{
if (sourceIndex > 0)
{
SoundManager.Stop(sourceIndex);
sourceIndex = -1;
}
return sourceIndex;
}
SoundManager.UpdateSoundPosition(sourceIndex, position, volume);
return sourceIndex;
}
public int UpdatePosition(int sourceIndex, Body body, float range, float baseVolume = 1.0f)
{
Vector2 bodyPosition = ConvertUnits.ToDisplayUnits(body.Position);
bodyPosition.Y = -bodyPosition.Y;
return UpdatePosition(sourceIndex, bodyPosition, range, baseVolume);
}
public int Loop(int sourceIndex, float volume)
{
if (volume == 0.0f)
{
if (sourceIndex > 0)
{
SoundManager.Stop(sourceIndex);
sourceIndex = -1;
}
return sourceIndex;
}
int newIndex = SoundManager.Loop(this, sourceIndex, volume);
return newIndex;
}
public int Loop(int sourceIndex, float volume, Vector2 position, float range)
{
if (volume <= 0.0f)
{
if (sourceIndex > 0)
{
SoundManager.Stop(sourceIndex);
sourceIndex = -1;
}
return sourceIndex;
}
int newIndex = SoundManager.Loop(this, sourceIndex, volume);
return UpdatePosition(newIndex, position, range, volume);
}
//public int Loop(float volume = 1.0f)
//{
// return SoundManager.Loop(this, volume);
//}
//public void Pause()
//{
// SoundManager.Pause(this);
//}
//public void Resume()
//{
// SoundManager.Resume(this);
//}
//public void Stop()
//{
// SoundManager.Stop(this);
//}
public void Remove()
{
loadedSounds.Remove(this);
System.Diagnostics.Debug.WriteLine(this.AlBufferId);
foreach (Sound s in loadedSounds)
{
if (s.oggSound == oggSound) return;
}
SoundManager.ClearAlSource(this.AlBufferId);
oggSound.Dispose();
}
public static void StartStream(string file, float volume = 1.0f)
{
SoundManager.StartStream(file, volume);
}
public static void Stoptream()
{
SoundManager.StopStream();
}
public static void Dispose()
{
SoundManager.Dispose();
}
}
}
+299
View File
@@ -0,0 +1,299 @@
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
namespace Subsurface.Sounds
{
static class SoundManager
{
public const int DefaultSourceCount = 16;
private static List<int> alSources = new List<int>();
private static int[] alBuffers = new int[DefaultSourceCount];
private static int lowpassFilterId;
static AudioContext AC;
public static OggStreamer oggStreamer;
public static OggStream oggStream;
public static void Init()
{
AC = new AudioContext();
for (int i = 0 ; i < DefaultSourceCount; i++)
{
alSources.Add(AL.GenSource());
}
if (ALHelper.Efx.IsInitialized)
{
lowpassFilterId = ALHelper.Efx.GenFilter();
//alFilters.Add(alFilterId);
ALHelper.Efx.Filter(lowpassFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass);
//LowPassHFGain = 1;
}
}
//public SoundManager(int bufferCount = DefaultSourceCount)
//{
// Stopwatch sw = new Stopwatch();
// sw.Start();
// alSourceId = AL.GenSource();
// //AL.Source(alSourceId, ALSourcei.Buffer, alBufferId);
// Volume = 1;
// if (ALHelper.Efx.IsInitialized)
// {
// alFilterId = ALHelper.Efx.GenFilter();
// ALHelper.Efx.Filter(alFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass);
// ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGain, 1);
// LowPassHFGain = 1;
// }
// sw.Stop();
// System.Diagnostics.Debug.WriteLine("oggsource: "+sw.ElapsedMilliseconds);
//}
// public static int Play(Sound sound, float volume = 1.0f)
// {
// return Play(sound, volume, new Vector2(0.0f, 0.0f));
//}
public static int Play(Sound sound, float volume = 1.0f)
{
//for (int i = 2; i < DefaultSourceCount; i++)
//{
// AL.SourceStop(alSources[i]);
// AL.Source(alSources[i], ALSourceb.Looping, false);
// System.Diagnostics.Debug.WriteLine(i + ": " + AL.GetSourceState(alSources[i]));
// System.Diagnostics.Debug.WriteLine(AL.GetSourceType(alSources[i]));
//}
for (int i = 1; i < DefaultSourceCount; i++)
{
//find a source that's free to use (not playing or paused)
if (AL.GetSourceState(alSources[i]) == ALSourceState.Playing
|| AL.GetSourceState(alSources[i]) == ALSourceState.Paused) continue;
//if (position!=Vector2.Zero)
// position /= 1000.0f;
alBuffers[i]=sound.AlBufferId;
AL.Source(alSources[i], ALSourceb.Looping, false);
AL.Source(alSources[i], ALSource3f.Position, 0.0f, 0.0f, 0.0f);
AL.Source(alSources[i], ALSourcei.Buffer, sound.AlBufferId);
AL.Source(alSources[i], ALSourcef.Gain, volume);
//AL.Source(alSources[i], ALSource3f.Position, position.X, position.Y, 0.0f);
AL.SourcePlay(alSources[i]);
//sound.sourceIndex = i;
return i;
}
return -1;
}
public static int Loop(Sound sound, int sourceIndex, float volume)
{
if (sourceIndex<1)
{
sourceIndex = Play(sound, volume);
if (sourceIndex>0)
{
AL.Source(alSources[sourceIndex], ALSourceb.Looping, true);
AL.Source(alSources[sourceIndex], ALSourcef.Gain, volume);
}
return sourceIndex;
}
else
{
AL.Source(alSources[sourceIndex], ALSourceb.Looping, true);
AL.Source(alSources[sourceIndex], ALSourcef.Gain, volume);
return sourceIndex;
}
}
//public static int Loop(int sourceIndex, float volume = 1.0f)
//{
// if (sourceIndex > 0 && alSources[sourceIndex]>0)
// {
// ALSourceState state = AL.GetSourceState(alSources[sourceIndex]);
// ALHelper.Check();
// if (state == ALSourceState.Playing) return sourceIndex;
// }
// int newSourceIndex = Play(sound, volume);
// AL.Source(alSources[sourceIndex], ALSourceb.Looping, true);
// return sourceIndex;
//}
public static void Pause(int sourceIndex)
{
if (AL.GetSourceState(alSources[sourceIndex]) != ALSourceState.Playing)
return;
AL.SourcePause(alSources[sourceIndex]);
ALHelper.Check();
}
public static void Resume(int sourceIndex)
{
if (AL.GetSourceState(alSources[sourceIndex]) != ALSourceState.Paused)
return;
Debug.WriteLine("sourceplay");
AL.SourcePlay(alSources[sourceIndex]);
ALHelper.Check();
}
public static void Stop(int sourceIndex)
{
if (sourceIndex < 1) return;
var state = AL.GetSourceState(alSources[sourceIndex]);
if (state == ALSourceState.Playing || state == ALSourceState.Paused)
{
AL.SourceStop(alSources[sourceIndex]);
AL.Source(alSources[sourceIndex], ALSourceb.Looping, false);
}
}
public static bool IsPlaying(int sourceIndex)
{
if (sourceIndex < 1) return false;
var state = AL.GetSourceState(alSources[sourceIndex]);
return (state == ALSourceState.Playing);
}
public static void Volume(int sourceIndex, float volume)
{
AL.Source(alSources[sourceIndex], ALSourcef.Gain, volume);
ALHelper.Check();
}
//int alFilterId;
static float lowPassHfGain;
public static float LowPassHFGain
{
get { return lowPassHfGain; }
set
{
if (ALHelper.Efx.IsInitialized)
{
for (int i = 0; i < DefaultSourceCount; i++)
{
//find a source that's free to use (not playing or paused)
if (AL.GetSourceState(alSources[i]) != ALSourceState.Playing
&& AL.GetSourceState(alSources[i])!= ALSourceState.Paused) continue;
ALHelper.Efx.Filter(lowpassFilterId, EfxFilterf.LowpassGainHF, lowPassHfGain = value);
ALHelper.Efx.BindFilterToSource(alSources[i], lowpassFilterId);
ALHelper.Check();
}
}
}
}
//float volume;
//public float Volume
//{
// get { return volume; }
// set
// {
// AL.Source(alSourceId, ALSourcef.Gain, volume = value);
// ALHelper.Check();
// }
//}
public static void UpdateSoundPosition(int sourceIndex, Vector2 position, float baseVolume = 1.0f)
{
if (sourceIndex < 1) return;
//Resume(sourceIndex);
position/= 1000.0f;
//System.Diagnostics.Debug.WriteLine("updatesoundpos: "+offset);
AL.Source(alSources[sourceIndex], ALSourcef.Gain, baseVolume);
AL.Source(alSources[sourceIndex], ALSource3f.Position, position.X, position.Y, 0.0f);
}
public static OggStream StartStream(string file, float volume = 1.0f)
{
if (oggStreamer == null)
oggStreamer = new OggStreamer();
oggStream = new OggStream(file);
oggStreamer.AddStream(oggStream);
oggStream.Volume = volume;
oggStream.Play();
return oggStream;
}
public static void StopStream()
{
if (oggStream!=null) oggStream.Stop();
}
public static void ClearAlSource(int bufferId)
{
for (int i = 1; i < DefaultSourceCount; i++)
{
if (alBuffers[i] == bufferId)
{
AL.Source(alSources[i], ALSourcei.Buffer, 0);
}
}
}
public static void Dispose()
{
if (ALHelper.Efx.IsInitialized)
ALHelper.Efx.DeleteFilter(lowpassFilterId);
for (int i = 0; i < DefaultSourceCount; i++)
{
var state = AL.GetSourceState(alSources[i]);
if (state == ALSourceState.Playing || state == ALSourceState.Paused)
Stop(i);
AL.DeleteSource(alSources[i]);
ALHelper.Check();
}
if (oggStream!=null)
{
oggStream.Stop();
oggStream.Dispose();
}
if (oggStreamer != null)
oggStreamer.Dispose();
}
}
}