コード例 #1
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
        /// <summary>
        /// Setups a forced fading out.
        /// </summary>
        /// <param name="action">The action to execute once its over.</param>
        private void SetupForceFadeOut(Action action)
        {
            // Check if there is anything currently playing to fade out at all.
            if (CurrentlyPlayingFile == null || Status == SoundStatus.Stopped)
            {
                ALThread.ExecuteALThread(action);
                return;
            }

            // Check if a force fade out is already running.
            if (!_forceFadeOut)
            {
                float timeLeft = CurrentlyPlayingFile.Duration - PlaybackLocation;

                _forceFadeOut = true;
                _forceFadeOutStartDuration = PlaybackLocation;
                _forceFadeOutLength        = MathHelper.Clamp(FadeOutLength, FadeOutLength, timeLeft);
                _forceFadeOutEndEvent      = action;
            }
            else
            {
                // Chain action if a new one is added.
                Action oldAction = _forceFadeOutEndEvent;
                _forceFadeOutEndEvent = () =>
                {
                    oldAction();
                    action();
                };
            }

            Debugger.Log(MessageType.Info, MessageSource.SoundManager, $"Performing smooth fade out on {ToString()}.");
        }
コード例 #2
0
        private void SoundThreadLoop()
        {
            _audioContext = new AudioContext();
            ALThread.BindThread();

            // Setup listener.
            AL.Listener(ALListener3f.Position, 0, 0, 0);
            AL.Listener(ALListener3f.Velocity, 0, 0, 0);

            while (Context.IsRunning)
            {
                // Update running playbacks.
                lock (_layers)
                {
                    foreach (KeyValuePair <string, SoundLayer> layer in _layers)
                    {
                        layer.Value.Update();
                    }
                }

                // Run queued actions.
                ALThread.Run();

                Helpers.CheckErrorAL("loop end");

                Task.Delay(1).Wait();
            }
        }
コード例 #3
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
        /// <summary>
        /// Play a file on the layer. If any previous file is playing it will be stopped.
        /// </summary>
        /// <param name="file">The file to play.</param>
        public ContinuousAction Play(SoundFile file)
        {
            ContinuousAction thisAction = new ContinuousAction();

            void PlayInternal()
            {
                // Stop whatever was playing before.
                StopPlayingAll(true);

                // Queue the file.
                AL.SourceQueueBuffer(_pointer, file.Pointer);
                _playList.Add(file);
                Helpers.CheckErrorAL($"queuing single in source {_pointer}");
                // Play it.
                AL.SourcePlay(_pointer);
                Status = SoundStatus.Playing;
                Helpers.CheckErrorAL($"playing single in source {_pointer}");

                Debugger.Log(MessageType.Info, MessageSource.SoundManager, $"Started playing [{file.Name}] on {ToString()}.");

                thisAction.Done();
            }

            // Check if forcing a fade out.
            if (FadeOutOnChange)
            {
                SetupForceFadeOut(PlayInternal);
            }
            else
            {
                ALThread.ExecuteALThread(PlayInternal);
            }

            return(thisAction);
        }
コード例 #4
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
        /// <summary>
        /// Stop playing any files.
        /// </summary>
        /// <param name="now">Whether to stop instantly or perform FadeOutOnChange if enabled.</param>
        public ContinuousAction StopPlayingAll(bool now = false)
        {
            ContinuousAction thisAction = new ContinuousAction();

            void StopPlayingAllInternal()
            {
                Debugger.Log(MessageType.Info, MessageSource.SoundManager, $"Stopped {ToString()}.");

                // Stop playback, clear played buffer.
                AL.Source(_pointer, ALSourceb.Looping, false);
                AL.SourceStop(_pointer);

                // Remove played buffers.
                RemovePlayed();
                Status = SoundStatus.Stopped;
                Helpers.CheckErrorAL("stopping");

                // Reset tracker variables.
                PerformReset();

                thisAction.Done();
            }

            if (FadeOutOnChange && !now)
            {
                SetupForceFadeOut(StopPlayingAllInternal);
            }
            else
            {
                ALThread.ExecuteALThread(StopPlayingAllInternal);
            }

            return(thisAction);
        }
コード例 #5
0
ファイル: Sound.cs プロジェクト: simo-andreev/Emotion
 /// <summary>
 /// Wait for the sound manager to loop.
 /// </summary>
 /// <param name="loopCount">How many times it should loop.</param>
 private void WaitForSoundLoops(int loopCount)
 {
     for (int i = 0; i < loopCount + 1; i++)
     {
         ALThread.ExecuteALThread(() => { }).Wait();
         ALThread.ExecuteALThread(() => { }).Wait();
     }
 }
コード例 #6
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
        /// <summary>
        /// Creates a new sound layer. This is usually done and managed by the SoundManager object in the Context.
        /// </summary>
        /// <param name="name">The name of the layer. Used by the SoundManager to refer to the layer.</param>
        public SoundLayer(string name)
        {
            Name      = name;
            _playList = new List <SoundFile>();

            ALThread.ExecuteALThread(() =>
            {
                // Initiate source.
                _pointer = AL.GenSource();
                Helpers.CheckErrorAL("creating source");
                Debugger.Log(MessageType.Info, MessageSource.SoundManager, $"Created {ToString()}.");
            });
        }
コード例 #7
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
 /// <summary>
 /// Pause if playing.
 /// </summary>
 public void Pause()
 {
     if (Status != SoundStatus.Playing)
     {
         return;
     }
     Debugger.Log(MessageType.Trace, MessageSource.SoundManager, $"Paused {ToString()}.");
     ALThread.ExecuteALThread(() =>
     {
         AL.SourcePause(_pointer);
         Status = SoundStatus.Paused;
         Helpers.CheckErrorAL("pausing");
     });
 }
