Improve CRingBuffer
This commit is contained in:
1 parent
6e4ccb39c0
commit
a46681c22b
4 files changed
+93
-105
No files matched your search
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in new issue
Block a user