public App() : base() { log = new ConsoleAL(); mainWindow = new MainWindow(); projectionWindow = new ProjectionWindow(); game = new Game(); displays = new List<ScoreDisplay>(); projectorState = ProjectorState.STAND_BY; gameState = GameState.WAITING; liveMatch = mainWindow.liveMatch; selectedTab = mainWindow.GetSelectedTab(); log.StartLog(); SetupTimer(); LoadDisplays(); LoadFileHandler(); WireHandlers(); projectionWindow.Show(); mainWindow.Show(); }
/// <summary> /// Sets up the hardware resources used by the controller. /// </summary> private ALController() { if (AL.NativeLibrary == IntPtr.Zero) { throw new DllNotFoundException( "Couldn't initialize OpenAL because the native binaries couldn't be found."); } if (!Open()) { throw new AudioHardwareException( "OpenAL device could not be initialized, see console output for details."); } Efx = new EffectsExtension(Device); if (ALC.IsExtensionPresent(Device, "ALC_EXT_CAPTURE")) { Microphone.PopulateCaptureDevices(); } // We have hardware here and it is ready _allSources = new uint[MaxNumberOfSources]; AL.GenSources(_allSources); ALHelper.CheckError("Failed to generate sources."); // TODO: allow more effects if (Efx.IsAvailable) { Filter = Efx.GenFilter(); } _availableSources = new Queue <uint>(_allSources); _sourcesInUse = new HashSet <uint>(); }
/// <summary> /// Disposes the <see cref="ALController"/>. /// </summary> /// <param name="disposing">If true, the managed resources are to be disposed.</param> private void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { Streamer.Dispose(); if (Filter != 0 && Efx.IsAvailable) { Efx.DeleteFilter(Filter); } SoundEffectInstancePool.DisposeInstances(); AL.DeleteSources(_allSources); ALHelper.CheckError("Failed to delete source."); Microphone.StopMicrophones(); DestroyContexts(); } _isDisposed = true; } }
public static bool CheckOpenALErrors(bool silent = false, [CallerMemberName] string callerInfoMember = null, [CallerFilePath] string callerInfoFile = null, [CallerLineNumber] int callerInfoLine = -1) { ALError error; bool found = false; while ((error = AL.GetError()) != ALError.NoError) { if (!silent) { Console.WriteLine( "Internal OpenAL error, code {0} at {1} in {2}, line {3}.", error, callerInfoMember, callerInfoFile, callerInfoLine); } found = true; if (!silent && System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); } } return(found); }
public long StartAudioOut(ServiceCtx Context) { if (State == AudioOutState.Stopped) { State = AudioOutState.Started; try { AudioCtx = new AudioContext(); //Create the audio context } catch (Exception) { Logging.Warn("OpenAL Error! PS: Install OpenAL Core SDK!"); OpenALInstalled = false; } if (OpenALInstalled) { AL.Listener(ALListenerf.Gain, (float)8.0); //Add more gain to it } } return(0); }
private void Initialize(byte[] data, ALFormat format, int size, int frequency, float volume, bool looping) { InitilizeSoundServices(); bufferID = AL.GenBuffer(); sourceID = AL.GenSource(); try { // loads sound into buffer AL.BufferData(bufferID, format, data, size, frequency); // binds buffer to source AL.Source(sourceID, ALSourcei.Buffer, bufferID); } catch (Exception ex) { throw ex; } Volume = volume; this.looping = looping; }
public static SoundClip LoadSound(string path) { SoundClip clip; string s = path.Substring(path.IndexOf('.')); switch (s) { case ".wav": clip = LoadWave(path); break; case ".ogg": clip = LoadOgg(path); break; default: throw new Exception("SoundFormat not recognised"); } AL.BufferData(clip.buffer, GetSoundFormat(clip.format), clip.data, clip.data.Length, clip.format.sampleRate); return(clip); }
public void Play() { var state = AL.GetSourceState(alSourceId); ALHelper.CheckError("Failed to get source state."); switch (state) { case ALSourceState.Playing: return; case ALSourceState.Paused: Resume(); return; } Prepare(); AL.SourcePlay(alSourceId); ALHelper.CheckError("Failed to play source."); Preparing = false; OggStreamer.Instance.AddStream(this); }
void ClearBuffers(int input) { if (audio_context == null || audio_context == null) { return; } int[] freedbuffers; if (input == 0) { int BuffersProcessed; AL.GetSource(src, ALGetSourcei.BuffersProcessed, out BuffersProcessed); if (BuffersProcessed == 0) { return; } freedbuffers = AL.SourceUnqueueBuffers(src, BuffersProcessed); } else { freedbuffers = AL.SourceUnqueueBuffers(src, input); } AL.DeleteBuffers(freedbuffers); }
public override void Create(int numBuffers) { bufferIDs = new uint[numBuffers]; completed = new bool[numBuffers]; for (int i = 0; i < numBuffers; i++) { completed[i] = true; } NumBuffers = numBuffers; lock (contextLock) { if (context == IntPtr.Zero) { CreateContext(); } contextRefs++; MakeContextCurrent(); AL.alDistanceModel(ALDistanceModel.None); CheckError("DistanceModel"); } Console.WriteLine("al context:" + context); }
protected override bool OnStart() { try { _al = AL.GetApi(); _alc = ALContext.GetApi(); } catch (Exception ex) { XPlane.Trace.WriteLine($"[OpenAL Sample] Failed to initialize Open AL: " + ex); return(false); } _flightLoop = FlightLoop.Create(FlightLoopPhaseType.BeforeFlightModel, InitSound); _flightLoop.Schedule(-1, false); Menu.PluginsMenu .AddItem("OpenAL Sample (Private Context)", item => item.CreateSubMenu() .AddItem("Play Sound", out _, PlaySound) ); return(true); }
public override void Dispose() { if (SourceHandle == -1) { return; } // free queued buffers AL.SourceStop(SourceHandle); AL.GetSource(SourceHandle, ALGetSourcei.BuffersQueued, out int queued); if (queued > 0) { var buffers = new int[queued]; AL.SourceUnqueueBuffers(SourceHandle, queued, buffers); foreach (int b in buffers) { AL.DeleteBuffer(b); } } AL.DeleteSource(SourceHandle); SourceHandle = -1; base.Dispose(); }
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; Open(precache: true); } } } }
private OggPlayerCommandReturn Playback_Stop(bool Internal) { if (!(m_PlayerState == OggPlayerStatus.Playing) || (m_PlayerState == OggPlayerStatus.Paused) || (m_PlayerState == OggPlayerStatus.Buffering)) { return(OggPlayerCommandReturn.InvalidCommandInThisPlayerState); } // Request stop m_StopRequested = true; // Wait a sensible time for the threads to enact this Thread.Sleep(50); // Stop player & clear buffers AL.SourceStop(m_Source); ClearBuffers(); // Reset stuff ResetPlayerCondition(); m_CurrentFile.SeekToTime(0); // Change state if (!Internal) { StateChange(OggPlayerStatus.Stopped, OggPlayerStateChanger.UserRequest); } // Done! return(OggPlayerCommandReturn.Success); }
public void OnAction(Entity entity, List <Entity> entityList) { if ((entity.Mask & MASK) == MASK) { List <IComponent> components = entity.Components; IComponent audioComponent = components.Find(delegate(IComponent component) { return(component.ComponentType == ComponentTypes.COMPONENT_AUDIO); }); IComponent positionComponent = components.Find(delegate(IComponent component) { return(component.ComponentType == ComponentTypes.COMPONENT_POSITION); }); Position((ComponentPosition)positionComponent, (ComponentAudio)audioComponent); Vector3 listenerPosition = new Vector3(0, 0, 0); Vector3 listenerDirection = new Vector3(0, 0, 0); Vector3 listenerUp = Vector3.UnitY; AL.Listener(ALListener3f.Position, ref listenerPosition); AL.Listener(ALListenerfv.Orientation, ref listenerDirection, ref listenerUp); } }
protected override void OnStop() { // Cleanup: nuke our context if we have it. This is hacky and bad - we should really destroy // our buffers and sources. I have _no_ idea if OpenAL will leak memory. if (ALC.GetCurrentContext() != default) { XPlane.Trace.WriteLine($"[OpenAL Sample] Deleting snd {_soundBuffer}"); if (_soundSource != 0) { AL.DeleteSource(_soundSource); _soundSource = 0; } if (_soundBuffer != 0) { AL.DeleteBuffer(_soundBuffer); _soundBuffer = 0; } } if (_context != default) { XPlane.Trace.WriteLine($"[OpenAL Sample] Deleting my context 0x{(ulong)_context.Handle:X8}"); ALC.MakeContextCurrent(default);
public void Update() { HashSet <OALSoundBuffer> purgeMe = new HashSet <OALSoundBuffer> (); ALSourceState state; foreach (var soundBuffer in playingSourcesCollection) { state = AL.GetSourceState(soundBuffer.SourceId); if (state == ALSourceState.Stopped) { AL.Source(soundBuffer.SourceId, ALSourcei.Buffer, 0); purgeMe.Add(soundBuffer); //Console.WriteLine ("to be recycled: " + soundBuffer.SourceId); } } foreach (var soundBuffer in purgeMe) { playingSourcesCollection.Remove(soundBuffer); RecycleSource(soundBuffer); } }
private Exception _SoundInitException; // Here to bubble back up to the developer /// <summary> /// Sets up the hardware resources used by the controller. /// </summary> private OpenALSoundController() { if (!OpenSoundController()) { return; } // We have hardware here and it is ready _bSoundAvailable = true; allSourcesArray = new int[MAX_NUMBER_OF_SOURCES]; AL.GenSources(allSourcesArray); availableSourcesCollection = new List <int> (); inUseSourcesCollection = new List <OALSoundBuffer> (); playingSourcesCollection = new List <OALSoundBuffer> (); purgeMe = new List <OALSoundBuffer> (); for (int x = 0; x < MAX_NUMBER_OF_SOURCES; x++) { availableSourcesCollection.Add(allSourcesArray [x]); } }
private void Button2_Click(object sender, EventArgs e) { AL.SourcePause(SoundSource); Playing = false; }
private void Run() { try { App.DebugLog("Started streaming custom audio @ {0}Hz", m_sampleRate); // Get number of channels and sample rate var channels = m_channels; var format = (channels == 2) ? ALFormat.Stereo16 : ALFormat.Mono16; var sampleRate = m_sampleRate; // Start reading int nextBufferIndex = 0; var shortBuffer = new short[SAMPLES_PER_BUFFER * channels]; // Loop until the we stop while (true) { // Get the queue state int queued, processed; lock (m_lock) { if (m_stopped) { break; } AL.GetSource(m_source, ALGetSourcei.BuffersQueued, out queued); AL.GetSource(m_source, ALGetSourcei.BuffersProcessed, out processed); App.CheckOpenALError(true); // Dequeued processed buffers if (processed > 0) { AL.SourceUnqueueBuffers((int)m_source, processed); App.CheckOpenALError(true); queued -= processed; processed = 0; } } // Queue some samples while (queued < m_buffers.Length) { // Generate the samples m_audioSource.GenerateSamples(this, shortBuffer, 0, SAMPLES_PER_BUFFER); // Pick an OpenAL buffer to put the samples in var alBuffer = m_buffers[nextBufferIndex]; nextBufferIndex = (nextBufferIndex + 1) % m_buffers.Length; lock (m_lock) { if (m_stopped) { break; } // Put the samples into the OpenAL buffer AL.BufferData((int)alBuffer, format, shortBuffer, SAMPLES_PER_BUFFER * channels * sizeof(short), sampleRate); App.CheckOpenALError(true); // Add the buffer to the source's queue AL.SourceQueueBuffer((int)m_source, (int)alBuffer); App.CheckOpenALError(true); } queued++; } // Play the source if it's not playing already lock (m_lock) { if (m_stopped) { break; } var state = AL.GetSourceState(m_source); if (state != ALSourceState.Playing) { if (state != ALSourceState.Initial) { App.Log("Error: Buffer overrun detected. Resuming custom audio"); } AL.SourcePlay(m_source); App.CheckOpenALError(true); } } // Sleep Thread.Sleep(UPDATE_INTERVAL_MILLIS); } App.DebugLog("Stopped streaming custom audio"); } catch (Exception e) { App.Log("Error streaming custom audio: Threw {0}: {1}", e.GetType().FullName, e.Message); App.Log(e.StackTrace); } finally { if (!m_stopped) { // Wait for complete while (true) { lock (m_lock) { if (m_stopped) { break; } var state = AL.GetSourceState(m_source); if (state != ALSourceState.Playing) { break; } } Thread.Sleep(UPDATE_INTERVAL_MILLIS); } // Stop Stop(); } } }
private void InitDS() { SoundSource = AL.GenSource(); SoundBuffer = AL.GenBuffer(); }
private void Button1_Click(object sender, EventArgs e) { AL.SourcePlay(SoundSource); Playing = true; }
void ExitOpenAL() { AL.Destroy(); }
private void LoadBuffer(uint index) { if (!(Sounds[index].Type == 2)) { System.IO.MemoryStream SoundStream = new System.IO.MemoryStream(); System.IO.BinaryWriter StreamWriter = new System.IO.BinaryWriter(SoundStream); Twinsanity.ADPCM ADPCM_Device = new Twinsanity.ADPCM(); SoundStream.Position = 44; if (Sounds[index].Type == 0) { System.IO.MemoryStream ADPCM = new System.IO.MemoryStream(); System.IO.MemoryStream PCM = new System.IO.MemoryStream(); System.IO.BinaryWriter ADPCMWriter = new System.IO.BinaryWriter(ADPCM); if (!Sounds[index].External) { MB.Position = Sounds[index].Offset + 48; ADPCMWriter.Write(MBReader.ReadBytes((int)Sounds[index].Size)); } else { ADPCMWriter.Write(Sounds[index].Stream.ToArray()); } ADPCM.Position = 0; ADPCM_Device.ADPCM2PCM(ADPCM, ref PCM); SoundStream.Position = 0; WriteHeader(ref SoundStream, Sounds[index].SampleRate, 1, (uint)PCM.Length); StreamWriter.Write(PCM.ToArray()); } else { System.IO.MemoryStream ADPCM = new System.IO.MemoryStream(); System.IO.MemoryStream ADPCM_R = new System.IO.MemoryStream(); System.IO.MemoryStream ADPCM_L = new System.IO.MemoryStream(); System.IO.MemoryStream PCM = new System.IO.MemoryStream(); System.IO.MemoryStream PCM_R = new System.IO.MemoryStream(); System.IO.MemoryStream PCM_L = new System.IO.MemoryStream(); System.IO.BinaryWriter ADPCMWriter = new System.IO.BinaryWriter(ADPCM); System.IO.BinaryWriter PCMWriter = new System.IO.BinaryWriter(PCM); if (!Sounds[index].External) { MB.Position = Sounds[index].Offset; ADPCMWriter.Write(MBReader.ReadBytes((int)Sounds[index].Size)); } else { ADPCMWriter.Write(Sounds[index].Stream.ToArray()); } ADPCM.Position = 0; ADPCM_Device.ADPCM_Demux(ADPCM, ref ADPCM_R, ref ADPCM_L, Interleave); ADPCM_R.Position = 0; PCM_R.Position = 0; ADPCM_L.Position = 0; PCM_L.Position = 0; ADPCM_Device.ADPCM2PCM(ADPCM_R, ref PCM_R); ADPCM_Device.ADPCM2PCM(ADPCM_L, ref PCM_L); ADPCM_Device.PCM_Mux(ref PCM, PCM_R, PCM_L); SoundStream.Position = 0; WriteHeader(ref SoundStream, Sounds[index].SampleRate, 2, (uint)PCM.Length); StreamWriter.Write(PCM.ToArray()); } SoundStream.Position = 0; AL.BindBufferToSource(SoundSource, SoundBuffer); AL.BufferData(SoundBuffer, ALFormat.Stereo16, SoundStream.GetBuffer(), SoundStream.GetBuffer().Length, 44100); TrackBar1.Maximum = SoundStream.GetBuffer().Length - 1; Label10.Text = "Loaded: yes"; } else { Interaction.MsgBox("No data to play"); } }
public BufferPoolItem() { BufferID = AL.GenBuffer(); }
public void ApplyVolumeSettings(double volume) { AL.Source(_sourceID, ALSourcef.Gain, (float)volume); }
private int GetSource(ALGetSourcei param) { AL.GetSource(_sourceID, param, out var value); return(value); }
/// <summary>Updates the sound component. Should be called every frame.</summary> /// <param name="timeElapsed">The time in seconds that elapsed since the last call to this function.</param> protected override void UpdateInverseModel(double timeElapsed) { /* * Set up the listener. * */ Vector3 listenerPosition = Program.Renderer.Camera.AbsolutePosition; Orientation3 listenerOrientation = new Orientation3(Program.Renderer.Camera.AbsoluteSide, Program.Renderer.Camera.AbsoluteUp, Program.Renderer.Camera.AbsoluteDirection); Vector3 listenerVelocity; if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead | Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior) { CarBase car = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar]; Vector3 diff = car.FrontAxle.Follower.WorldPosition - car.RearAxle.Follower.WorldPosition; if (diff.IsNullVector()) { listenerVelocity = car.CurrentSpeed * Vector3.Forward; } else { listenerVelocity = car.CurrentSpeed * Vector3.Normalize(diff); } } else { listenerVelocity = Vector3.Zero; } AL.Listener(ALListener3f.Position, 0.0f, 0.0f, 0.0f); AL.Listener(ALListener3f.Velocity, (float)listenerVelocity.X, (float)listenerVelocity.Y, (float)listenerVelocity.Z); var Orientation = new float[] { (float)listenerOrientation.Z.X, (float)listenerOrientation.Z.Y, (float)listenerOrientation.Z.Z, -(float)listenerOrientation.Y.X, -(float)listenerOrientation.Y.Y, -(float)listenerOrientation.Y.Z }; AL.Listener(ALListenerfv.Orientation, ref Orientation); /* * Set up the atmospheric attributes. * */ double elevation = Program.Renderer.Camera.AbsolutePosition.Y + Program.CurrentRoute.Atmosphere.InitialElevation; double airTemperature = Program.CurrentRoute.Atmosphere.GetAirTemperature(elevation); double airPressure = Program.CurrentRoute.Atmosphere.GetAirPressure(elevation, airTemperature); double speedOfSound = Program.CurrentRoute.Atmosphere.GetSpeedOfSound(airPressure, airTemperature); try { AL.SpeedOfSound((float)speedOfSound); } catch { } /* * Collect all sounds that are to be played * and ensure that all others are stopped. * */ List <SoundSourceAttenuation> toBePlayed = new List <SoundSourceAttenuation>(); for (int i = 0; i < SourceCount; i++) { if (Sources[i].State == SoundSourceState.StopPending) { /* * The sound is still playing but is to be stopped. * Stop the sound, then remove it from the list of * sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } else if (Sources[i].State == SoundSourceState.Stopped) { /* * The sound was already stopped. Remove it from * the list of sound sources. * */ Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } else if (GlobalMute) { /* * The sound is playing or about to be played, but * the global mute option is enabled. Stop the sound * sound if necessary, then remove it from the list * of sound sources if the sound is not looping. * */ if (Sources[i].State == SoundSourceState.Playing) { AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.PlayPending; Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } } else { /* * The sound is to be played or is already playing. * */ if (Sources[i].State == SoundSourceState.Playing) { int state; AL.GetSource(Sources[i].OpenAlSourceName, ALGetSourcei.SourceState, out state); if (state != (int)ALSourceState.Initial & state != (int)ALSourceState.Playing) { /* * The sound is not playing any longer. * Remove it from the list of sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; continue; } } /* * Calculate the gain, then add the sound * to the list of sounds to be played. * */ Vector3 position; switch (Sources[i].Type) { case SoundType.TrainCar: Vector3 direction; var Car = (AbstractCar)Sources[i].Parent; Car.CreateWorldCoordinates(Sources[i].Position, out position, out direction); break; default: position = Sources[i].Position; break; } Vector3 positionDifference = position - listenerPosition; double distance = positionDifference.Norm(); double radius = Sources[i].Radius; if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) { if (Sources[i].Parent != TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar]) { radius *= 0.5; } } double gain; if (distance < 2.0 * radius) { gain = 1.0 - distance * distance * (4.0 * radius - distance) / (16.0 * radius * radius * radius); } else { gain = radius / distance; } gain *= Sources[i].Volume; if (gain <= 0.0) { /* * The gain is too low. Stop the sound if playing, * but keep looping sounds pending. * */ if (Sources[i].State == SoundSourceState.Playing) { AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.PlayPending; Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } } else { /* * Add the source. * */ toBePlayed.Add(new SoundSourceAttenuation(Sources[i], gain, distance)); } } } /* * Now that we have the list of sounds that are to be played, * sort them by their gain so that we can determine and * adjust the clamp factor. * */ double clampFactor = Math.Exp(LogClampFactor); for (int i = 0; i < toBePlayed.Count; i++) { toBePlayed[i].Gain -= clampFactor * toBePlayed[i].Distance * toBePlayed[i].Distance; } toBePlayed.Sort(); for (int i = 0; i < toBePlayed.Count; i++) { toBePlayed[i].Gain += clampFactor * toBePlayed[i].Distance * toBePlayed[i].Distance; } double desiredLogClampFactor; int index = Interface.CurrentOptions.SoundNumber; if (toBePlayed.Count <= index) { desiredLogClampFactor = MinLogClampFactor; } else { double cutoffDistance = toBePlayed[index].Distance; if (cutoffDistance <= 0.0) { desiredLogClampFactor = MaxLogClampFactor; } else { double cutoffGain = toBePlayed[index].Gain; desiredLogClampFactor = Math.Log(cutoffGain / (cutoffDistance * cutoffDistance)); if (desiredLogClampFactor < MinLogClampFactor) { desiredLogClampFactor = MinLogClampFactor; } else if (desiredLogClampFactor > MaxLogClampFactor) { desiredLogClampFactor = MaxLogClampFactor; } } } const double rate = 3.0; if (LogClampFactor < desiredLogClampFactor) { LogClampFactor += timeElapsed * rate; if (LogClampFactor > desiredLogClampFactor) { LogClampFactor = desiredLogClampFactor; } } else if (LogClampFactor > desiredLogClampFactor) { LogClampFactor -= timeElapsed * rate; if (LogClampFactor < desiredLogClampFactor) { LogClampFactor = desiredLogClampFactor; } } /* * Play the sounds. * */ clampFactor = Math.Exp(LogClampFactor); for (int i = index; i < toBePlayed.Count; i++) { toBePlayed[i].Gain = 0.0; } for (int i = 0; i < toBePlayed.Count; i++) { SoundSource source = toBePlayed[i].Source; double gain = toBePlayed[i].Gain - clampFactor * toBePlayed[i].Distance * toBePlayed[i].Distance; if (gain <= 0.0) { /* * Stop the sound. * */ if (source.State == SoundSourceState.Playing) { AL.DeleteSources(1, ref source.OpenAlSourceName); source.State = SoundSourceState.PlayPending; source.OpenAlSourceName = 0; } if (!source.Looped) { source.State = SoundSourceState.Stopped; source.OpenAlSourceName = 0; } } else { /* * Ensure the buffer is loaded, then play the sound. * */ if (source.State != SoundSourceState.Playing) { LoadBuffer(source.Buffer); if (source.Buffer.Loaded) { AL.GenSources(1, out source.OpenAlSourceName); AL.Source(source.OpenAlSourceName, ALSourcei.Buffer, source.Buffer.OpenAlBufferName); } else { /* * We cannot play the sound because * the buffer could not be loaded. * */ source.State = SoundSourceState.Stopped; continue; } } Vector3 position; Vector3 velocity; switch (source.Type) { case SoundType.TrainCar: Vector3 direction; var Car = (AbstractCar)Sources[i].Parent; Car.CreateWorldCoordinates(source.Position, out position, out direction); velocity = Car.CurrentSpeed * direction; break; default: position = source.Position; velocity = Vector3.Zero; break; } position -= listenerPosition; AL.Source(source.OpenAlSourceName, ALSource3f.Position, (float)position.X, (float)position.Y, (float)position.Z); AL.Source(source.OpenAlSourceName, ALSource3f.Velocity, (float)velocity.X, (float)velocity.Y, (float)velocity.Z); AL.Source(source.OpenAlSourceName, ALSourcef.Pitch, (float)source.Pitch); AL.Source(source.OpenAlSourceName, ALSourcef.Gain, (float)gain); if (source.State != SoundSourceState.Playing) { AL.Source(source.OpenAlSourceName, ALSourceb.Looping, source.Looped); AL.SourcePlay(source.OpenAlSourceName); source.State = SoundSourceState.Playing; } } } }
/// <summary>Updates the sound component. Should be called every frame.</summary> /// <param name="timeElapsed">The time in seconds that elapsed since the last call to this function.</param> protected override void UpdateLinearModel(double timeElapsed) { /* * Set up the listener * */ Vector3 listenerPosition = Program.Renderer.Camera.AbsolutePosition; Orientation3 listenerOrientation = new Orientation3(Program.Renderer.Camera.AbsoluteSide, Program.Renderer.Camera.AbsoluteUp, Program.Renderer.Camera.AbsoluteDirection); Vector3 listenerVelocity; if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead | Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior) { CarBase car = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar]; Vector3 diff = car.FrontAxle.Follower.WorldPosition - car.RearAxle.Follower.WorldPosition; listenerVelocity = car.CurrentSpeed * Vector3.Normalize(diff) + Program.Renderer.Camera.AlignmentSpeed.Position; } else { listenerVelocity = Program.Renderer.Camera.AlignmentSpeed.Position; } AL.Listener(ALListener3f.Position, 0.0f, 0.0f, 0.0f); AL.Listener(ALListener3f.Velocity, (float)listenerVelocity.X, (float)listenerVelocity.Y, (float)listenerVelocity.Z); var Orientation = new[] { (float)listenerOrientation.Z.X, (float)listenerOrientation.Z.Y, (float)listenerOrientation.Z.Z, -(float)listenerOrientation.Y.X, -(float)listenerOrientation.Y.Y, -(float)listenerOrientation.Y.Z }; AL.Listener(ALListenerfv.Orientation, ref Orientation); /* * Set up the atmospheric attributes * */ double elevation = Program.Renderer.Camera.AbsolutePosition.Y + Program.CurrentRoute.Atmosphere.InitialElevation; double airTemperature = Program.CurrentRoute.Atmosphere.GetAirTemperature(elevation); double airPressure = Program.CurrentRoute.Atmosphere.GetAirPressure(elevation, airTemperature); double speedOfSound = Program.CurrentRoute.Atmosphere.GetSpeedOfSound(airPressure, airTemperature); try { AL.SpeedOfSound((float)speedOfSound); } catch { } /* * Update the sound sources * */ int actuallyPlaying = 0; for (int i = 0; i < SourceCount; i++) { if (Sources[i].State == SoundSourceState.StopPending) { /* * The sound is still playing but is to be stopped. * Stop the sound, then remove it from the list of * sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } else if (Sources[i].State == SoundSourceState.Stopped) { /* * The sound was already stopped. Remove it from * the list of sound sources. * */ Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } else if (GlobalMute) { /* * The sound is playing or about to be played, but * the global mute option is enabled. Stop the sound * sound if necessary, then remove it from the list * of sound sources if the sound is not looping. * */ if (Sources[i].State == SoundSourceState.Playing) { AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.PlayPending; Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } } else { /* * The sound is to be played or is already playing. * Calculate the sound gain. * */ Vector3 direction; Vector3 position; Vector3 velocity; switch (Sources[i].Type) { case SoundType.TrainCar: var Car = (AbstractCar)Sources[i].Parent; Car.CreateWorldCoordinates(Sources[i].Position, out position, out direction); velocity = Car.CurrentSpeed * direction; break; default: position = Sources[i].Position; velocity = Vector3.Zero; break; } Vector3 positionDifference = position - listenerPosition; double gain; if (GlobalMute) { gain = 0.0; } else { double distance = positionDifference.Norm(); double innerRadius = Sources[i].Radius; if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) { if (Sources[i].Parent != TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar]) { innerRadius *= 0.5; } } double outerRadius = OuterRadiusFactor * innerRadius; if (distance < outerRadius) { if (distance <= innerRadius) { gain = Sources[i].Volume; } else { gain = (distance - outerRadius) / (innerRadius - outerRadius); gain *= Sources[i].Volume; } gain = 3.0 * gain * gain - 2.0 * gain * gain * gain; } else { gain = 0.0; } } if (gain <= GainThreshold) { /* * If the gain is too low to be audible, stop the sound. * If the sound is not looping, stop it if necessary, * then remove it from the list of sound sources. * */ if (Sources[i].State == SoundSourceState.Playing) { AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.PlayPending; Sources[i].OpenAlSourceName = 0; } if (!Sources[i].Looped) { Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } } else { /* * Play the sound and update position, velocity, pitch and gain. * For non-looping sounds, check if the sound is still playing. * */ gain = (gain - GainThreshold) / (1.0 - GainThreshold); if (Sources[i].State != SoundSourceState.Playing) { LoadBuffer(Sources[i].Buffer); if (Sources[i].Buffer.Loaded) { AL.GenSources(1, out Sources[i].OpenAlSourceName); AL.Source(Sources[i].OpenAlSourceName, ALSourcei.Buffer, Sources[i].Buffer.OpenAlBufferName); } else { /* * We cannot play the sound because * the buffer could not be loaded. * */ Sources[i].State = SoundSourceState.Stopped; continue; } } AL.Source(Sources[i].OpenAlSourceName, ALSource3f.Position, (float)positionDifference.X, (float)positionDifference.Y, (float)positionDifference.Z); AL.Source(Sources[i].OpenAlSourceName, ALSource3f.Velocity, (float)velocity.X, (float)velocity.Y, (float)velocity.Z); AL.Source(Sources[i].OpenAlSourceName, ALSourcef.Pitch, (float)Sources[i].Pitch); AL.Source(Sources[i].OpenAlSourceName, ALSourcef.Gain, (float)gain); if (Sources[i].State != SoundSourceState.Playing) { AL.Source(Sources[i].OpenAlSourceName, ALSourceb.Looping, Sources[i].Looped); AL.SourcePlay(Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.Playing; } if (!Sources[i].Looped) { int state; AL.GetSource(Sources[i].OpenAlSourceName, ALGetSourcei.SourceState, out state); if (state != (int)ALSourceState.Initial & state != (int)ALSourceState.Playing) { /* * The sound is not playing any longer. * Remove it from the list of sound sources. * */ AL.DeleteSources(1, ref Sources[i].OpenAlSourceName); Sources[i].State = SoundSourceState.Stopped; Sources[i].OpenAlSourceName = 0; Sources[i] = Sources[SourceCount - 1]; SourceCount--; i--; } else { actuallyPlaying++; } } else { actuallyPlaying++; } } } } /* * Adjust the outer radius factor / the clamp factor. * */ if (actuallyPlaying >= Interface.CurrentOptions.SoundNumber - 2) { /* * Too many sounds are playing. * Reduce the outer radius factor. * */ OuterRadiusFactorSpeed -= timeElapsed; if (OuterRadiusFactorSpeed < -OuterRadiusFactorMaximumSpeed) { OuterRadiusFactorSpeed = -OuterRadiusFactorMaximumSpeed; } } else if (actuallyPlaying <= Interface.CurrentOptions.SoundNumber - 6) { /* * Only few sounds are playing. * Increase the outer radius factor. * */ OuterRadiusFactorSpeed += timeElapsed; if (OuterRadiusFactorSpeed > OuterRadiusFactorMaximumSpeed) { OuterRadiusFactorSpeed = OuterRadiusFactorMaximumSpeed; } } else { /* * Neither too many nor too few sounds are playing. * Stabilize the outer radius factor. * */ if (OuterRadiusFactorSpeed < 0.0) { OuterRadiusFactorSpeed += timeElapsed; if (OuterRadiusFactorSpeed > 0.0) { OuterRadiusFactorSpeed = 0.0; } } else { OuterRadiusFactorSpeed -= timeElapsed; if (OuterRadiusFactorSpeed < 0.0) { OuterRadiusFactorSpeed = 0.0; } } } OuterRadiusFactor += OuterRadiusFactorSpeed * timeElapsed; if (OuterRadiusFactor < OuterRadiusFactorMinimum) { OuterRadiusFactor = OuterRadiusFactorMinimum; OuterRadiusFactorSpeed = 0.0; } else if (OuterRadiusFactor > OuterRadiusFactorMaximum) { OuterRadiusFactor = OuterRadiusFactorMaximum; OuterRadiusFactorSpeed = 0.0; } }
public unsafe void UnlockBuffer(int bytes) { int processed; AL.GetSource(this._Source, ALGetSourcei.BuffersProcessed, out processed); if (processed > 0) { var bufs = AL.SourceUnqueueBuffers(this._Source, processed); foreach (var buffer in bufs) { if (buffer == 0) { continue; } var idx = Array.IndexOf(this._Buffers, buffer); if (idx != -1) { this._SamplesSent += this._BufferBytes[idx] >> (this.Host.Sound.shm.samplebits / 8 - 1); this._SamplesSent &= this.Host.Sound.shm.samples - 1; this._BufferBytes[idx] = 0; } if (!this._FreeBuffers.Contains(buffer)) { this._FreeBuffers.Enqueue(buffer); } } } if (this._FreeBuffers.Count == 0) { this.Host.Console.DPrint("UnlockBuffer: No free buffers!\n"); return; } var buf = this._FreeBuffers.Dequeue(); if (buf != 0) { AL.BufferData(buf, this._BufferFormat, this.Host.Sound.shm.buffer, this.Host.Sound.shm.speed); AL.SourceQueueBuffer(this._Source, buf); var idx = Array.IndexOf(this._Buffers, buf); if (idx != -1) { this._BufferBytes[idx] = bytes; } int state; AL.GetSource(this._Source, ALGetSourcei.SourceState, out state); if ((ALSourceState)state != ALSourceState.Playing) { AL.SourcePlay(this._Source); this.Host.Console.DPrint("Sound resumed from {0}, free {1} of {2} buffers\n", ((ALSourceState)state).ToString("F"), this._FreeBuffers.Count, this._Buffers.Length); } } }
public void ClearBuffer() { AL.SourceStop(this._Source); }