コード例 #8
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
        /// <summary>
        /// Remove played buffers from the source queue. In the playlist they are replaced by nulls.
        /// </summary>
        private void RemovePlayed()
        {
            ALThread.ForceALThread();

            AL.GetSource(_pointer, ALGetSourcei.BuffersProcessed, out int processed);
            Helpers.CheckErrorAL($"checking processed buffers of source {_pointer}");
            if (processed > 0)
            {
                AL.SourceUnqueueBuffers(_pointer, processed);
                Helpers.CheckErrorAL($"removing {processed} buffers of source {_pointer}");
                if (_playList.Count > 0)
                {
                    _playList.RemoveRange(0, Math.Min(_playList.Count, processed));
                }
                _isFirst = false;
            }
        }
コード例 #9
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
        /// <summary>
        /// Queue a file to be played on the layer.
        /// </summary>
        /// <param name="file"></param>
        public ContinuousAction QueuePlay(SoundFile file)
        {
            ContinuousAction thisAction = new ContinuousAction();

            void QueuePlayInternal()
            {
                Debugger.Log(MessageType.Info, MessageSource.SoundManager, $"Queued [{file.Name}] on {ToString()}.");

                // If playback is over but stop wasn't called then cleanup needs to be performed.
                if (Status == SoundStatus.Stopped)
                {
                    PerformReset();
                }

                AL.SourceQueueBuffer(_pointer, file.Pointer);
                _playList.Add(file);
                Helpers.CheckErrorAL($"queuing in source {_pointer}");

                // Play if not playing.
                if (Status != SoundStatus.Stopped)
                {
                    return;
                }
                AL.SourcePlay(_pointer);
                Status = SoundStatus.Playing;
                Helpers.CheckErrorAL($"playing source {_pointer}");

                Debugger.Log(MessageType.Info, MessageSource.SoundManager, $"Started playing [{file.Name}] on {ToString()}.");

                thisAction.Done();
            }

            if (FadeOutOnChange)
            {
                SetupForceFadeOut(QueuePlayInternal);
            }
            else
            {
                ALThread.ExecuteALThread(QueuePlayInternal);
            }

            return(thisAction);
        }
コード例 #10
0
ファイル: SoundLayer.cs プロジェクト: CharlieScarver/Emotion
        /// <summary>
        /// Destroy the layer freeing resources.
        /// </summary>
        public ContinuousAction Dispose()
        {
            ContinuousAction thisAction = new ContinuousAction();

            ALThread.ExecuteALThread(() =>
            {
                Debugger.Log(MessageType.Info, MessageSource.SoundManager, $"Destroyed {ToString()}.");

                StopPlayingAll(true);
                AL.DeleteSource(_pointer);
                Helpers.CheckErrorAL($"cleanup of source {_pointer}");

                _pointer = -1;
                _playList.Clear();

                thisAction.Done();
            });

            return(thisAction);
        }
コード例 #11
0
 /// <summary>
 /// Destroy the audio context.
 /// </summary>
 public void Dispose()
 {
     ALThread.ExecuteALThread(() => { _audioContext.Dispose(); });
 }
コード例 #12
0
        internal override void Create(byte[] data)
        {
            using (MemoryStream stream = new MemoryStream(data))
            {
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    // Read RIFF header.
                    string signature = new string(reader.ReadChars(4));
                    if (signature != "RIFF")
                    {
                        throw new Exception("Unsupported sound signature.");
                    }

                    // Chunk size.
                    reader.ReadInt32();

                    string format = new string(reader.ReadChars(4));
                    if (format != "WAVE")
                    {
                        throw new Exception("Unsupported sound format.");
                    }

                    // Read WAVE header.
                    string formatSignature = new string(reader.ReadChars(4));

                    // Skip junk.
                    while (formatSignature != "fmt ")
                    {
                        int junkSize = reader.ReadInt32();
                        reader.ReadBytes(junkSize);
                        formatSignature = new string(reader.ReadChars(4));
                    }

                    // Format chunk size.
                    int chunkSize = reader.ReadInt32();
                    // Audio format.
                    reader.ReadInt16();
                    int channels = reader.ReadInt16();
                    // Frequency.
                    int sampleRate = reader.ReadInt32();
                    // Byte rate.
                    reader.ReadInt32();
                    // Block align.
                    reader.ReadInt16();
                    int bitsPerSample = reader.ReadInt16();

                    // Finish the rest of the chunk.
                    reader.ReadBytes(chunkSize - 16);

                    // Read the signature.
                    formatSignature = new string(reader.ReadChars(4));

                    // Find the data chunk.
                    while (formatSignature != "data")
                    {
                        int junkSize = reader.ReadInt32();
                        reader.ReadBytes(junkSize);
                        formatSignature = new string(reader.ReadChars(4));
                    }

                    // Read the data chunk length.
                    int dataLength = reader.ReadInt32();

                    // Read the data.
                    byte[] soundData = reader.ReadBytes(dataLength);

                    // Create a sound buffer and load it.
                    ALThread.ExecuteALThread(() =>
                    {
                        Pointer = AL.GenBuffer();
                        AL.BufferData(Pointer, GetSoundFormat(channels, bitsPerSample), soundData, soundData.Length, sampleRate);
                    });

                    Duration = soundData.Length / (sampleRate * channels * bitsPerSample / 8f);
                }
            }
        }
コード例 #13
0
 internal override void Destroy()
 {
     ALThread.ExecuteALThread(() => { AL.DeleteBuffer(Pointer); });
 }