bool AllocateSource(out uint source, int priority) { while (!Ready) { } if (freeSources.Count > 0) { return(freeSources.TryDequeue(out source)); } else { //Try and stop playing oldest lower priority source for (int i = 0; i < sfxInstances.Count; i++) { var info = Instances[sfxInstances[i]]; if (info.Instance != null && info.Instance.Priority <= priority) { if (info.Source != uint.MaxValue) { Al.alSourceStopv(1, ref info.Source); Al.alSourcei(info.Source, Al.AL_BUFFER, 0); info.Instance.Stopped(); } Instances[sfxInstances[i]].Source = uint.MaxValue; sfxInstances.RemoveAt(i); source = info.Source; return(true); } } source = uint.MaxValue; return(false); } }
static void SetPropertiesAl(uint src, ref SourceProperties prop, int flags) { if ((flags & FLAG_POS) == FLAG_POS) { Al.alSourcei(src, Al.AL_SOURCE_RELATIVE, prop.Is3D ? 0 : 1); Al.alSource3f(src, Al.AL_POSITION, prop.Position.X, prop.Position.Y, prop.Position.Z); } if ((flags & FLAG_VEL) == FLAG_VEL) { Al.alSource3f(src, Al.AL_VELOCITY, prop.Velocity.X, prop.Velocity.Y, prop.Velocity.Z); } if ((flags & FLAG_DIRECTION) == FLAG_DIRECTION) { Al.alSource3f(src, Al.AL_DIRECTION, prop.Direction.X, prop.Direction.Y, prop.Direction.Z); } if ((flags & FLAG_GAIN) == FLAG_GAIN) { Al.alSourcef(src, Al.AL_GAIN, prop.Gain); } if ((flags & FLAG_PITCH) == FLAG_PITCH) { Al.alSourcef(src, Al.AL_PITCH, prop.Pitch); } if ((flags & FLAG_DIST) == FLAG_DIST) { Al.alSourcef(src, Al.AL_REFERENCE_DISTANCE, prop.ReferenceDistance); Al.alSourcef(src, Al.AL_MAX_DISTANCE, prop.MaxDistance); } if ((flags & FLAG_CONE) == FLAG_CONE) { Al.alSourcef(src, Al.AL_CONE_INNER_ANGLE, prop.ConeInnerAngle); Al.alSourcef(src, Al.AL_CONE_OUTER_ANGLE, prop.ConeOuterAngle); Al.alSourcef(src, Al.AL_CONE_OUTER_GAIN, prop.ConeOuterGain); } }
public void Play(bool loop = false, float timeOffset = 0) { if (ID == uint.MaxValue) { throw new ObjectDisposedException("SoundInstance"); } var props = properties; if (!gainSet) { UpdateAttenuation(); } dirtyFlags = 0; Playing = true; man.Do(() => { var src = man.AM_GetInstanceSource(ID, true); if (src == uint.MaxValue) { dirtyFlags = int.MaxValue; Playing = false; return; } SetPropertiesAl(src, ref props, int.MaxValue); if (timeOffset > 0) { Al.alSourcef(src, Al.AL_SEC_OFFSET, timeOffset); } Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID); Al.alSourcei(src, Al.AL_LOOPING, loop ? 1 : 0); Al.alSourcePlay(src); man.AM_AddInstance(ID); }); }
public void SetGain(float gain) { if (Active) { Al.alSourcef(ID, Al.AL_GAIN, gain); } Al.CheckErrors(); }
public void SetAttenuation(float attenuation) { if (Active) { Al.alSourcef(ID, Al.AL_GAIN, ALUtils.DbToAlGain(attenuation) * man.GetVolume(SoundType.Sfx)); } Al.CheckErrors(); }
public void SetPitch(float pitch) { if (Active) { Al.alSourcef(ID, Al.AL_PITCH, pitch); } Al.CheckErrors(); }
public void SetVelocity(Vector3 pos) { if (Active) { Al.alSource3f(ID, Al.AL_VELOCITY, pos.X, pos.Y, pos.Z); } Al.CheckErrors(); }
public void Stop() { if (Active) { Al.alSourceStopv(1, ref ID); Al.CheckErrors(); Active = false; } }
public static void CheckErrors() { int error; if ((error = Al.alGetError()) != Al.AL_NO_ERROR) { throw new InvalidOperationException(Al.GetString(error)); } }
public void StopAllSfx() { Actions.Enqueue(() => { foreach (var sfx in sfxInstances) { Al.alSourceStopv(1, ref sfx.ID); } sfxInstances.Clear(); }); }
void _Begin() { if (playing) { Cleanup(); } dataleft = true; playing = true; var bytes = ArrayPool <byte> .Shared.Rent(POOL_BUFFER_SIZE); for (int i = 0; i < 3; i++) { var b = manager.Buffers.Dequeue(); int read = Read(bytes, sound.Data); if (read != 0) { try { Al.BufferData(b, sound.Format, bytes, read, sound.Frequency); } catch (Exception) { FLLog.Error("AL", $"Error in source {info}"); throw; } Al.alSourceQueueBuffers(ID, 1, ref b); } else { manager.Buffers.Enqueue(b); } if (read < POOL_BUFFER_SIZE) { if (!looping) { dataleft = false; break; } else { sound.Data.Seek(0, SeekOrigin.Begin); } } } ArrayPool <byte> .Shared.Return(bytes); Al.alSourcef(ID, Al.AL_GAIN, ALUtils.ClampVolume(_gain)); Al.alSourcePlay(ID); manager.activeStreamers.Add(this); }
public void Stop() { uint _id = ID; Playing = false; man.Do(() => { var src = man.AM_GetInstanceSource(_id, false); if (src != uint.MaxValue) { Al.alSourceStopv(1, ref src); } }); }
public void SetPosition(Vector3 pos) { if (float.IsNaN(pos.X) || float.IsNaN(pos.Y) || float.IsNaN(pos.Z)) { //NaN ??? - Exit FLLog.Error("Sound", "Attempted to set NaN pos"); return; } if (Active) { Al.alSource3f(ID, Al.AL_POSITION, pos.X, pos.Y, pos.Z); } Al.CheckErrors(); }
void Cleanup() { playing = false; Al.alSourceStopv(1, ref ID); int p = 0; Al.alGetSourcei(ID, Al.AL_BUFFERS_PROCESSED, out p); for (int i = 0; i < p; i++) { uint buf = 0; Al.alSourceUnqueueBuffers(ID, 1, ref buf); manager.Buffers.Enqueue(buf); } sound.Data.Seek(0, SeekOrigin.Begin); }
public void PlaySound(SoundData data, float volume = 1f) { uint src; if (!AllocateSource(out src)) { return; } Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID); Al.alSourcef(src, Al.AL_GAIN, volume); Al.alSourcePlay(src); toAdd.Enqueue(new SoundEffectInstance() { ID = src }); }
public void Update() { if (running) { //Run actions Action toRun; while (actions.TryDequeue(out toRun)) { toRun(); } //update SFX for (int i = sfxInstances.Count - 1; i >= 0; i--) { var src = Instances[sfxInstances[i]].Source; var instance = Instances[sfxInstances[i]].Instance; if (src == uint.MaxValue) { continue; } int state; Al.alGetSourcei(src, Al.AL_SOURCE_STATE, out state); if (state == Al.AL_STOPPED) { Al.alSourcei(src, Al.AL_BUFFER, 0); freeSources.Enqueue(src); Instances[sfxInstances[i]].Source = uint.MaxValue; instance?.Stopped(); sfxInstances.RemoveAt(i); i--; } } //update Streaming //Task.Run(() => //{ foreach (var item in activeStreamers) { item.Update(); } foreach (var item in toRemove) { activeStreamers.Remove(item); item.OnStopped(); } toRemove.Clear(); //}); } }
void _Begin() { if (playing) { Cleanup(); } dataleft = true; playing = true; var bytes = BufferAllocator.AllocateBytes(); for (int i = 0; i < 3; i++) { var b = manager.Buffers.Dequeue(); int read = sound.Data.Read(bytes, 0, bytes.Length); if (read != 0) { Al.BufferData(b, sound.Format, bytes, read, sound.Frequency); Al.CheckErrors(); Al.alSourceQueueBuffers(ID, 1, ref b); Al.CheckErrors(); } else { manager.Buffers.Enqueue(b); } if (read < bytes.Length) { if (!looping) { dataleft = false; break; } else { sound.Data.Seek(0, SeekOrigin.Begin); } } } BufferAllocator.Free(bytes); Al.alSourcef(ID, Al.AL_GAIN, ALUtils.ClampVolume(_gain)); Al.alSourcePlay(ID); Al.CheckErrors(); manager.activeStreamers.Add(this); }
public AudioManager(IUIThread uithread) { UIThread = uithread; audioThreadId = Thread.CurrentThread.ManagedThreadId; initTask = Task.Run(() => { Platform.RegisterDllMap(typeof(AudioManager).Assembly); Music = new MusicPlayer(this); //Init context dev = Alc.alcOpenDevice(null); ctx = Alc.alcCreateContext(dev, IntPtr.Zero); Alc.alcMakeContextCurrent(ctx); for (int i = 0; i < MAX_SOURCES; i++) { freeSources.Enqueue(Al.GenSource()); } for (int i = 0; i < MAX_STREAM_BUFFERS; i++) { Buffers.Enqueue(Al.GenBuffer()); } Instances = new InstanceInfo[MAX_INSTANCES]; for (int i = 0; i < MAX_INSTANCES; i++) { Instances[i].Source = uint.MaxValue; freeInstances.Enqueue((uint)i); } uint musicSource; for (int i = 0; i < 2; i++) { while (!freeSources.TryDequeue(out musicSource)) { } streamingSources.Enqueue(musicSource); } FLLog.Debug("Audio", "Audio initialised"); Al.alListenerf(Al.AL_GAIN, ALUtils.ClampVolume(ALUtils.LinearToAlGain(_masterVolume))); Ready = true; }); }
public void PlaySound(Stream stream, float volume = 1f) { uint src; if (!AllocateSource(out src)) { return; } var data = AllocateData(); data.LoadStream(stream); Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID); Al.alSourcef(src, Al.AL_GAIN, volume); Al.alSourcePlay(src); toAdd.Enqueue(new SoundEffectInstance() { ID = src, Dispose = data }); }
public void ReleaseAllSfx() { actions.Enqueue(() => { foreach (var sfx in sfxInstances) { var id = Instances[sfx].Source; if (id != uint.MaxValue) { Al.alSourceStopv(1, ref id); Al.alSourcei(id, Al.AL_BUFFER, 0); freeSources.Enqueue(id); Instances[sfx].Source = uint.MaxValue; } Instances[sfx].Instance?.Stopped(); Instances[sfx].Instance?.Dispose(true); } sfxInstances.Clear(); }); }
public void LoadStream(Stream stream) { using (var snd = SoundLoader.Open(stream)) { byte[] data; if (snd.Size != -1) { data = new byte[snd.Size]; System.Diagnostics.Trace.Assert(snd.Data.Read(data, 0, snd.Size) == snd.Size); } else { using (var mem = new MemoryStream()) { snd.Data.CopyTo(mem); data = mem.GetBuffer(); } } Al.BufferData(ID, snd.Format, data, data.Length, snd.Frequency); } }
public SoundInstance PlaySound(SoundData data, bool loop = false, float volume = 1f, float minD = -1, float maxD = -1, Vector3?posv = null, SoundData dispose = null, Action onFinish = null) { uint src; if (!AllocateSource(out src)) { return(null); } Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID); Al.alSourcef(src, Al.AL_GAIN, volume); Al.alSourcei(src, Al.AL_LOOPING, loop ? 1 : 0); if (posv != null) { Al.alSourcei(src, Al.AL_SOURCE_RELATIVE, 0); var pos = posv.Value; Al.alSource3f(src, Al.AL_POSITION, pos.X, pos.Y, pos.Z); } else { Al.alSourcei(src, Al.AL_SOURCE_RELATIVE, 1); Al.alSource3f(src, Al.AL_POSITION, 0, 0, 0); } if (minD != -1 && maxD != -1) { Al.alSourcef(src, Al.AL_REFERENCE_DISTANCE, minD); Al.alSourcef(src, Al.AL_MAX_DISTANCE, maxD); } Al.alSourcePlay(src); var inst = new SoundInstance(src) { Dispose = dispose, OnFinish = onFinish }; toAdd.Enqueue(inst); return(inst); }
public bool Update() { bool hadData = dataleft; //Do things if (dataleft) { int processed; Al.alGetSourcei(ID, Al.AL_BUFFERS_PROCESSED, out processed); var bytes = ArrayPool <byte> .Shared.Rent(POOL_BUFFER_SIZE); for (int i = 0; i < processed; i++) { uint buf = 0; Al.alSourceUnqueueBuffers(ID, 1, ref buf); int read = Read(bytes, sound.Data); if (read != 0) { try { Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency); } catch (Exception) { FLLog.Error("AL", $"Error in source {info}"); throw; } Al.alSourceQueueBuffers(ID, 1, ref buf); if (read < POOL_BUFFER_SIZE) { if (looping) { sound.Data.Seek(0, SeekOrigin.Begin); } else { dataleft = false; } } } else { if (looping) { sound.Data.Seek(0, SeekOrigin.Begin); read = sound.Data.Read(bytes, 0, POOL_BUFFER_SIZE); Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency); Al.alSourceQueueBuffers(ID, 1, ref buf); } else { dataleft = false; manager.Buffers.Enqueue(buf); break; } } } ArrayPool <byte> .Shared.Return(bytes); } //Return buffers int val; Al.alGetSourcei(ID, Al.AL_SOURCE_STATE, out val); if (val != Al.AL_PLAYING && val != Al.AL_PAUSED) { if (hadData) { FLLog.Warning("Audio", "Buffer underrun"); Al.alSourcePlay(ID); } else { CleanupDelayed(); return(false); } } return(true); }
void UpdateThread() { audioThreadId = Thread.CurrentThread.ManagedThreadId; //Init context IntPtr dev = Alc.alcOpenDevice(null); IntPtr ctx = Alc.alcCreateContext(dev, IntPtr.Zero); Alc.alcMakeContextCurrent(ctx); Al.CheckErrors(); for (int i = 0; i < MAX_SOURCES; i++) { freeSources.Enqueue(Al.GenSource()); } for (int i = 0; i < MAX_STREAM_BUFFERS; i++) { Buffers.Enqueue(Al.GenBuffer()); } Instances = new InstanceInfo[MAX_INSTANCES]; for (int i = 0; i < MAX_INSTANCES; i++) { Instances[i].Source = uint.MaxValue; freeInstances.Enqueue((uint)i); } uint musicSource; for (int i = 0; i < 2; i++) { while (!freeSources.TryDequeue(out musicSource)) { } streamingSources.Enqueue(musicSource); } FLLog.Debug("Audio", "Audio initialised"); Ready = true; Al.alListenerf(Al.AL_GAIN, ALUtils.ClampVolume(ALUtils.LinearToAlGain(_masterVolume))); while (running) { //Run actions Action toRun; while (actions.TryDequeue(out toRun)) { toRun(); } //update SFX for (int i = sfxInstances.Count - 1; i >= 0; i--) { var src = Instances[sfxInstances[i]].Source; var instance = Instances[sfxInstances[i]].Instance; int state; Al.alGetSourcei(src, Al.AL_SOURCE_STATE, out state); Al.CheckErrors(); if (state == Al.AL_STOPPED) { Al.alSourcei(src, Al.AL_BUFFER, 0); freeSources.Enqueue(src); Instances[sfxInstances[i]].Source = uint.MaxValue; instance?.Stopped(); sfxInstances.RemoveAt(i); i--; } } //update Streaming foreach (var item in activeStreamers) { item.Update(); } foreach (var item in toRemove) { activeStreamers.Remove(item); item.OnStopped(); } toRemove.Clear(); Thread.Sleep((sfxInstances.Count > 0 || activeStreamers.Count > 0) ? 1 : 5); } //Delete context Alc.alcMakeContextCurrent(IntPtr.Zero); Alc.alcDestroyContext(ctx); Alc.alcCloseDevice(dev); }
public void SetListenerPosition(Vector3 pos) { Al.alListener3f(Al.AL_POSITION, pos.X, pos.Y, pos.Z); }
public bool Update() { bool hadData = dataleft; //Do things if (dataleft) { int processed; Al.alGetSourcei(ID, Al.AL_BUFFERS_PROCESSED, out processed); Al.CheckErrors(); var bytes = BufferAllocator.AllocateBytes(); for (int i = 0; i < processed; i++) { uint buf = 0; Al.alSourceUnqueueBuffers(ID, 1, ref buf); int read = sound.Data.Read(bytes, 0, bytes.Length); if (read != 0) { Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency); Al.CheckErrors(); Al.alSourceQueueBuffers(ID, 1, ref buf); Al.CheckErrors(); if (read < bytes.Length) { if (looping) { sound.Data.Seek(0, SeekOrigin.Begin); } else { dataleft = false; } } } else { if (looping) { sound.Data.Seek(0, SeekOrigin.Begin); read = sound.Data.Read(bytes, 0, bytes.Length); Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency); Al.CheckErrors(); Al.alSourceQueueBuffers(ID, 1, ref buf); Al.CheckErrors(); } else { dataleft = false; manager.Buffers.Enqueue(buf); break; } } } BufferAllocator.Free(bytes); } //Return buffers int val; Al.alGetSourcei(ID, Al.AL_SOURCE_STATE, out val); Al.CheckErrors(); if (val != Al.AL_PLAYING && val != Al.AL_PAUSED) { if (hadData) { FLLog.Warning("Audio", "Buffer underrun"); Al.alSourcePlay(ID); Al.CheckErrors(); } else { CleanupDelayed(); return(false); } } return(true); }
void UpdateThread() { //Init context IntPtr dev = Alc.alcOpenDevice(null); IntPtr ctx = Alc.alcCreateContext(dev, IntPtr.Zero); Alc.alcMakeContextCurrent(ctx); for (int i = 0; i < MAX_SOURCES; i++) { freeSources.Enqueue(Al.GenSource()); } for (int i = 0; i < MAX_BUFFERS; i++) { Buffers.Enqueue(Al.GenBuffer()); } uint musicSource; for (int i = 0; i < 2; i++) { while (!freeSources.TryDequeue(out musicSource)) { } streamingSources.Enqueue(musicSource); } FLLog.Debug("Audio", "Audio initialised"); Ready = true; while (running) { //insert into items to update while (toAdd.Count > 0) { SoundEffectInstance item; if (toAdd.TryDequeue(out item)) { sfxInstances.Add(item); } } Action toRun; if (Actions.TryDequeue(out toRun)) { toRun(); } //update SFX for (int i = sfxInstances.Count - 1; i >= 0; i--) { int state; Al.alGetSourcei(sfxInstances[i].ID, Al.AL_SOURCE_STATE, out state); if (state != Al.AL_PLAYING) { if (sfxInstances[i].Dispose != null) { sfxInstances[i].Dispose.Dispose(); } freeSources.Enqueue(sfxInstances[i].ID); sfxInstances.RemoveAt(i); i--; } } //update Streaming foreach (var item in activeStreamers) { item.Update(); } foreach (var item in toRemove) { activeStreamers.Remove(item); if (item.Stopped != null) { item.OnStopped(); } } Thread.Sleep(5); } //Delete context Alc.alcMakeContextCurrent(IntPtr.Zero); Alc.alcDestroyContext(ctx); Alc.alcCloseDevice(ctx); }
internal SoundData(AudioManager manager) { this.manager = manager; ID = Al.GenBuffer(); }
public void Dispose() { Al.alDeleteBuffers(1, ref ID); }