diff --git a/Vocaluxe/Lib/Sound/CPortAudioCommon.cs b/Vocaluxe/Lib/Sound/CPortAudioCommon.cs
new file mode 100644
index 00000000..d3584860
--- /dev/null
+++ b/Vocaluxe/Lib/Sound/CPortAudioCommon.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Diagnostics;
+using PortAudioSharp;
+using Vocaluxe.Base;
+
+namespace Vocaluxe.Lib.Sound
+{
+ ///
+ /// PortAudio can be used for record and playback
+ /// So do some common stuff here and make sure those 2 do not interfere
+ ///
+ /// DO NEVER use following Pa_* functions other than the ones from this class:
+ /// Initialize, Terminate, OpenStream, CloseStream
+ ///
+ abstract class CPortAudioCommon
+ {
+ private static int _RefCount;
+ private static readonly object _Mutex = new object();
+
+ ///
+ /// Safe method to init PortAudio (adds a reference)
+ /// MUST call CloseDriver when done
+ ///
+ /// True on success, falso if not initialized (log written)
+ protected static bool _InitDriver()
+ {
+ lock (_Mutex)
+ {
+ if (_RefCount == 0)
+ {
+ if (_CheckError("Initialize", PortAudio.Pa_Initialize()))
+ return false;
+ }
+ _RefCount++;
+ }
+ return true;
+ }
+
+ ///
+ /// Safe method to close PortAudio
+ /// MUST be called _exactly_ once after successfull InitDriver call
+ ///
+ protected static void _CloseDriver()
+ {
+ lock (_Mutex)
+ {
+ Debug.Assert(_RefCount > 0);
+ _RefCount--;
+ if (_RefCount == 0)
+ PortAudio.Pa_Terminate();
+ }
+ }
+
+ protected static PortAudio.PaError _OpenStream(out IntPtr stream, ref PortAudio.PaStreamParameters? inputParameters, ref PortAudio.PaStreamParameters? outputParameters,
+ double sampleRate, uint framesPerBuffer, PortAudio.PaStreamFlags streamFlags,
+ PortAudio.PaStreamCallbackDelegate streamCallback, IntPtr userData)
+ {
+ lock (_Mutex)
+ {
+ return PortAudio.Pa_OpenStream(out stream, ref inputParameters, ref outputParameters, sampleRate, framesPerBuffer, streamFlags, streamCallback, userData);
+ }
+ }
+
+ ///
+ /// Convenience method to safely open an input stream and log potential error
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// True on success
+ protected static bool _OpenInputStream(out IntPtr stream, ref PortAudio.PaStreamParameters? inputParameters,
+ double sampleRate, uint framesPerBuffer, PortAudio.PaStreamFlags streamFlags,
+ PortAudio.PaStreamCallbackDelegate streamCallback, IntPtr userData)
+ {
+ PortAudio.PaStreamParameters? outputParameters = null;
+ return
+ !_CheckError("OpenInputStream",
+ _OpenStream(out stream, ref inputParameters, ref outputParameters, sampleRate, framesPerBuffer, streamFlags, streamCallback, userData));
+ }
+
+ ///
+ /// Convenience method to safely open an output stream and log potential error
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// True on success
+ protected static bool _OpenOutputStream(out IntPtr stream, ref PortAudio.PaStreamParameters? outputParameters,
+ double sampleRate, uint framesPerBuffer, PortAudio.PaStreamFlags streamFlags,
+ PortAudio.PaStreamCallbackDelegate streamCallback, IntPtr userData)
+ {
+ PortAudio.PaStreamParameters? inputParameters = null;
+ return
+ !_CheckError("OpenOutputStream",
+ _OpenStream(out stream, ref inputParameters, ref outputParameters, sampleRate, framesPerBuffer, streamFlags, streamCallback, userData));
+ }
+
+ protected static void _CloseStream(IntPtr stream)
+ {
+ lock (_Mutex)
+ {
+ PortAudio.Pa_CloseStream(stream);
+ }
+ }
+
+ ///
+ /// Checks if PA returned an error and logs it
+ /// Returns true on error
+ ///
+ /// Action identifier (E.g. openStream)
+ /// Result returned by Pa_* call
+ /// True on error
+ protected static bool _CheckError(String action, PortAudio.PaError errorCode)
+ {
+ if (errorCode != PortAudio.PaError.paNoError)
+ {
+ CLog.LogError(action + " error: " + PortAudio.Pa_GetErrorText(errorCode));
+ if (errorCode == PortAudio.PaError.paUnanticipatedHostError)
+ {
+ PortAudio.PaHostErrorInfo errorInfo = PortAudio.Pa_GetLastHostErrorInfo();
+ CLog.LogError("- Host error API type: " + errorInfo.hostApiType);
+ CLog.LogError("- Host error code: " + errorInfo.errorCode);
+ CLog.LogError("- Host error text: " + errorInfo.errorText);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Selects the most appropriate host api
+ ///
+ /// The most appropriate host api
+ protected static int _GetHostApi()
+ {
+ //Caller has to hold a reference anyway so no locking needed
+ if (_RefCount < 1)
+ return -1;
+
+ int selectedHostApi = PortAudio.Pa_GetDefaultHostApi();
+ int apiCount = PortAudio.Pa_GetHostApiCount();
+ for (int i = 0; i < apiCount; i++)
+ {
+ PortAudio.PaHostApiInfo apiInfo = PortAudio.Pa_GetHostApiInfo(i);
+ if ((apiInfo.type == PortAudio.PaHostApiTypeId.paDirectSound)
+ || (apiInfo.type == PortAudio.PaHostApiTypeId.paALSA))
+ selectedHostApi = i;
+ }
+ return selectedHostApi;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs
index c69eed4e..13ce9857 100644
--- a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs
+++ b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs
@@ -35,7 +35,7 @@ namespace Vocaluxe.Lib.Sound.Playback
}
}
- delegate void Closeproc(int streamID);
+ delegate void Closeproc(int stream);
interface IPlayback
{
diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs
index 38742b9f..86f62f4d 100644
--- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs
+++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs
@@ -15,42 +15,35 @@
// along with Vocaluxe. If not, see .
#endregion
-using System;
using System.Collections.Generic;
-using System.Linq;
namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{
class CPortAudioPlay : IPlayback
{
private bool _Initialized;
- private readonly List _Decoder = new List();
- private Closeproc _Closeproc;
- private int _Count = 1;
-
- private readonly Object _MutexDecoder = new Object();
-
- private List _Streams;
+ private readonly List _Streams = new List();
+ private int _NextID;
public bool Init()
{
if (_Initialized)
CloseAll();
- _Closeproc = _CloseProc;
_Initialized = true;
- _Streams = new List();
return true;
}
public void CloseAll()
{
- lock (_MutexDecoder)
+ lock (_Streams)
{
- for (int i = 0; i < _Decoder.Count; i++)
- _Decoder[i].Free(_Closeproc, i + 1);
+ foreach (CPortAudioStream stream in _Streams)
+ stream.Free();
+ _Streams.Clear();
}
+ _Initialized = false;
}
public void SetGlobalVolume(float volume)
@@ -66,7 +59,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
if (!_Initialized)
return 0;
- lock (_MutexDecoder)
+ lock (_Streams)
{
return _Streams.Count;
}
@@ -82,17 +75,16 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
public int Load(string media, bool prescan)
{
- var stream = new SAudioStreams(0);
- var decoder = new CPortAudioStream();
+ //Note: We ignore prescan here as the stream does it always
- if (decoder.Open(media) > -1)
+ var stream = new CPortAudioStream(_NextID++, _CloseProc);
+
+ if (stream.Open(media))
{
- lock (_MutexDecoder)
+ lock (_Streams)
{
- _Decoder.Add(decoder);
- stream.Handle = _Count++;
_Streams.Add(stream);
- return stream.Handle;
+ return stream.ID;
}
}
return 0;
@@ -100,12 +92,15 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
public void Close(int stream)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
+ int index = _GetStreamIndex(stream);
+ if (index >= 0)
{
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].Free(_Closeproc, stream);
+ _Streams[index].Free();
+ _Streams.RemoveAt(index);
}
}
}
@@ -117,216 +112,219 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
public void Play(int stream, bool loop)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
+ int index = _GetStreamIndex(stream);
+ if (index >= 0)
{
- if (_AlreadyAdded(stream))
- {
- _Decoder[_GetStreamIndex(stream)].Loop = loop;
- _Decoder[_GetStreamIndex(stream)].Play();
- }
+ _Streams[index].Loop = loop;
+ _Streams[index].Play();
}
}
}
public void Pause(int stream)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].Paused = true;
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].Paused = true;
}
}
public void Stop(int stream)
{
- Pause(stream);
+ if (!_Initialized)
+ return;
+ lock (_Streams)
+ {
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].Stop();
+ }
}
public void Fade(int stream, float targetVolume, float seconds)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].Fade(targetVolume, seconds);
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].Fade(targetVolume, seconds);
}
}
public void FadeAndPause(int stream, float targetVolume, float seconds)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].FadeAndPause(targetVolume, seconds);
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].FadeAndPause(targetVolume, seconds);
}
}
public void FadeAndClose(int stream, float targetVolume, float seconds)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].FadeAndClose(targetVolume, seconds, _Closeproc, stream);
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].FadeAndClose(targetVolume, seconds);
}
}
public void FadeAndStop(int stream, float targetVolume, float seconds)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].FadeAndStop(targetVolume, seconds, _Closeproc, stream);
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].FadeAndStop(targetVolume, seconds);
}
}
public void SetStreamVolume(int stream, float volume)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].Volume = volume;
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].Volume = volume;
}
}
public void SetStreamVolumeMax(int stream, float volume)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].VolumeMax = volume;
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].VolumeMax = volume;
}
}
public float GetLength(int stream)
{
- if (_Initialized)
+ if (!_Initialized)
+ return 0f;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- return _Decoder[_GetStreamIndex(stream)].Length;
- }
+ if (_AlreadyAdded(stream))
+ return _Streams[_GetStreamIndex(stream)].Length;
}
return 0f;
}
public float GetPosition(int stream)
{
- if (_Initialized)
- {
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- return _Decoder[_GetStreamIndex(stream)].Position;
- }
-
+ if (!_Initialized)
return 0f;
+ lock (_Streams)
+ {
+ if (_AlreadyAdded(stream))
+ return _Streams[_GetStreamIndex(stream)].Position;
}
+
return 0f;
}
public bool IsPlaying(int stream)
{
- if (_Initialized)
+ if (!_Initialized)
+ return false;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- return !_Decoder[_GetStreamIndex(stream)].Paused && !_Decoder[_GetStreamIndex(stream)].Finished;
- }
+ if (_AlreadyAdded(stream))
+ return !_Streams[_GetStreamIndex(stream)].Paused && !_Streams[_GetStreamIndex(stream)].Finished;
}
return false;
}
public bool IsPaused(int stream)
{
- if (_Initialized)
+ if (!_Initialized)
+ return false;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- return _Decoder[_GetStreamIndex(stream)].Paused;
- }
+ if (_AlreadyAdded(stream))
+ return _Streams[_GetStreamIndex(stream)].Paused;
}
return false;
}
public bool IsFinished(int stream)
{
- if (_Initialized)
+ if (!_Initialized)
+ return true;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- return _Decoder[_GetStreamIndex(stream)].Finished;
- }
+ if (_AlreadyAdded(stream))
+ return _Streams[_GetStreamIndex(stream)].Finished;
}
return true;
}
public void SetPosition(int stream, float position)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(stream))
- _Decoder[_GetStreamIndex(stream)].Skip(position);
- }
+ if (_AlreadyAdded(stream))
+ _Streams[_GetStreamIndex(stream)].Skip(position);
}
}
#endregion Stream Handling
+ ///
+ /// Returns true if strem with given id is found
+ /// MUST hold _Stream-lock
+ ///
+ /// Stream id
+ ///
private bool _AlreadyAdded(int stream)
{
- return _Streams.Any(st => st.Handle == stream);
+ return _GetStreamIndex(stream) >= 0;
}
+ ///
+ /// Returns the index of the stream with the given id
+ /// MUST hold _Stream-lock
+ ///
+ /// Stream id
+ ///
private int _GetStreamIndex(int stream)
{
for (int i = 0; i < _Streams.Count; i++)
{
- if (_Streams[i].Handle == stream)
+ if (_Streams[i].ID == stream)
return i;
}
return -1;
}
- private void _CloseProc(int streamID)
+ ///
+ /// Removes the stream with the given handle
+ ///
+ /// Stream handle
+ private void _CloseProc(int stream)
{
- if (_Initialized)
+ if (!_Initialized)
+ return;
+ lock (_Streams)
{
- lock (_MutexDecoder)
- {
- if (_AlreadyAdded(streamID))
- {
- int index = _GetStreamIndex(streamID);
- _Decoder.RemoveAt(index);
- _Streams.RemoveAt(index);
- }
- }
+ if (_AlreadyAdded(stream))
+ _Streams.RemoveAt(_GetStreamIndex(stream));
}
}
}
diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs
index d4cb57c5..109dbd88 100644
--- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs
+++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs
@@ -8,15 +8,15 @@ using VocaluxeLib;
namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{
- class CPortAudioStream : IDisposable
+ class CPortAudioStream : CPortAudioCommon, IDisposable
{
private const long _Bufsize = 1000000L;
private const long _Beginrefill = 800000L;
+ public readonly int ID;
+ private readonly Closeproc _Closeproc;
+
private readonly CSyncTimer _SyncTimer;
- private static bool _Initialized;
- private static int _NumStreams;
- private static readonly Object _Mutex = new object();
private int _ByteCount = 4;
private float _Volume = 1f;
private float _VolumeMax = 1f;
@@ -26,11 +26,9 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
private static PortAudioSharp.PortAudio.PaHostApiInfo _ApiInfo;
private static PortAudioSharp.PortAudio.PaDeviceInfo _OutputDeviceInfo;
- private IntPtr _Ptr = new IntPtr(0);
+ private IntPtr _Stream = IntPtr.Zero;
- private Closeproc _Closeproc;
private PortAudioSharp.PortAudio.PaStreamCallbackDelegate _PaStreamCallback;
- private int _StreamID;
private IAudioDecoder _Decoder;
private float _BytesPerSecond;
private bool _NoMoreData;
@@ -61,8 +59,10 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
private readonly Object _LockData = new Object();
private readonly Object _LockSyncSignals = new Object();
- public CPortAudioStream()
+ public CPortAudioStream(int id, Closeproc closeproc)
{
+ ID = id;
+ _Closeproc = closeproc;
_SyncTimer = new CSyncTimer(0f, 1f, 0.02f);
}
@@ -71,10 +71,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
Dispose();
}
- public void Free(Closeproc closeProc, int streamID)
+ public void Free()
{
- _Closeproc = closeProc;
- _StreamID = streamID;
_Terminated = true;
}
@@ -135,6 +133,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
return _SyncTimer.Time;
}
}
@@ -172,18 +171,14 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
_AfterFadeAction = EStreamAction.Pause;
}
- public void FadeAndClose(float targetVolume, float fadeTime, Closeproc closeProc, int streamID)
+ public void FadeAndClose(float targetVolume, float fadeTime)
{
- _Closeproc = closeProc;
- _StreamID = streamID;
Fade(targetVolume, fadeTime);
_AfterFadeAction = EStreamAction.Close;
}
- public void FadeAndStop(float targetVolume, float fadeTime, Closeproc closeProc, int streamID)
+ public void FadeAndStop(float targetVolume, float fadeTime)
{
- _Closeproc = closeProc;
- _StreamID = streamID;
Fade(targetVolume, fadeTime);
_AfterFadeAction = EStreamAction.Stop;
}
@@ -192,18 +187,12 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
{
Paused = false;
_AfterFadeAction = EStreamAction.Nothing;
- lock (_Mutex)
- {
- _ErrorCheck("StartStream", PortAudioSharp.PortAudio.Pa_StartStream(_Ptr));
- }
+ _CheckError("StartStream", PortAudioSharp.PortAudio.Pa_StartStream(_Stream));
}
public void Stop()
{
- lock (_Mutex)
- {
- _ErrorCheck("StopStream (playback)", PortAudioSharp.PortAudio.Pa_StopStream(_Ptr));
- }
+ _CheckError("StopStream (playback)", PortAudioSharp.PortAudio.Pa_StopStream(_Stream));
Skip(0f);
}
@@ -213,60 +202,57 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
set { _SetLoop = value; }
}
- public int Open(string fileName)
+ public bool Open(string fileName)
{
if (_FileOpened)
- return -1;
+ return false;
if (!File.Exists(fileName))
- return -1;
-
- _Decoder = new CAudioDecoderFFmpeg();
- _Decoder.Init();
+ return false;
+ bool driverInitialized = false;
try
{
- lock (_Mutex)
- {
- if (!_Initialized)
- {
- if (_ErrorCheck("Initialize", PortAudioSharp.PortAudio.Pa_Initialize()))
- return -1;
- _Initialized = true;
+ if (!_InitDriver())
+ return false;
+ driverInitialized = true;
- int hostApi = _ApiSelect();
- _ApiInfo = PortAudioSharp.PortAudio.Pa_GetHostApiInfo(hostApi);
- _OutputDeviceInfo = PortAudioSharp.PortAudio.Pa_GetDeviceInfo(_ApiInfo.defaultOutputDevice);
- if (_OutputDeviceInfo.defaultLowOutputLatency < 0.1)
- _OutputDeviceInfo.defaultLowOutputLatency = 0.1;
- }
- }
+ int hostApi = _GetHostApi();
+ _ApiInfo = PortAudioSharp.PortAudio.Pa_GetHostApiInfo(hostApi);
+ _OutputDeviceInfo = PortAudioSharp.PortAudio.Pa_GetDeviceInfo(_ApiInfo.defaultOutputDevice);
+ if (_OutputDeviceInfo.defaultLowOutputLatency < 0.1)
+ _OutputDeviceInfo.defaultLowOutputLatency = 0.1;
_PaStreamCallback = _ProcessNewData;
}
catch (Exception)
{
- _Initialized = false;
+ if (driverInitialized)
+ _CloseDriver();
CLog.LogError("Error Init PortAudio Playback");
- return -1;
+ return false;
}
+ _Decoder = new CAudioDecoderFFmpeg();
+ _Decoder.Init();
_Decoder.Open(fileName);
- _Duration = _Decoder.GetLength();
SFormatInfo format = _Decoder.GetFormatInfo();
if (format.SamplesPerSecond == 0)
- return -1;
+ {
+ _CloseDriver();
+ _Decoder.Close();
+ _Decoder = null;
+ CLog.LogError("Error Init PortAudio Playback (samples=0)");
+ return false;
+ }
+ _Duration = _Decoder.GetLength();
_ByteCount = 2 * format.ChannelCount;
_BytesPerSecond = format.SamplesPerSecond * _ByteCount;
_CurrentTime = 0f;
_SyncTimer.Time = _CurrentTime;
- var stream = new SAudioStreams(0);
-
- var data = new IntPtr(0);
-
PortAudioSharp.PortAudio.PaStreamParameters? outputParams = new PortAudioSharp.PortAudio.PaStreamParameters
{
channelCount = format.ChannelCount,
@@ -274,38 +260,33 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
sampleFormat = PortAudioSharp.PortAudio.PaSampleFormat.paInt16,
suggestedLatency = _OutputDeviceInfo.defaultLowOutputLatency
};
- PortAudioSharp.PortAudio.PaStreamParameters? inputParams = null;
- var bufsize = (uint)CConfig.AudioBufferSize;
- lock (_Mutex)
+ if (!_OpenOutputStream(
+ out _Stream,
+ ref outputParams,
+ format.SamplesPerSecond,
+ (uint)CConfig.AudioBufferSize,
+ PortAudioSharp.PortAudio.PaStreamFlags.paNoFlag,
+ _PaStreamCallback,
+ IntPtr.Zero) || _Stream == IntPtr.Zero)
{
- _ErrorCheck("OpenDefaultStream (playback)", PortAudioSharp.PortAudio.Pa_OpenStream(
- out _Ptr,
- ref inputParams,
- ref outputParams,
- format.SamplesPerSecond,
- bufsize,
- PortAudioSharp.PortAudio.PaStreamFlags.paNoFlag,
- _PaStreamCallback,
- data));
+ _CloseDriver();
+ _Decoder.Close();
+ _Decoder = null;
+ return false;
}
- stream.Handle = _Ptr.ToInt32();
+ //From now on closing the driver and the decoder is handled by the thread ONLY!
- if (stream.Handle != 0)
- {
- _NumStreams++;
- _Paused = true;
- _Waiting = true;
- _FileOpened = true;
- _Data = new CRingBuffer(_Bufsize);
- _NoMoreData = false;
- _DecoderThread = new Thread(_Execute) {Priority = ThreadPriority.Normal, Name = Path.GetFileName(fileName)};
- _DecoderThread.Start();
+ _Paused = true;
+ _Waiting = true;
+ _FileOpened = true;
+ _Data = new CRingBuffer(_Bufsize);
+ _NoMoreData = false;
+ _DecoderThread = new Thread(_Execute) {Priority = ThreadPriority.Normal, Name = Path.GetFileName(fileName)};
+ _DecoderThread.Start();
- return stream.Handle;
- }
- return -1;
+ return true;
}
public void Skip(float time)
@@ -374,9 +355,6 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
private void _DoDecode()
{
- if (!_FileOpened)
- return;
-
if (_Paused)
return;
@@ -431,22 +409,11 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
private void _DoFree()
{
- if (_Initialized)
- {
- Stop();
- _NumStreams--;
- if (_NumStreams == 0)
- {
- lock (_Mutex)
- {
- PortAudioSharp.PortAudio.Pa_Terminate();
- _Initialized = false;
- }
- }
- _Decoder.Close();
- }
+ _CloseStream(_Stream);
+ _CloseDriver();
+ _Decoder.Close();
- _Closeproc(_StreamID);
+ _Closeproc(ID);
}
#endregion Threading
@@ -517,44 +484,6 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio
}
#endregion Callbacks
- private bool _ErrorCheck(String action, PortAudioSharp.PortAudio.PaError errorCode)
- {
- if (errorCode != PortAudioSharp.PortAudio.PaError.paNoError)
- {
- if (errorCode == PortAudioSharp.PortAudio.PaError.paStreamIsNotStopped)
- return false;
-
- CLog.LogError(action + " error (playback): " + PortAudioSharp.PortAudio.Pa_GetErrorText(errorCode));
- if (errorCode == PortAudioSharp.PortAudio.PaError.paUnanticipatedHostError)
- {
- PortAudioSharp.PortAudio.PaHostErrorInfo errorInfo = PortAudioSharp.PortAudio.Pa_GetLastHostErrorInfo();
- CLog.LogError("- Host error API type: " + errorInfo.hostApiType);
- CLog.LogError("- Host error code: " + errorInfo.errorCode);
- CLog.LogError("- Host error text: " + errorInfo.errorText);
- }
- return true;
- }
-
- return false;
- }
-
- private int _ApiSelect()
- {
- if (!_Initialized)
- return 0;
-
- int selectedHostApi = PortAudioSharp.PortAudio.Pa_GetDefaultHostApi();
- int apiCount = PortAudioSharp.PortAudio.Pa_GetHostApiCount();
- for (int i = 0; i < apiCount; i++)
- {
- PortAudioSharp.PortAudio.PaHostApiInfo apiInfo = PortAudioSharp.PortAudio.Pa_GetHostApiInfo(i);
- if ((apiInfo.type == PortAudioSharp.PortAudio.PaHostApiTypeId.paDirectSound)
- || (apiInfo.type == PortAudioSharp.PortAudio.PaHostApiTypeId.paALSA))
- selectedHostApi = i;
- }
- return selectedHostApi;
- }
-
private void _Update()
{
if (_Fading != null)
diff --git a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs
index 86b5f3ee..a059d463 100644
--- a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs
+++ b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs
@@ -24,7 +24,7 @@ using Vocaluxe.Base;
namespace Vocaluxe.Lib.Sound.Record.PortAudio
{
- class CPortAudioRecord : IRecord
+ class CPortAudioRecord : CPortAudioCommon, IRecord
{
private bool _Initialized;
private readonly List _Devices = new List();
@@ -47,16 +47,16 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio
/// true if success
public bool Init()
{
+ if (_Initialized)
+ return false;
+
try
{
- if (_Initialized)
- Close();
-
- if (_ErrorCheck("Initialize", PortAudioSharp.PortAudio.Pa_Initialize()))
+ if (!_InitDriver())
return false;
_Devices.Clear();
- int hostAPI = _ApiSelect();
+ int hostAPI = _GetHostApi();
int numDevices = PortAudioSharp.PortAudio.Pa_GetDeviceCount();
for (int i = 0; i < numDevices; i++)
{
@@ -100,9 +100,6 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio
Stop();
- foreach (CBuffer buffer in _Buffer)
- buffer.Reset();
-
foreach (IntPtr handle in _RecHandle)
{
int waitcount = 0;
@@ -113,6 +110,9 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio
}
}
+ foreach (CBuffer buffer in _Buffer)
+ buffer.Reset();
+
for (int i = 0; i < _RecHandle.Length; i++)
_RecHandle[i] = IntPtr.Zero;
@@ -127,19 +127,17 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio
sampleFormat = PortAudioSharp.PortAudio.PaSampleFormat.paInt16,
suggestedLatency = PortAudioSharp.PortAudio.Pa_GetDeviceInfo(_Devices[dev].ID).defaultLowInputLatency
};
- PortAudioSharp.PortAudio.PaStreamParameters? outputParams = null;
- if (_ErrorCheck("OpenStream (rec)", PortAudioSharp.PortAudio.Pa_OpenStream(
+ if (!_OpenInputStream(
out _RecHandle[dev],
ref inputParams,
- ref outputParams,
44100,
882,
PortAudioSharp.PortAudio.PaStreamFlags.paNoFlag,
_MyRecProc,
- new IntPtr(dev))))
+ new IntPtr(dev)))
return false;
- if (_ErrorCheck("Start Stream (rec)", PortAudioSharp.PortAudio.Pa_StartStream(_RecHandle[dev])))
+ if (_CheckError("Start Stream (rec)", PortAudioSharp.PortAudio.Pa_StartStream(_RecHandle[dev])))
return false;
}
}
@@ -165,13 +163,14 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio
///
public void Close()
{
- Stop();
+ if (!_Initialized)
+ return;
- if (_Initialized)
- {
- PortAudioSharp.PortAudio.Pa_Terminate();
- _Initialized = false;
- }
+ foreach (IntPtr handle in _RecHandle)
+ _CloseStream(handle);
+ _CloseDriver();
+
+ _Initialized = false;
//System.IO.File.WriteAllBytes("test0.raw", _Buffer[0].Buffer);
}
@@ -312,40 +311,5 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio
return PortAudioSharp.PortAudio.PaStreamCallbackResult.paContinue;
}
-
- private bool _ErrorCheck(String action, PortAudioSharp.PortAudio.PaError errorCode)
- {
- if (errorCode != PortAudioSharp.PortAudio.PaError.paNoError)
- {
- CLog.LogError(action + " error (rec): " + PortAudioSharp.PortAudio.Pa_GetErrorText(errorCode));
- if (errorCode == PortAudioSharp.PortAudio.PaError.paUnanticipatedHostError)
- {
- PortAudioSharp.PortAudio.PaHostErrorInfo errorInfo = PortAudioSharp.PortAudio.Pa_GetLastHostErrorInfo();
- CLog.LogError("- Host error API type: " + errorInfo.hostApiType);
- CLog.LogError("- Host error code: " + errorInfo.errorCode);
- CLog.LogError("- Host error text: " + errorInfo.errorText);
- }
- return true;
- }
-
- return false;
- }
-
- private int _ApiSelect()
- {
- if (!_Initialized)
- return 0;
-
- int selectedHostApi = PortAudioSharp.PortAudio.Pa_GetDefaultHostApi();
- int apiCount = PortAudioSharp.PortAudio.Pa_GetHostApiCount();
- for (int i = 0; i < apiCount; i++)
- {
- PortAudioSharp.PortAudio.PaHostApiInfo apiInfo = PortAudioSharp.PortAudio.Pa_GetHostApiInfo(i);
- if ((apiInfo.type == PortAudioSharp.PortAudio.PaHostApiTypeId.paDirectSound)
- || (apiInfo.type == PortAudioSharp.PortAudio.PaHostApiTypeId.paALSA))
- selectedHostApi = i;
- }
- return selectedHostApi;
- }
}
}
\ No newline at end of file
diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj
index 111f9a7e..047fbfd9 100644
--- a/Vocaluxe/Vocaluxe.csproj
+++ b/Vocaluxe/Vocaluxe.csproj
@@ -221,6 +221,7 @@
+