/// <summary> /// Creates a new OpenALDataBuffer. /// </summary> /// <returns>OpenALDataBuffer</returns> public static OpenALDataBuffer CreateBuffer() { var bufferId = new uint[1]; OpenAL.alGenBuffers(1, bufferId); return(new OpenALDataBuffer(bufferId[0])); }
public void QueuePlayback(AudioSource audioSource, byte[] data) { if (this.isDisposed) { throw new ObjectDisposedException("OpenALPlaybackProvider"); } if (audioSource == null) { throw new ArgumentNullException("audioSource"); } Stack <SourceBuffer> bufferStack; if (!this.buffers.TryGetValue(audioSource, out bufferStack)) { this.buffers[audioSource] = bufferStack = new Stack <SourceBuffer>(); } lock (this.pool.SyncRoot) { Source source = this.pool.RequestSource(audioSource); Tuple <float, float> gain; if (this.gains.TryGetValue(audioSource, out gain)) { source.Gain = gain.Item2; } else { source.Gain = this.normalGain; } const int bufferLen = 4; if (data.Length == 0) { return; } if (!source.IsPlaying) { OpenAL.DebugFormat("{0} bound to {1} isn't playing, inserting silent buffers", audioSource, source); RequireBuffers(bufferStack, source, bufferLen); for (int i = 0; i < bufferLen; ++i) { OpenALAudioFormat format = audioSource.CodecSettings.ToOpenALFormat(); SourceBuffer wait = bufferStack.Pop(); wait.Buffer(new byte[format.GetBytes((uint)audioSource.CodecSettings.FrameSize)], format, (uint)audioSource.CodecSettings.SampleRate); source.QueueAndPlay(wait); } } RequireBuffers(bufferStack, source, 1); SourceBuffer buffer = bufferStack.Pop(); buffer.Buffer(data, audioSource.CodecSettings.ToOpenALFormat(), (uint)audioSource.CodecSettings.SampleRate); source.QueueAndPlay(buffer); } }
protected void Dispose(bool disposing) { if (this.isDisposed) { return; } OpenAL.DebugFormat("Freeing OpenALPlaybackProvider. Disposing: ", disposing); if (disposing) { this.pool.Dispose(); if (this.device != null) { this.device.Dispose(); } } SourceBuffer.Clear(); OpenALRunner.RemoveUser(); OpenALRunner.RemovePlaybackProvider(this); this.pool = null; this.device = null; this.isDisposed = true; }
internal static void AddUser() { OpenAL.Debug("Adding OpenAL user"); int now = Interlocked.Increment(ref counter); if (now != 1 || running) { return; } lock (SyncRoot) { if (running) { return; } running = true; (runnerThread = new Thread(Runner) { IsBackground = true, Name = "OpenAL Runner" }).Start(); } }
internal static void AddPlaybackProvider(OpenALPlaybackProvider provider) { OpenAL.Debug("Adding OpenAL Playback Provider"); if (provider == null) { throw new ArgumentNullException("provider"); } lock (PlaybackProviders) PlaybackProviders.Add(provider); }
internal static void RemoveCaptureProvider(OpenALCaptureProvider provider) { OpenAL.Debug("Removing OpenAL Capture Provider"); if (provider == null) { throw new ArgumentNullException("provider"); } lock (CaptureProviders) CaptureProviders.Remove(provider); }
void SoundThread() { Profiler.SetThread(); OpenAL.Initialize(); while (true) { Thread.Sleep(SleepTime); if (State.Terminated) { break; } if (!DoSound()) { return; } } }
public void FreeSource(AudioSource source) { if (this.isDisposed) { throw new ObjectDisposedException("OpenALPlaybackProvider"); } if (source == null) { throw new ArgumentNullException("source"); } OpenAL.DebugFormat("Freeing source {0}", source); lock (this.gains) this.gains = this.gains.Where(kvp => kvp.Key != source).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); buffers.Remove(source); pool.FreeSource(source); }
protected void Dispose (bool disposing) { if (this.disposed) return; OpenAL.DebugFormat ("Freeing OpenALCaptureProvider. Disposing: {0}", disposing); if (disposing) { if (IsCapturing) EndCapture(); if (this.device != null) this.device.Dispose(); } this.device = null; this.disposed = true; }
internal static void RemoveUser() { OpenAL.Debug("Removing OpenAL user"); int now = Interlocked.Decrement(ref counter); if (now != 0 || !running) { return; } lock (SyncRoot) { if (!running) { return; } running = false; } }
void Sound() { Profiler.Start(); try { WatchdogToken.Ping(); var viewer = Game.RenderProcess.Viewer; if (viewer == null) { return; } OpenAL.alListenerf(OpenAL.AL_GAIN, Program.Simulator.Paused ? 0 : (float)Game.Settings.SoundVolumePercent / 100f); // Update activity sounds if (viewer.Simulator.SoundNotify != Event.None) { if (viewer.World.GameSounds != null) { viewer.World.GameSounds.HandleEvent(viewer.Simulator.SoundNotify); } viewer.Simulator.SoundNotify = Event.None; } // Update all sound in our list //float UpdateInterrupts = 0; StartUpdateTime = viewer.RealTime; int RetryUpdate = 0; int restartIndex = -1; while (RetryUpdate >= 0) { bool updateInterrupted = false; lock (SoundSources) { UpdateCounter++; UpdateCounter %= FULLUPDATECYCLE; var removals = new List <KeyValuePair <object, SoundSourceBase> >(); #if DEBUG_SOURCE_SOURCES SoundSrcBaseCount += SoundSources.Count; #endif foreach (var sources in SoundSources) { restartIndex++; #if DEBUG_SOURCE_SOURCES SoundSrcCount += sources.Value.Count; if (sources.Value.Count < 1) { NullSoundSrcBaseCount++; //Trace.TraceInformation("Null SoundSourceBase {0}", sources.Key.ToString()); } #endif if (restartIndex >= RetryUpdate) { for (int i = 0; i < sources.Value.Count; i++) { if (!sources.Value[i].NeedsFrequentUpdate && UpdateCounter > 0) { continue; } if (!sources.Value[i].Update() && viewer.Simulator.GameSpeed <= 1) { Trace.TraceInformation("Sound Update return False"); // This doesn't seem to be needed - cleanup when a train is removed seems to do it anyway. //removals.Add(new KeyValuePair<object, SoundSourceBase>(sources.Key, sources.Value[i])); } } } // Check if Add or Remove Sound Sources is waiting to get in - allow it if so. // Update can be a (relatively) long process. if (ASyncUpdatePending > 0) { updateInterrupted = true; RetryUpdate = restartIndex; //Trace.TraceInformation("Sound Source Updates Interrupted: {0}, Restart Index:{1}", UpdateInterrupts, restartIndex); break; } } if (!updateInterrupted) { RetryUpdate = -1; } #if DEBUG_SOURCE_SOURCES Trace.TraceInformation("SoundProcess: sound source self-removal on " + Thread.CurrentThread.Name); #endif // Remove Sound Sources for train no longer active. This doesn't seem to be necessary - // cleanup when a train is removed seems to do it anyway with hardly any delay. foreach (var removal in removals) { // If either of the key or value no longer exist, we can't remove them - so skip over them. if (SoundSources.ContainsKey(removal.Key) && SoundSources[removal.Key].Contains(removal.Value)) { removal.Value.Uninitialize(); SoundSources[removal.Key].Remove(removal.Value); if (SoundSources[removal.Key].Count == 0) { SoundSources.Remove(removal.Key); } } } } //Update check for activity sounds if (ORTSActSoundSourceList != null) { ORTSActSoundSourceList.Update(); } } //if (UpdateInterrupts > 1) // Trace.TraceInformation("Sound Source Update Interrupted more than once: {0}", UpdateInterrupts); // <CSComment> the block below could provide better sound response but is more demanding in terms of CPU time, especially for slow CPUs /* int resptime = (int)((viewer.RealTime - StartUpdateTime) * 1000); * SleepTime = 50 - resptime; * if (SleepTime < 5) * SleepTime = 5;*/ #if DEBUG_SOURCE_SOURCES SoundTime += (int)((viewer.RealTime - StartUpdateTime) * 1000); if (viewer.RealTime - ConsoleWriteTime >= 15f) { Console.WriteLine("SoundSourceBases (Null): {0} ({1}), SoundSources: {2}, Time: {3}ms", (int)(SoundSrcBaseCount / UpdateCounter), (int)(NullSoundSrcBaseCount / UpdateCounter), (int)(SoundSrcCount / UpdateCounter), (int)(SoundTime / UpdateCounter)); ConsoleWriteTime = viewer.RealTime; SoundTime = 0; UpdateCounter = 0; SoundSrcCount = 0; SoundSrcBaseCount = 0; NullSoundSrcBaseCount = 0; } #endif } finally { Profiler.Stop(); } }
public IEnumerable <IAudioDevice> GetDevices() { return(OpenAL.GetPlaybackDevices()); }
/// <summary> /// Updates the form content. Warning: Creates garbage - Not any more I hope - Dennis /// </summary> void UpdateContent() { var soundSources = Viewer.SoundProcess.SoundSources; activeSoundList.BeginUpdate(); inactiveSoundList.BeginUpdate(); for (int i = 0; i < activeSoundList.Nodes.Count; i++) { activeSoundList.Nodes[i].Nodes.Clear(); } for (int i = 0; i < inactiveSoundList.Nodes.Count; i++) { inactiveSoundList.Nodes[i].Nodes.Clear(); } lock (Viewer.SoundProcess.SoundSources) { foreach (var src in soundSources.Values) { foreach (var ssb in src) { if (ssb is SoundSource) { AddToForm((SoundSource)ssb); } else if (ssb is TrackSoundSource) { var ts = (TrackSoundSource)ssb; if (ts._activeInSource != null) { AddToForm(ts._activeInSource); } if (ts._activeOutSource != null) { AddToForm(ts._activeOutSource); } } } } CleanUp(activeSoundList.Nodes); CleanUp(inactiveSoundList.Nodes); activeSoundList.EndUpdate(); inactiveSoundList.EndUpdate(); // Fill selected node's data if (activeSoundList.SelectedNode != lastActSelectedNode) { selectedNode = activeSoundList.SelectedNode; lastActSelectedNode = activeSoundList.SelectedNode; inactiveSoundList.SelectedNode = null; lastInActSelectedNode = null; } else if (inactiveSoundList.SelectedNode != lastInActSelectedNode) { selectedNode = inactiveSoundList.SelectedNode; lastInActSelectedNode = inactiveSoundList.SelectedNode; activeSoundList.SelectedNode = null; lastActSelectedNode = null; } if (selectedNode != null && selectedNode.Tag is SoundSource && (SoundSource)selectedNode.Tag != null) { selectedSoundSource = (SoundSource)selectedNode.Tag; int soundSourceID = -1; int i = -1; if (selectedSoundSource.SoundStreams.Count > 0) { while (++i < selectedSoundSource.SoundStreams.Count) { soundSourceID = selectedSoundSource.SoundStreams[i].ALSoundSource.SoundSourceID; if (soundSourceID != -1) { break; } } } if (selectedSoundSource.WorldLocation != WorldLocation.None && selectedSoundSource.SoundStreams.Count > 0) { //Source distance: distance.Text = Math.Sqrt(selectedSoundSource.DistanceSquared).ToString("F1"); //Stream distance: //float[] pos = new float[3]; //OpenAL.alGetSource3f(soundSourceID, OpenAL.AL_POSITION, out pos[0], out pos[1], out pos[2]); //float[] lpos = new float[3]; //OpenAL.alGetListener3f(OpenAL.AL_POSITION, out lpos[0], out lpos[1], out lpos[2]); //for (var j = 0; j < 3; j++) // pos[j] -= lpos[j]; //distance.Text = Math.Sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]).ToString("F1"); } else { distance.Text = "-"; } int relative; OpenAL.alGetSourcei(soundSourceID, OpenAL.AL_SOURCE_RELATIVE, out relative); sound3D.Checked = relative == OpenAL.AL_FALSE; if (selectedSoundSource.Car != null) { speed.Text = Math.Abs(selectedSoundSource.Car.SpeedMpS).ToString("F1"); var Variable1 = selectedSoundSource.Car.Variable1; var Variable2 = selectedSoundSource.Car.Variable2; var Variable3 = selectedSoundSource.Car.Variable3; if (selectedSoundSource.Car is MSTSSteamLocomotive) { Variable1 /= 100f; Variable2 /= 100f; Variable3 /= 100f; } if (selectedSoundSource.Car is MSTSElectricLocomotive) { Variable1 /= 100f; Variable2 /= 100f; } variable1.Text = Variable1.ToString("0.#%"); variable2.Text = Variable2.ToString("0.#%"); variable3.Text = Variable3.ToString("0.#%"); } else { speed.Text = "-"; variable1.Text = "-"; variable2.Text = "-"; variable3.Text = "-"; } float gain; OpenAL.alGetSourcef(soundSourceID, OpenAL.AL_GAIN, out gain); smsVolume.Text = gain.ToString("0.#%"); } else { distance.Text = "-"; speed.Text = "-"; variable1.Text = "-"; variable2.Text = "-"; variable3.Text = "-"; smsVolume.Text = "-"; activeSoundList.SelectedNode = null; inactiveSoundList.SelectedNode = null; } waves.Text = SoundItem.AllPieces.Count.ToString(); alSources.Text = ALSoundSource.ActiveCount.ToString(); } }
/// <summary> /// Updates the form content. Warning: Creates garbage /// </summary> void UpdateContent() { var soundSources = Viewer.SoundProcess.GetSoundSources(); activeSoundList.BeginUpdate(); inactiveSoundList.BeginUpdate(); for (int i = 0; i < activeSoundList.Nodes.Count; i++) { activeSoundList.Nodes[i].Nodes.Clear(); } for (int i = 0; i < inactiveSoundList.Nodes.Count; i++) { inactiveSoundList.Nodes[i].Nodes.Clear(); } foreach (var src in soundSources.Values) { foreach (var ssb in src) { if (ssb is SoundSource) { var ss = (SoundSource)ssb; TreeNode node; var nodeString = String.Format("{0}: {1} ", ss.Car != null ? ss.Car.UiD.ToString() : "-", ss.SMSFileName); var nodeKey = nodeString + ss.GetHashCode().ToString(); if (ss.Active) { int index = activeSoundList.Nodes.IndexOfKey(nodeKey); if (index == -1) { activeSoundList.Nodes.Add(nodeKey, nodeString); index = activeSoundList.Nodes.IndexOfKey(nodeKey); } node = activeSoundList.Nodes[index]; } else { int index = inactiveSoundList.Nodes.IndexOfKey(nodeKey); if (index == -1) { inactiveSoundList.Nodes.Add(nodeKey, nodeString); index = inactiveSoundList.Nodes.IndexOfKey(nodeKey); } node = inactiveSoundList.Nodes[index]; } node.Tag = ss; var activeSS = 0; foreach (var soundStream in ss.SoundStreams) { var playingData = soundStream.ALSoundSource.GetPlayingData(); if (playingData[0] != "-1") { activeSS++; } var streamString = String.Format("{0} {1} (cue: {2}) {3}", playingData); var streamKey = streamString + soundStream.GetHashCode().ToString(); node.Nodes.Add(streamKey, streamString); node.Nodes[streamKey].Tag = soundStream; } node.Text = string.Format("{0}({1}{2}", node.Text.Split('(')[0], activeSS, @"@"); } else { } } } CleanUp(activeSoundList.Nodes); CleanUp(inactiveSoundList.Nodes); // Fill selected node's data var selectedNode = activeSoundList.SelectedNode; if (selectedNode == null) { selectedNode = inactiveSoundList.SelectedNode; } if (selectedNode != null && selectedNode.Tag is SoundSource) { selectedSoundSource = (SoundSource)selectedNode.Tag; } else { selectedSoundSource = null; } if (selectedSoundSource != null) { int soundSourceID = -1; int i = -1; if (selectedSoundSource.SoundStreams.Count > 0) { while (++i < selectedSoundSource.SoundStreams.Count) { soundSourceID = selectedSoundSource.SoundStreams[i].ALSoundSource.SoundSourceID; if (soundSourceID != -1) { break; } } } if (selectedSoundSource.WorldLocation != WorldLocation.None && selectedSoundSource.SoundStreams.Count > 0) { //Source distance: //distance.Text = Math.Sqrt(selectedSoundSource.DistanceSquared).ToString("F1"); //Stream distance: float[] pos = new float[3]; OpenAL.alGetSource3f(soundSourceID, OpenAL.AL_POSITION, out pos[0], out pos[1], out pos[2]); float[] lpos = new float[3]; OpenAL.alGetListener3f(OpenAL.AL_POSITION, out lpos[0], out lpos[1], out lpos[2]); for (var j = 0; j < 3; j++) { pos[j] -= lpos[j]; } distance.Text = Math.Sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]).ToString("F1"); } else { distance.Text = "-"; } int relative; OpenAL.alGetSourcei(soundSourceID, OpenAL.AL_SOURCE_RELATIVE, out relative); sound3D.Checked = relative == OpenAL.AL_FALSE; if (selectedSoundSource.Car != null) { speed.Text = Math.Abs(selectedSoundSource.Car.SpeedMpS).ToString("F1"); var Variable1 = selectedSoundSource.Car.Variable1; var Variable2 = selectedSoundSource.Car.Variable2; var Variable3 = selectedSoundSource.Car.Variable3; if (selectedSoundSource.Car is MSTSSteamLocomotive) { Variable1 /= 100f; Variable2 /= 100f; Variable3 /= 100f; } if (selectedSoundSource.Car is MSTSElectricLocomotive) { Variable1 /= 100f; Variable2 /= 100f; } variable1.Text = Variable1.ToString("0.#%"); variable2.Text = Variable2.ToString("0.#%"); variable3.Text = Variable3.ToString("0.#%"); } else { speed.Text = "0"; variable1.Text = "-"; variable2.Text = "-"; variable3.Text = "-"; } float gain; OpenAL.alGetSourcef(soundSourceID, OpenAL.AL_GAIN, out gain); smsVolume.Text = gain.ToString("0.#%"); } activeSoundList.EndUpdate(); inactiveSoundList.EndUpdate(); waves.Text = SoundItem.AllPieces.Count.ToString(); alSources.Text = ALSoundSource.ActiveCount.ToString(); }
public IEnumerable<IAudioDevice> GetDevices () { return OpenAL.GetCaptureDevices(); }
public void UpdateSoundPosition() { if (Car.SoundSourceIDs.Count == 0 || Viewer.Camera == null) { return; } if (Car.Train != null) { var realSpeedMpS = Car.SpeedMpS; //TODO Following if block is needed due to physics flipping when using rear cab // If such physics flipping is removed next block has to be removed. if (Car is MSTSLocomotive) { var loco = Car as MSTSLocomotive; if (loco.UsingRearCab) { realSpeedMpS = -realSpeedMpS; } } Vector3 directionVector = Vector3.Multiply(Car.WorldPosition.XNAMatrix.Forward, realSpeedMpS); Velocity = new float[] { directionVector.X, directionVector.Y, -directionVector.Z }; } else { Velocity = new float[] { 0, 0, 0 } }; // TODO This entire block of code (down to TODO END) should be inside the SoundProcess, not here. SoundLocation = new WorldLocation(Car.WorldPosition.WorldLocation); SoundLocation.NormalizeTo(Camera.SoundBaseTile.X, Camera.SoundBaseTile.Y); float[] position = new float[] { SoundLocation.Location.X, SoundLocation.Location.Y, SoundLocation.Location.Z }; // make a copy of SoundSourceIDs, but check that it didn't change during the copy; if it changed, try again up to 5 times. var sSIDsFinalCount = -1; var sSIDsInitCount = -2; int[] soundSourceIDs = { 0 }; int trialCount = 0; try { while (sSIDsInitCount != sSIDsFinalCount && trialCount < 5) { sSIDsInitCount = Car.SoundSourceIDs.Count; soundSourceIDs = Car.SoundSourceIDs.ToArray(); sSIDsFinalCount = Car.SoundSourceIDs.Count; trialCount++; } } catch { Trace.TraceInformation("Skipped update of position and speed of sound sources"); return; } if (trialCount >= 5) { return; } foreach (var soundSourceID in soundSourceIDs) { Viewer.Simulator.updaterWorking = true; if (OpenAL.alIsSource(soundSourceID)) { OpenAL.alSourcefv(soundSourceID, OpenAL.AL_POSITION, position); OpenAL.alSourcefv(soundSourceID, OpenAL.AL_VELOCITY, Velocity); } Viewer.Simulator.updaterWorking = false; } // TODO END } }