From a46681c22b5debf55727f00b15d30536c80ef162 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Thu, 1 May 2014 00:15:21 +0200 Subject: [PATCH] Improve CRingBuffer --- Vocaluxe/Lib/Sound/Playback/IPlayback.cs | 78 ++++++++++----- .../Sound/Playback/OpenAL/COpenAlStream.cs | 4 +- .../Playback/PortAudio/CPortAudioStream.cs | 98 +++++++------------ Vocaluxe/Lib/Sound/Record/CDelayTest.cs | 18 +--- 4 files changed, 93 insertions(+), 105 deletions(-) diff --git a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs index 47fd10a9..23a5275e 100644 --- a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs +++ b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs @@ -15,6 +15,8 @@ // along with Vocaluxe. If not, see . #endregion +using System; + namespace Vocaluxe.Lib.Sound.Playback { public enum EStreamAction @@ -77,53 +79,75 @@ namespace Vocaluxe.Lib.Sound.Playback class CRingBuffer { private readonly byte[] _Data; - private readonly long _Size; - private long _ReadPos; - private long _WritePos; - private long _BytesNotRead; + private readonly int _Size; + private int _ReadPos; + private int _WritePos; + private int _BytesNotRead; - public long BytesNotRead + public int BytesNotRead { get { return _BytesNotRead; } } - public CRingBuffer(long size) + public CRingBuffer(int size) { _Size = size; _Data = new byte[size]; - _ReadPos = 0L; - _WritePos = 0L; - _BytesNotRead = 0L; + Reset(); + } + + public void Reset() + { + _ReadPos = 0; + _WritePos = 0; + _BytesNotRead = 0; } public void Write(byte[] data) { - long written = 0L; - while (written < data.Length) + int start = 0; + int end = data.Length; + if (end - start > _Size) + start = end - _Size; + int lenTotal = end - start; + int len = Math.Min(lenTotal, _Size - _WritePos); + Buffer.BlockCopy(data, start, _Data, _WritePos, len); + _WritePos += len; + if (_WritePos >= _Size) { - _Data[_WritePos] = data[written]; - _WritePos++; - if (_WritePos >= _Size) - _WritePos = 0L; - - written++; - _BytesNotRead++; + _WritePos = 0; + start += len; + len = end - start; + if (len > 0) + { + Buffer.BlockCopy(data, start, _Data, _WritePos, len); + _WritePos += len; + } } + _BytesNotRead += lenTotal; } public void Read(byte[] data) { - long read = 0L; - while (read < data.Length && _BytesNotRead > 0L) - { - data[read] = _Data[_ReadPos]; - _ReadPos++; - if (_ReadPos >= _Size) - _ReadPos = 0L; + int lenTotal = Math.Min(data.Length, _BytesNotRead); + if (lenTotal == 0) + return; - read++; - _BytesNotRead--; + int len = Math.Min(lenTotal, _Size - _ReadPos); + Buffer.BlockCopy(_Data, _ReadPos, data, 0, len); + _ReadPos += len; + if (_ReadPos >= _Size) + { + _ReadPos = 0; + int start = len; + len = lenTotal - len; + if (len > 0) + { + Buffer.BlockCopy(_Data, _ReadPos, data, start, len); + _ReadPos += len; + } } + _BytesNotRead -= lenTotal; } } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs index 3297e49e..ec5bdefa 100644 --- a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs +++ b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs @@ -30,7 +30,7 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL { private const int _BufferSize = 2048; private const int _BufferCount = 5; - private const long _Bufsize = 50000L; + private const int _Bufsize = 50000; private Object _CloseMutex; @@ -288,7 +288,7 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL lock (_MutexData) { - _Data = new CRingBuffer(_Bufsize); + _Data.Reset(); _NoMoreData = false; } } diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs index 0da436cc..1042e0f8 100644 --- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs +++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs @@ -27,8 +27,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { class CPortAudioStream : IDisposable { - private const long _Bufsize = 1000000L; - private const long _Beginrefill = 800000L; + private const int _Bufsize = 1000000; + private const int _Beginrefill = 800000; public readonly int ID; private readonly Closeproc _Closeproc; @@ -53,22 +53,21 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio private bool _FileOpened; - private bool _Waiting; private bool _Skip; private bool _Loop; private float _Duration; private float _CurrentTime; - private float _TimeCode; + private volatile float _TimeCode; - private bool _Paused; + private volatile bool _Paused; private CRingBuffer _Data; - private float _SetStart; + private volatile float _SetStart; private float _Start; - private bool _SetLoop; - private bool _SetSkip; - private bool _Terminated; + private volatile bool _SetLoop; + private volatile bool _SetSkip; + private volatile bool _Terminated; private Thread _DecoderThread; @@ -114,7 +113,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { lock (_LockData) { - return _NoMoreData && _Data.BytesNotRead == 0L && _SyncTimer.Time >= _Duration; + return _NoMoreData && _Data.BytesNotRead == 0 && _SyncTimer.Time >= _Duration; } } } @@ -124,11 +123,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio get { return _Volume * 100f; } set { - lock (_LockData) - { - value.Clamp(0f, 100f); - _Volume = value / 100f; - } + value.Clamp(0f, 100f); + _Volume = value / 100f; } } @@ -137,11 +133,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio get { return _VolumeMax * 100f; } set { - lock (_LockData) - { - value.Clamp(0f, 100f); - _VolumeMax = value / 100f; - } + value.Clamp(0f, 100f); + _VolumeMax = value / 100f; } } @@ -153,8 +146,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { if (Finished) _SyncTimer.Pause(); - //TODO: Why not use Decoder.GetPosition()? - //Decoder may return wrong timestamps. If you change this to exessive testing for monoton timestamps espacially for ogg files + //Decoder may return wrong timestamps. If you change this do exessive testing for monoton timestamps espacially for ogg files return _SyncTimer.Time; } } @@ -273,6 +265,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio _ByteCount = 2 * format.ChannelCount; _BytesPerSecond = format.SamplesPerSecond * _ByteCount; _CurrentTime = 0f; + _SyncTimer.Pause(); _SyncTimer.Time = _CurrentTime; PortAudioSharp.PortAudio.PaStreamParameters? outputParams = new PortAudioSharp.PortAudio.PaStreamParameters @@ -303,7 +296,6 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio //From now on closing the driver and the decoder is handled by the thread ONLY! _Paused = true; - _Waiting = true; _FileOpened = true; _Data = new CRingBuffer(_Bufsize); _NoMoreData = false; @@ -319,7 +311,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { _SetStart = time; _SetSkip = true; - _Waiting = true; + _EventDecode.Set(); } } @@ -331,10 +323,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio _Decoder.SetPosition(_Start); _CurrentTime = _Start; _TimeCode = _Start; - _Data = new CRingBuffer(_Bufsize); + _Data.Reset(); _NoMoreData = false; - _EventDecode.Set(); - _Waiting = false; _SyncTimer.Time = _Start; } } @@ -343,35 +333,27 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { while (!_Terminated) { - if (_EventDecode.WaitOne(10)) + lock (_LockSyncSignals) { - lock (_LockSyncSignals) + if (_SetSkip) { - if (_SetSkip) - { - _Skip = true; - _EventDecode.Set(); - _Waiting = true; - } - + _Skip = true; _SetSkip = false; - - _Start = _SetStart; - _Loop = _SetLoop; } - if (_Skip) - { - _DoSkip(); - _Skip = false; - } - - if (!_Waiting) - { - _DoDecode(); - _Update(); - } + _Start = _SetStart; + _Loop = _SetLoop; } + + if (_Skip) + { + _DoSkip(); + _Skip = false; + } + + _DoDecode(); + _Update(); + _EventDecode.WaitOne(); } _DoFree(); @@ -422,12 +404,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio _Data.Write(buffer); _TimeCode = timecode; if (_Data.BytesNotRead < _Beginrefill) - { - _Waiting = false; _EventDecode.Set(); - } - else - _Waiting = true; } } @@ -458,7 +435,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { try { - Marshal.Copy(buf, 0, output, (int)frameCount * _ByteCount); + Marshal.Copy(buf, 0, output, buf.Length); } catch (Exception e) { @@ -482,13 +459,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio } } - if (_Data.BytesNotRead < _Beginrefill) - { + if (_Data.BytesNotRead < _Beginrefill && !_NoMoreData) _EventDecode.Set(); - _Waiting = false; - } - else - _Waiting = true; float latency = buf.Length / _BytesPerSecond + CConfig.AudioLatency / 1000f; float time = _TimeCode - _Data.BytesNotRead / _BytesPerSecond - latency; @@ -503,7 +475,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio } catch (Exception e) { - CLog.LogError("Error PortAudio.treamCallback: " + e.Message); + CLog.LogError("Error PortAudio.StreamCallback: " + e.Message); } return PortAudioSharp.PortAudio.PaStreamCallbackResult.paContinue; diff --git a/Vocaluxe/Lib/Sound/Record/CDelayTest.cs b/Vocaluxe/Lib/Sound/Record/CDelayTest.cs index 27865727..456885d9 100644 --- a/Vocaluxe/Lib/Sound/Record/CDelayTest.cs +++ b/Vocaluxe/Lib/Sound/Record/CDelayTest.cs @@ -15,8 +15,6 @@ // along with Vocaluxe. If not, see . #endregion -using System; -using System.Diagnostics; using Vocaluxe.Base; namespace Vocaluxe.Lib.Sound.Record @@ -32,7 +30,6 @@ namespace Vocaluxe.Lib.Sound.Record private const float _MaxDelayTime = 1000; public bool Running { get; private set; } - private readonly Stopwatch _Timer = new Stopwatch(); private int _Stream = -1; private readonly SDelayChannel[] _DelaysChannel; @@ -72,7 +69,6 @@ namespace Vocaluxe.Lib.Sound.Record if (!Running) return; Running = false; - _Timer.Stop(); _CloseStream(); foreach (SDelayChannel delay in _DelaysChannel) { @@ -101,16 +97,13 @@ namespace Vocaluxe.Lib.Sound.Record { if (!Running) return; - if (!_Timer.IsRunning) - { - if (CSound.GetPosition(_Stream) > 0f) - _Timer.Restart(); - } - if (!_Timer.IsRunning) + + float time = CSound.GetPosition(_Stream) * 1000f; + if (time <= 0f) return; bool isActive = false; - if (_Timer.ElapsedMilliseconds <= _MaxDelayTime) + if (time <= _MaxDelayTime) { for (int i = 0; i < _DelaysChannel.Length; i++) { @@ -118,12 +111,11 @@ namespace Vocaluxe.Lib.Sound.Record continue; if (CRecord.GetTone(_DelaysChannel[i].Channel) == 9) { - Delays[i] = (int)_Timer.ElapsedMilliseconds; + Delays[i] = (int)time; _DelaysChannel[i].Finished = true; } else isActive = true; - Console.WriteLine(CRecord.GetMaxVolume(_DelaysChannel[i].Channel)); } } if (!isActive)