mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 10:04:24 +00:00
270 lines
7.6 KiB
C#
270 lines
7.6 KiB
C#
using System;
|
|
using System.Threading;
|
|
|
|
namespace CUETools.Codecs
|
|
{
|
|
public class AudioPipe : IAudioSource//, IDisposable
|
|
{
|
|
private AudioBuffer _readBuffer, _writeBuffer;
|
|
private AudioPCMConfig pcm;
|
|
private long _sampleLen, _samplePos;
|
|
private int _maxLength;
|
|
private Thread _workThread;
|
|
private IAudioSource _source;
|
|
private bool _close = false;
|
|
private bool _haveData = false;
|
|
private int _bufferPos = 0;
|
|
private Exception _ex = null;
|
|
private bool own;
|
|
private ThreadPriority priority;
|
|
|
|
public IAudioDecoderSettings Settings => null;
|
|
|
|
public long Position
|
|
{
|
|
get
|
|
{
|
|
return _samplePos;
|
|
}
|
|
set
|
|
{
|
|
if (value == _samplePos)
|
|
return;
|
|
|
|
if (_source == null)
|
|
throw new NotSupportedException();
|
|
|
|
lock (this)
|
|
{
|
|
_close = true;
|
|
Monitor.Pulse(this);
|
|
}
|
|
if (_workThread != null)
|
|
{
|
|
_workThread.Join();
|
|
_workThread = null;
|
|
}
|
|
_source.Position = value;
|
|
_samplePos = value;
|
|
_bufferPos = 0;
|
|
_haveData = false;
|
|
_close = false;
|
|
//Go();
|
|
//throw new Exception("not supported");
|
|
}
|
|
}
|
|
|
|
public TimeSpan Duration => Length < 0 ? TimeSpan.Zero : TimeSpan.FromSeconds((double)Length / PCM.SampleRate);
|
|
|
|
public long Length
|
|
{
|
|
get
|
|
{
|
|
return _sampleLen;
|
|
}
|
|
}
|
|
|
|
public long Remaining
|
|
{
|
|
get
|
|
{
|
|
return _sampleLen - _samplePos;
|
|
}
|
|
}
|
|
|
|
public AudioPCMConfig PCM
|
|
{
|
|
get
|
|
{
|
|
return pcm;
|
|
}
|
|
}
|
|
|
|
public string Path
|
|
{
|
|
get
|
|
{
|
|
if (_source == null)
|
|
return "";
|
|
return _source.Path;
|
|
}
|
|
}
|
|
|
|
public AudioPipe(AudioPCMConfig pcm, int size)
|
|
{
|
|
this.pcm = pcm;
|
|
_readBuffer = new AudioBuffer(pcm, size);
|
|
_writeBuffer = new AudioBuffer(pcm, size);
|
|
_maxLength = size;
|
|
_sampleLen = -1;
|
|
_samplePos = 0;
|
|
}
|
|
|
|
public AudioPipe(IAudioSource source, int size, bool own, ThreadPriority priority)
|
|
: this(source.PCM, size)
|
|
{
|
|
this.own = own;
|
|
this.priority = priority;
|
|
_source = source;
|
|
_sampleLen = _source.Length;
|
|
_samplePos = _source.Position;
|
|
}
|
|
|
|
public AudioPipe(IAudioSource source, int size)
|
|
: this(source, size, true, ThreadPriority.BelowNormal)
|
|
{
|
|
}
|
|
|
|
private void Decompress(object o)
|
|
{
|
|
#if !DEBUG
|
|
try
|
|
#endif
|
|
{
|
|
bool done = false;
|
|
do
|
|
{
|
|
done = _source.Read(_writeBuffer, -1) == 0;
|
|
lock (this)
|
|
{
|
|
while (_haveData && !_close)
|
|
Monitor.Wait(this);
|
|
if (_close)
|
|
break;
|
|
AudioBuffer temp = _writeBuffer;
|
|
_writeBuffer = _readBuffer;
|
|
_readBuffer = temp;
|
|
_haveData = true;
|
|
Monitor.Pulse(this);
|
|
}
|
|
} while (!done);
|
|
}
|
|
#if !DEBUG
|
|
catch (Exception ex)
|
|
{
|
|
lock (this)
|
|
{
|
|
_ex = ex;
|
|
Monitor.Pulse(this);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private void Go()
|
|
{
|
|
if (_workThread != null || _ex != null || _source == null) return;
|
|
_workThread = new Thread(Decompress);
|
|
_workThread.Priority = priority;
|
|
_workThread.IsBackground = true;
|
|
_workThread.Name = "AudioPipe";
|
|
_workThread.Start(null);
|
|
}
|
|
|
|
//public new void Dispose()
|
|
//{
|
|
// _buffer.Clear();
|
|
//}
|
|
|
|
public void Close()
|
|
{
|
|
lock (this)
|
|
{
|
|
_close = true;
|
|
Monitor.Pulse(this);
|
|
}
|
|
if (_workThread != null)
|
|
{
|
|
_workThread.Join();
|
|
_workThread = null;
|
|
}
|
|
if (_source != null)
|
|
{
|
|
if (own) _source.Close();
|
|
_source = null;
|
|
}
|
|
if (_readBuffer != null)
|
|
{
|
|
//_readBuffer.Clear();
|
|
_readBuffer = null;
|
|
}
|
|
if (_writeBuffer != null)
|
|
{
|
|
//_writeBuffer.Clear();
|
|
_writeBuffer = null;
|
|
}
|
|
}
|
|
|
|
public int Write(AudioBuffer buff)
|
|
{
|
|
if (_writeBuffer.Size < _writeBuffer.Length + buff.Length)
|
|
{
|
|
AudioBuffer realloced = new AudioBuffer(pcm, _writeBuffer.Size + buff.Size);
|
|
realloced.Prepare(_writeBuffer, 0, _writeBuffer.Length);
|
|
_writeBuffer = realloced;
|
|
}
|
|
if (_writeBuffer.Length == 0)
|
|
_writeBuffer.Prepare(buff, 0, buff.Length);
|
|
else
|
|
{
|
|
_writeBuffer.Load(_writeBuffer.Length, buff, 0, buff.Length);
|
|
_writeBuffer.Length += buff.Length;
|
|
}
|
|
lock (this)
|
|
{
|
|
if (!_haveData)
|
|
{
|
|
AudioBuffer temp = _writeBuffer;
|
|
_writeBuffer = _readBuffer;
|
|
_writeBuffer.Length = 0;
|
|
_readBuffer = temp;
|
|
_haveData = true;
|
|
Monitor.Pulse(this);
|
|
}
|
|
}
|
|
return _writeBuffer.Length;
|
|
}
|
|
|
|
public int Read(AudioBuffer buff, int maxLength)
|
|
{
|
|
Go();
|
|
|
|
bool needToCopy = false;
|
|
if (_bufferPos != 0)
|
|
needToCopy = true;
|
|
else
|
|
lock (this)
|
|
{
|
|
while (!_haveData && _ex == null)
|
|
Monitor.Wait(this);
|
|
if (_ex != null)
|
|
throw _ex;
|
|
if (_bufferPos == 0 && (maxLength < 0 || _readBuffer.Length <= maxLength))
|
|
{
|
|
buff.Swap(_readBuffer);
|
|
_haveData = false;
|
|
Monitor.Pulse(this);
|
|
}
|
|
else
|
|
needToCopy = true;
|
|
}
|
|
if (needToCopy)
|
|
{
|
|
buff.Prepare(_readBuffer, _bufferPos, maxLength);
|
|
_bufferPos += buff.Length;
|
|
if (_bufferPos == _readBuffer.Length)
|
|
{
|
|
_bufferPos = 0;
|
|
lock (this)
|
|
{
|
|
_haveData = false;
|
|
Monitor.Pulse(this);
|
|
}
|
|
}
|
|
}
|
|
_samplePos += buff.Length;
|
|
return buff.Length;
|
|
}
|
|
}
|
|
}
|