Improve CRingBuffer

This commit is contained in:
Flamefire committed 2014-05-01 00:15:21 +02:00
1 parent 6e4ccb39c0
commit a46681c22b
4 files changed
+93 -105

No files matched your search

+51 -27
View File
@@ -15,6 +15,8 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>. // along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion #endregion
using System;
namespace Vocaluxe.Lib.Sound.Playback namespace Vocaluxe.Lib.Sound.Playback
{ {
public enum EStreamAction public enum EStreamAction
@@ -77,53 +79,75 @@ namespace Vocaluxe.Lib.Sound.Playback
class CRingBuffer class CRingBuffer
{ {
private readonly byte[] _Data; private readonly byte[] _Data;
private readonly long _Size; private readonly int _Size;
private long _ReadPos; private int _ReadPos;
private long _WritePos; private int _WritePos;
private long _BytesNotRead; private int _BytesNotRead;
public long BytesNotRead public int BytesNotRead
{ {
get { return _BytesNotRead; } get { return _BytesNotRead; }
} }
public CRingBuffer(long size) public CRingBuffer(int size)
{ {
_Size = size; _Size = size;
_Data = new byte[size]; _Data = new byte[size];
_ReadPos = 0L; Reset();
_WritePos = 0L; }
_BytesNotRead = 0L;
public void Reset()
{
_ReadPos = 0;
_WritePos = 0;
_BytesNotRead = 0;
} }
public void Write(byte[] data) public void Write(byte[] data)
{ {
long written = 0L; int start = 0;
while (written < data.Length) 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 = 0;
_WritePos++; start += len;
if (_WritePos >= _Size) len = end - start;
_WritePos = 0L; if (len > 0)
{
written++; Buffer.BlockCopy(data, start, _Data, _WritePos, len);
_BytesNotRead++; _WritePos += len;
}
} }
_BytesNotRead += lenTotal;
} }
public void Read(byte[] data) public void Read(byte[] data)
{ {
long read = 0L; int lenTotal = Math.Min(data.Length, _BytesNotRead);
while (read < data.Length && _BytesNotRead > 0L) if (lenTotal == 0)
{ return;
data[read] = _Data[_ReadPos];
_ReadPos++;
if (_ReadPos >= _Size)
_ReadPos = 0L;
read++; int len = Math.Min(lenTotal, _Size - _ReadPos);
_BytesNotRead--; 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;
} }
} }
} }
@@ -30,7 +30,7 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL
{ {
private const int _BufferSize = 2048; private const int _BufferSize = 2048;
private const int _BufferCount = 5; private const int _BufferCount = 5;
private const long _Bufsize = 50000L; private const int _Bufsize = 50000;
private Object _CloseMutex; private Object _CloseMutex;
@@ -288,7 +288,7 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL
lock (_MutexData) lock (_MutexData)
{ {
_Data = new CRingBuffer(_Bufsize); _Data.Reset();
_NoMoreData = false; _NoMoreData = false;
} }
} }
@@ -27,8 +27,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{ {
class CPortAudioStream : IDisposable class CPortAudioStream : IDisposable
{ {
private const long _Bufsize = 1000000L; private const int _Bufsize = 1000000;
private const long _Beginrefill = 800000L; private const int _Beginrefill = 800000;
public readonly int ID; public readonly int ID;
private readonly Closeproc _Closeproc; private readonly Closeproc _Closeproc;
@@ -53,22 +53,21 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
private bool _FileOpened; private bool _FileOpened;
private bool _Waiting;
private bool _Skip; private bool _Skip;
private bool _Loop; private bool _Loop;
private float _Duration; private float _Duration;
private float _CurrentTime; private float _CurrentTime;
private float _TimeCode; private volatile float _TimeCode;
private bool _Paused; private volatile bool _Paused;
private CRingBuffer _Data; private CRingBuffer _Data;
private float _SetStart; private volatile float _SetStart;
private float _Start; private float _Start;
private bool _SetLoop; private volatile bool _SetLoop;
private bool _SetSkip; private volatile bool _SetSkip;
private bool _Terminated; private volatile bool _Terminated;
private Thread _DecoderThread; private Thread _DecoderThread;
@@ -114,7 +113,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{ {
lock (_LockData) 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; } get { return _Volume * 100f; }
set 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; } get { return _VolumeMax * 100f; }
set 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) if (Finished)
_SyncTimer.Pause(); _SyncTimer.Pause();
//TODO: Why not use Decoder.GetPosition()? //Decoder may return wrong timestamps. If you change this do exessive testing for monoton timestamps espacially for ogg files
//Decoder may return wrong timestamps. If you change this to exessive testing for monoton timestamps espacially for ogg files
return _SyncTimer.Time; return _SyncTimer.Time;
} }
} }
@@ -273,6 +265,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
_ByteCount = 2 * format.ChannelCount; _ByteCount = 2 * format.ChannelCount;
_BytesPerSecond = format.SamplesPerSecond * _ByteCount; _BytesPerSecond = format.SamplesPerSecond * _ByteCount;
_CurrentTime = 0f; _CurrentTime = 0f;
_SyncTimer.Pause();
_SyncTimer.Time = _CurrentTime; _SyncTimer.Time = _CurrentTime;
PortAudioSharp.PortAudio.PaStreamParameters? outputParams = new PortAudioSharp.PortAudio.PaStreamParameters 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! //From now on closing the driver and the decoder is handled by the thread ONLY!
_Paused = true; _Paused = true;
_Waiting = true;
_FileOpened = true; _FileOpened = true;
_Data = new CRingBuffer(_Bufsize); _Data = new CRingBuffer(_Bufsize);
_NoMoreData = false; _NoMoreData = false;
@@ -319,7 +311,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{ {
_SetStart = time; _SetStart = time;
_SetSkip = true; _SetSkip = true;
_Waiting = true; _EventDecode.Set();
} }
} }
@@ -331,10 +323,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
_Decoder.SetPosition(_Start); _Decoder.SetPosition(_Start);
_CurrentTime = _Start; _CurrentTime = _Start;
_TimeCode = _Start; _TimeCode = _Start;
_Data = new CRingBuffer(_Bufsize); _Data.Reset();
_NoMoreData = false; _NoMoreData = false;
_EventDecode.Set();
_Waiting = false;
_SyncTimer.Time = _Start; _SyncTimer.Time = _Start;
} }
} }
@@ -343,35 +333,27 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{ {
while (!_Terminated) while (!_Terminated)
{ {
if (_EventDecode.WaitOne(10)) lock (_LockSyncSignals)
{ {
lock (_LockSyncSignals) if (_SetSkip)
{ {
if (_SetSkip) _Skip = true;
{
_Skip = true;
_EventDecode.Set();
_Waiting = true;
}
_SetSkip = false; _SetSkip = false;
_Start = _SetStart;
_Loop = _SetLoop;
} }
if (_Skip) _Start = _SetStart;
{ _Loop = _SetLoop;
_DoSkip();
_Skip = false;
}
if (!_Waiting)
{
_DoDecode();
_Update();
}
} }
if (_Skip)
{
_DoSkip();
_Skip = false;
}
_DoDecode();
_Update();
_EventDecode.WaitOne();
} }
_DoFree(); _DoFree();
@@ -422,12 +404,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
_Data.Write(buffer); _Data.Write(buffer);
_TimeCode = timecode; _TimeCode = timecode;
if (_Data.BytesNotRead < _Beginrefill) if (_Data.BytesNotRead < _Beginrefill)
{
_Waiting = false;
_EventDecode.Set(); _EventDecode.Set();
}
else
_Waiting = true;
} }
} }
@@ -458,7 +435,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{ {
try try
{ {
Marshal.Copy(buf, 0, output, (int)frameCount * _ByteCount); Marshal.Copy(buf, 0, output, buf.Length);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -482,13 +459,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
} }
} }
if (_Data.BytesNotRead < _Beginrefill) if (_Data.BytesNotRead < _Beginrefill && !_NoMoreData)
{
_EventDecode.Set(); _EventDecode.Set();
_Waiting = false;
}
else
_Waiting = true;
float latency = buf.Length / _BytesPerSecond + CConfig.AudioLatency / 1000f; float latency = buf.Length / _BytesPerSecond + CConfig.AudioLatency / 1000f;
float time = _TimeCode - _Data.BytesNotRead / _BytesPerSecond - latency; float time = _TimeCode - _Data.BytesNotRead / _BytesPerSecond - latency;
@@ -503,7 +475,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
} }
catch (Exception e) catch (Exception e)
{ {
CLog.LogError("Error PortAudio.treamCallback: " + e.Message); CLog.LogError("Error PortAudio.StreamCallback: " + e.Message);
} }
return PortAudioSharp.PortAudio.PaStreamCallbackResult.paContinue; return PortAudioSharp.PortAudio.PaStreamCallbackResult.paContinue;
+5 -13
View File
@@ -15,8 +15,6 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>. // along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion #endregion
using System;
using System.Diagnostics;
using Vocaluxe.Base; using Vocaluxe.Base;
namespace Vocaluxe.Lib.Sound.Record namespace Vocaluxe.Lib.Sound.Record
@@ -32,7 +30,6 @@ namespace Vocaluxe.Lib.Sound.Record
private const float _MaxDelayTime = 1000; private const float _MaxDelayTime = 1000;
public bool Running { get; private set; } public bool Running { get; private set; }
private readonly Stopwatch _Timer = new Stopwatch();
private int _Stream = -1; private int _Stream = -1;
private readonly SDelayChannel[] _DelaysChannel; private readonly SDelayChannel[] _DelaysChannel;
@@ -72,7 +69,6 @@ namespace Vocaluxe.Lib.Sound.Record
if (!Running) if (!Running)
return; return;
Running = false; Running = false;
_Timer.Stop();
_CloseStream(); _CloseStream();
foreach (SDelayChannel delay in _DelaysChannel) foreach (SDelayChannel delay in _DelaysChannel)
{ {
@@ -101,16 +97,13 @@ namespace Vocaluxe.Lib.Sound.Record
{ {
if (!Running) if (!Running)
return; return;
if (!_Timer.IsRunning)
{ float time = CSound.GetPosition(_Stream) * 1000f;
if (CSound.GetPosition(_Stream) > 0f) if (time <= 0f)
_Timer.Restart();
}
if (!_Timer.IsRunning)
return; return;
bool isActive = false; bool isActive = false;
if (_Timer.ElapsedMilliseconds <= _MaxDelayTime) if (time <= _MaxDelayTime)
{ {
for (int i = 0; i < _DelaysChannel.Length; i++) for (int i = 0; i < _DelaysChannel.Length; i++)
{ {
@@ -118,12 +111,11 @@ namespace Vocaluxe.Lib.Sound.Record
continue; continue;
if (CRecord.GetTone(_DelaysChannel[i].Channel) == 9) if (CRecord.GetTone(_DelaysChannel[i].Channel) == 9)
{ {
Delays[i] = (int)_Timer.ElapsedMilliseconds; Delays[i] = (int)time;
_DelaysChannel[i].Finished = true; _DelaysChannel[i].Finished = true;
} }
else else
isActive = true; isActive = true;
Console.WriteLine(CRecord.GetMaxVolume(_DelaysChannel[i].Channel));
} }
} }
if (!isActive) if (!isActive)