From 3bc8fd516f89d9179037ddd8f626dfa6f579c2aa Mon Sep 17 00:00:00 2001 From: Flamefire Date: Fri, 21 Mar 2014 20:36:36 +0100 Subject: [PATCH] Add a base record class to handle common functions (avoid duplicate code) --- ...PortAudioCommon.cs => CPortAudioHandle.cs} | 98 ++++++++--- .../Playback/PortAudio/CPortAudioStream.cs | 33 ++-- Vocaluxe/Lib/Sound/Record/CRecordBase.cs | 148 ++++++++++++++++ .../Record/DirectSound/CDirectSoundRecord.cs | 140 ++------------- .../Record/PortAudio/CPortAudioRecord.cs | 165 +++--------------- Vocaluxe/Vocaluxe.csproj | 3 +- 6 files changed, 277 insertions(+), 310 deletions(-) rename Vocaluxe/Lib/Sound/{CPortAudioCommon.cs => CPortAudioHandle.cs} (61%) create mode 100644 Vocaluxe/Lib/Sound/Record/CRecordBase.cs diff --git a/Vocaluxe/Lib/Sound/CPortAudioCommon.cs b/Vocaluxe/Lib/Sound/CPortAudioHandle.cs similarity index 61% rename from Vocaluxe/Lib/Sound/CPortAudioCommon.cs rename to Vocaluxe/Lib/Sound/CPortAudioHandle.cs index a3233047..0406055e 100644 --- a/Vocaluxe/Lib/Sound/CPortAudioCommon.cs +++ b/Vocaluxe/Lib/Sound/CPortAudioHandle.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using PortAudioSharp; using Vocaluxe.Base; @@ -8,40 +9,53 @@ 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 + /// Basic lifetime: On Init() get a new handle, close/dispose it in your close/dispose /// /// DO NEVER use following Pa_* functions other than the ones from this class: /// Initialize, Terminate, OpenStream, CloseStream /// - static class CPortAudioCommon + class CPortAudioHandle : IDisposable { private static int _RefCount; private static readonly object _Mutex = new object(); + private bool _Disposed; + private readonly List _Streams = new List(); + /// - /// Safe method to init PortAudio (adds a reference) - /// MUST call CloseDriver when done + /// Initializes PortAudio library (if required) /// - /// True on success, falso if not initialized (log written) - public static bool InitDriver() + public CPortAudioHandle() { lock (_Mutex) { if (_RefCount == 0) { if (CheckError("Initialize", PortAudio.Pa_Initialize())) - return false; + throw new Exception(); } _RefCount++; } - return true; } - /// - /// Safe method to close PortAudio - /// MUST be called _exactly_ once after successfull InitDriver call - /// - public static void CloseDriver() + ~CPortAudioHandle() { + _Dispose(false); + } + + private void _Dispose(bool disposing) + { + if (_Disposed) + return; + if (!disposing) + CLog.LogDebug("Did not close CPortAudioHandle"); + //Make sure we do not leek any streams as we may keep PA open + if (_Streams.Count > 0) + { + CLog.LogDebug("Did not close " + _Streams.Count + "PortAudio-Stream(s)"); + while (_Streams.Count > 0) + CloseStream(_Streams[0]); + } lock (_Mutex) { Debug.Assert(_RefCount > 0); @@ -49,15 +63,37 @@ namespace Vocaluxe.Lib.Sound if (_RefCount == 0) PortAudio.Pa_Terminate(); } + _Disposed = true; } - public 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) + public void Dispose() { + _Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Close the PortAudio handle once you are done + /// + public void Close() + { + Dispose(); + } + + public 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) + { + if (_Disposed) + throw new ObjectDisposedException("PortAudioHandle already disposed"); + lock (_Mutex) { - return PortAudio.Pa_OpenStream(out stream, ref inputParameters, ref outputParameters, sampleRate, framesPerBuffer, streamFlags, streamCallback, userData); + PortAudio.PaError res = PortAudio.Pa_OpenStream(out stream, ref inputParameters, ref outputParameters, sampleRate, framesPerBuffer, streamFlags, streamCallback, + userData); + if (res == PortAudio.PaError.paNoError) + _Streams.Add(stream); + return res; } } @@ -72,9 +108,9 @@ namespace Vocaluxe.Lib.Sound /// /// /// True on success - public static bool OpenInputStream(out IntPtr stream, ref PortAudio.PaStreamParameters? inputParameters, - double sampleRate, uint framesPerBuffer, PortAudio.PaStreamFlags streamFlags, - PortAudio.PaStreamCallbackDelegate streamCallback, IntPtr userData) + public 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 @@ -93,9 +129,9 @@ namespace Vocaluxe.Lib.Sound /// /// /// True on success - public static bool OpenOutputStream(out IntPtr stream, ref PortAudio.PaStreamParameters? outputParameters, - double sampleRate, uint framesPerBuffer, PortAudio.PaStreamFlags streamFlags, - PortAudio.PaStreamCallbackDelegate streamCallback, IntPtr userData) + public 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 @@ -103,11 +139,15 @@ namespace Vocaluxe.Lib.Sound OpenStream(out stream, ref inputParameters, ref outputParameters, sampleRate, framesPerBuffer, streamFlags, streamCallback, userData)); } - public static void CloseStream(IntPtr stream) + public void CloseStream(IntPtr stream) { + if (_Disposed) + throw new ObjectDisposedException("PortAudioHandle already disposed"); + lock (_Mutex) { PortAudio.Pa_CloseStream(stream); + _Streams.Remove(stream); } } @@ -118,8 +158,11 @@ namespace Vocaluxe.Lib.Sound /// Action identifier (E.g. openStream) /// Result returned by Pa_* call /// True on error - public static bool CheckError(String action, PortAudio.PaError errorCode) + public bool CheckError(String action, PortAudio.PaError errorCode) { + if (_Disposed) + throw new ObjectDisposedException("PortAudioHandle already disposed"); + if (errorCode != PortAudio.PaError.paNoError) { CLog.LogError(action + " error: " + PortAudio.Pa_GetErrorText(errorCode)); @@ -140,11 +183,10 @@ namespace Vocaluxe.Lib.Sound /// Selects the most appropriate host api /// /// The most appropriate host api - public static int GetHostApi() + public int GetHostApi() { - //Caller has to hold a reference anyway so no locking needed - if (_RefCount < 1) - return -1; + if (_Disposed) + throw new ObjectDisposedException("PortAudioHandle already disposed"); int selectedHostApi = PortAudio.Pa_GetDefaultHostApi(); int apiCount = PortAudio.Pa_GetHostApiCount(); diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs index 62a2f9f4..cd2328e2 100644 --- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs +++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs @@ -15,6 +15,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio public readonly int ID; private readonly Closeproc _Closeproc; + private CPortAudioHandle _PaHandle; private readonly CSyncTimer _SyncTimer; private int _ByteCount = 4; @@ -187,12 +188,12 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { Paused = false; _AfterFadeAction = EStreamAction.Nothing; - CPortAudioCommon.CheckError("StartStream", PortAudioSharp.PortAudio.Pa_StartStream(_Stream)); + _PaHandle.CheckError("StartStream", PortAudioSharp.PortAudio.Pa_StartStream(_Stream)); } public void Stop() { - CPortAudioCommon.CheckError("StopStream (playback)", PortAudioSharp.PortAudio.Pa_StopStream(_Stream)); + _PaHandle.CheckError("StopStream (playback)", PortAudioSharp.PortAudio.Pa_StopStream(_Stream)); Skip(0f); } @@ -210,14 +211,11 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio if (!File.Exists(fileName)) return false; - bool driverInitialized = false; try { - if (!CPortAudioCommon.InitDriver()) - return false; - driverInitialized = true; + _PaHandle = new CPortAudioHandle(); - int hostApi = CPortAudioCommon.GetHostApi(); + int hostApi = _PaHandle.GetHostApi(); _ApiInfo = PortAudioSharp.PortAudio.Pa_GetHostApiInfo(hostApi); _OutputDeviceInfo = PortAudioSharp.PortAudio.Pa_GetDeviceInfo(_ApiInfo.defaultOutputDevice); if (_OutputDeviceInfo.defaultLowOutputLatency < 0.1) @@ -227,8 +225,11 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio } catch (Exception) { - if (driverInitialized) - CPortAudioCommon.CloseDriver(); + if (_PaHandle != null) + { + _PaHandle.Close(); + _PaHandle = null; + } CLog.LogError("Error Init PortAudio Playback"); return false; } @@ -240,7 +241,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio SFormatInfo format = _Decoder.GetFormatInfo(); if (format.SamplesPerSecond == 0) { - CPortAudioCommon.CloseDriver(); + _PaHandle.Close(); + _PaHandle = null; _Decoder.Close(); _Decoder = null; CLog.LogError("Error Init PortAudio Playback (samples=0)"); @@ -262,7 +264,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio hostApiSpecificStreamInfo = IntPtr.Zero }; - if (!CPortAudioCommon.OpenOutputStream( + if (!_PaHandle.OpenOutputStream( out _Stream, ref outputParams, format.SamplesPerSecond, @@ -271,7 +273,8 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio _PaStreamCallback, IntPtr.Zero) || _Stream == IntPtr.Zero) { - CPortAudioCommon.CloseDriver(); + _PaHandle.Close(); + _PaHandle = null; _Decoder.Close(); _Decoder = null; return false; @@ -410,9 +413,11 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio private void _DoFree() { - CPortAudioCommon.CloseStream(_Stream); - CPortAudioCommon.CloseDriver(); + _PaHandle.CloseStream(_Stream); + _PaHandle.Close(); + _PaHandle = null; _Decoder.Close(); + _Decoder = null; _Closeproc(ID); } diff --git a/Vocaluxe/Lib/Sound/Record/CRecordBase.cs b/Vocaluxe/Lib/Sound/Record/CRecordBase.cs new file mode 100644 index 00000000..78630c90 --- /dev/null +++ b/Vocaluxe/Lib/Sound/Record/CRecordBase.cs @@ -0,0 +1,148 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Vocaluxe.Base; + +namespace Vocaluxe.Lib.Sound.Record +{ + /// + /// Base class to implement common functionality for Record classes + /// + abstract class CRecordBase + { + private bool _Initialized; + protected List _Devices; + protected CBuffer[] _Buffer; + + /// + /// Init recording + /// Child class should overwrite this to list devices + /// + /// true if success + public virtual bool Init() + { + if (_Initialized) + return false; + + _Devices = new List(); + _Buffer = new CBuffer[CSettings.MaxNumPlayer]; + for (int i = 0; i < _Buffer.Length; i++) + _Buffer[i] = new CBuffer(); + + _Initialized = true; + + return true; + } + + /// + /// Stop all voice capturing streams and terminates recording freeing resources + /// + public virtual void Close() + { + if (!_Initialized) + return; + + _Devices = null; + if (_Buffer != null) + { + foreach (CBuffer buffer in _Buffer) + buffer.Dispose(); + _Buffer = null; + } + + _Initialized = false; + } + + /// + /// Procedure to be called by descendent classes with data that got recorded + /// + /// Device from which the data was recorded + /// Recorded samples, assume Int16 and interleaved for multi-channels + protected void _HandleData(CRecordDevice device, byte[] data) + { + byte[] leftBuffer; + byte[] rightBuffer; + + if (device.Channels == 2) + { + leftBuffer = new byte[data.Length / 2]; + rightBuffer = new byte[data.Length / 2]; + //[]: Sample, L: Left channel R: Right channel + //[LR][LR][LR][LR][LR][LR] + //The data is interleaved and needs to be demultiplexed + for (int i = 0; i < data.Length / 4; i++) + { + leftBuffer[i * 2] = data[i * 4]; + leftBuffer[i * 2 + 1] = data[i * 4 + 1]; + rightBuffer[i * 2] = data[i * 4 + 2]; + rightBuffer[i * 2 + 1] = data[i * 4 + 3]; + } + } + else + leftBuffer = rightBuffer = data; + + if (device.PlayerChannel1 > 0) + _Buffer[device.PlayerChannel1 - 1].ProcessNewBuffer(leftBuffer); + + if (device.PlayerChannel2 > 0) + _Buffer[device.PlayerChannel2 - 1].ProcessNewBuffer(rightBuffer); + } + + /// + /// Detect Pitch and Volume of the newest voice buffer + /// + /// + public void AnalyzeBuffer(int player) + { + if (!_Initialized) + return; + + _Buffer[player].AnalyzeBuffer(); + } + + public int GetToneAbs(int player) + { + if (!_Initialized) + return 0; + + return _Buffer[player].ToneAbs; + } + + public int GetTone(int player) + { + return _Initialized ? _Buffer[player].Tone : 0; + } + + public void SetTone(int player, int tone) + { + if (!_Initialized) + return; + + _Buffer[player].Tone = tone; + } + + public float GetMaxVolume(int player) + { + return _Initialized ? _Buffer[player].MaxVolume : 0f; + } + + public bool ToneValid(int player) + { + return _Initialized && _Buffer[player].ToneValid; + } + + public int NumHalfTones() + { + return CBuffer.NumHalfTones; + } + + public float[] ToneWeigth(int player) + { + return _Initialized ? _Buffer[player].ToneWeigth : null; + } + + public ReadOnlyCollection RecordDevices() + { + return (_Initialized && _Devices.Count > 0) ? _Devices.AsReadOnly() : null; + } + } +} \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs index e0a37e8e..61b54b23 100644 --- a/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs +++ b/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs @@ -23,39 +23,28 @@ using Vocaluxe.Base; namespace Vocaluxe.Lib.Sound.Record.DirectSound { - class CDirectSoundRecord : IRecord + class CDirectSoundRecord : CRecordBase, IRecord { private bool _Initialized; - private List _Devices; + private List _Sources; - private readonly CBuffer[] _Buffer; - - public CDirectSoundRecord() + public override bool Init() { - _Buffer = new CBuffer[CSettings.MaxNumPlayer]; - for (int i = 0; i < _Buffer.Length; i++) - _Buffer[i] = new CBuffer(); + if (!base.Init()) + return false; - Init(); - } - - public bool Init() - { - DeviceCollection devices = DirectSoundCapture.GetDevices(); - _Devices = new List(); _Sources = new List(); - int id = 0; + DeviceCollection devices = DirectSoundCapture.GetDevices(); + foreach (DeviceInformation dev in devices) { using (var ds = new DirectSoundCapture(dev.DriverGuid)) { - var device = new CRecordDevice(id, dev.DriverGuid.ToString(), dev.Description, ds.Capabilities.Channels); + var device = new CRecordDevice(_Devices.Count, dev.DriverGuid.ToString(), dev.Description, ds.Capabilities.Channels); _Devices.Add(device); - - id++; } } @@ -64,14 +53,11 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound return true; } - public void Close() + public override void Close() { - if (_Initialized) - { - Stop(); - _Initialized = false; - } - //System.IO.File.WriteAllBytes("test0.raw", _Buffer[0].Buffer); + Stop(); + _Initialized = false; + base.Close(); } public bool Start() @@ -112,81 +98,6 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound return true; } - public void AnalyzeBuffer(int player) - { - if (!_Initialized) - return; - - _Buffer[player].AnalyzeBuffer(); - } - - public int GetToneAbs(int player) - { - if (!_Initialized) - return 0; - - return _Buffer[player].ToneAbs; - } - - public int GetTone(int player) - { - if (!_Initialized) - return 0; - - return _Buffer[player].Tone; - } - - public void SetTone(int player, int tone) - { - if (!_Initialized) - return; - - _Buffer[player].Tone = tone; - } - - public float GetMaxVolume(int player) - { - if (!_Initialized) - return 0f; - - return _Buffer[player].MaxVolume; - } - - public bool ToneValid(int player) - { - if (!_Initialized) - return false; - - return _Buffer[player].ToneValid; - } - - public ReadOnlyCollection RecordDevices() - { - if (!_Initialized) - return null; - - if (_Devices.Count == 0) - return null; - - return _Devices.AsReadOnly(); - } - - public int NumHalfTones() - { - if (!_Initialized) - return 0; - - return CBuffer.NumHalfTones; - } - - public float[] ToneWeigth(int player) - { - if (!_Initialized) - return null; - - return _Buffer[player].ToneWeigth; - } - private void _OnDataReady(object sender, CSampleDataEventArgs e) { if (!_Initialized) @@ -194,32 +105,7 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound CRecordDevice dev = _Devices.FirstOrDefault(device => device.Driver == e.Guid); if (dev == null) return; - byte[] leftBuffer; - byte[] rightBuffer; - - if (dev.Channels == 2) - { - leftBuffer = new byte[e.Data.Length / 2]; - rightBuffer = new byte[e.Data.Length / 2]; - //[]: Sample, L: Left channel R: Right channel - //[LR][LR][LR][LR][LR][LR] - //The data is interleaved and needs to be demultiplexed - for (int i = 0; i < e.Data.Length / 4; i++) - { - leftBuffer[i * 2] = e.Data[i * 4]; - leftBuffer[i * 2 + 1] = e.Data[i * 4 + 1]; - rightBuffer[i * 2] = e.Data[i * 4 + 2]; - rightBuffer[i * 2 + 1] = e.Data[i * 4 + 3]; - } - } - else - leftBuffer = rightBuffer = e.Data; - - if (dev.PlayerChannel1 > 0) - _Buffer[dev.PlayerChannel1 - 1].ProcessNewBuffer(leftBuffer); - - if (dev.PlayerChannel2 > 0) - _Buffer[dev.PlayerChannel2 - 1].ProcessNewBuffer(rightBuffer); + _HandleData(dev, e.Data); } } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs index 5515b8b9..76b952da 100644 --- a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs @@ -16,47 +16,33 @@ #endregion using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Runtime.InteropServices; using System.Threading; using Vocaluxe.Base; namespace Vocaluxe.Lib.Sound.Record.PortAudio { - class CPortAudioRecord : IRecord + class CPortAudioRecord : CRecordBase, IRecord { private bool _Initialized; - private readonly List _Devices = new List(); - + private CPortAudioHandle _PaHandle; private PortAudioSharp.PortAudio.PaStreamCallbackDelegate _MyRecProc; private IntPtr[] _RecHandle; - private readonly CBuffer[] _Buffer; - - public CPortAudioRecord() - { - _Buffer = new CBuffer[CSettings.MaxNumPlayer]; - for (int i = 0; i < _Buffer.Length; i++) - _Buffer[i] = new CBuffer(); - } - /// /// Init PortAudio and list record devices /// /// true if success - public bool Init() + public override bool Init() { - if (_Initialized) + if (!base.Init()) return false; try { - if (!CPortAudioCommon.InitDriver()) - return false; + _PaHandle = new CPortAudioHandle(); - _Devices.Clear(); - int hostAPI = CPortAudioCommon.GetHostApi(); + int hostAPI = _PaHandle.GetHostApi(); int numDevices = PortAudioSharp.PortAudio.Pa_GetDeviceCount(); for (int i = 0; i < numDevices; i++) { @@ -69,9 +55,6 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio } } - foreach (CBuffer buffer in _Buffer) - buffer.Reset(); - _RecHandle = new IntPtr[_Devices.Count]; _MyRecProc = _MyPaStreamCallback; _Initialized = true; @@ -80,6 +63,7 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio { _Initialized = false; CLog.LogError("Error initializing PortAudio: " + e.Message); + Close(); return false; } @@ -95,9 +79,6 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio if (!_Initialized) return false; - if (_RecHandle == null || _RecHandle.Length == 0) - return false; - Stop(); foreach (IntPtr handle in _RecHandle) @@ -128,7 +109,7 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio suggestedLatency = PortAudioSharp.PortAudio.Pa_GetDeviceInfo(_Devices[dev].ID).defaultLowInputLatency, hostApiSpecificStreamInfo = IntPtr.Zero }; - if (!CPortAudioCommon.OpenInputStream( + if (!_PaHandle.OpenInputStream( out _RecHandle[dev], ref inputParams, 44100, @@ -138,7 +119,7 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio new IntPtr(dev))) return false; - if (CPortAudioCommon.CheckError("Start Stream (rec)", PortAudioSharp.PortAudio.Pa_StartStream(_RecHandle[dev]))) + if (_PaHandle.CheckError("Start Stream (rec)", PortAudioSharp.PortAudio.Pa_StartStream(_RecHandle[dev]))) return false; } } @@ -162,97 +143,25 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio /// /// Stop all voice capturing streams and terminate PortAudio /// - public void Close() + public override void Close() { - if (!_Initialized) - return; - - foreach (IntPtr handle in _RecHandle) - CPortAudioCommon.CloseStream(handle); - CPortAudioCommon.CloseDriver(); + if (_RecHandle != null) + { + foreach (IntPtr handle in _RecHandle) + { + if (handle != IntPtr.Zero) + _PaHandle.CloseStream(handle); + } + } + if (_PaHandle != null) + { + _PaHandle.Close(); + _PaHandle = null; + } _Initialized = false; - //System.IO.File.WriteAllBytes("test0.raw", _Buffer[0].Buffer); - } - - /// - /// Detect Pitch and Volume of the newest voice buffer - /// - /// - public void AnalyzeBuffer(int player) - { - if (!_Initialized) - return; - - _Buffer[player].AnalyzeBuffer(); - } - - public int GetToneAbs(int player) - { - if (!_Initialized) - return 0; - - return _Buffer[player].ToneAbs; - } - - public int GetTone(int player) - { - if (!_Initialized) - return 0; - - return _Buffer[player].Tone; - } - - public void SetTone(int player, int tone) - { - if (!_Initialized) - return; - - _Buffer[player].Tone = tone; - } - - public float GetMaxVolume(int player) - { - if (!_Initialized) - return 0f; - - return _Buffer[player].MaxVolume; - } - - public bool ToneValid(int player) - { - if (!_Initialized) - return false; - - return _Buffer[player].ToneValid; - } - - public int NumHalfTones() - { - if (!_Initialized) - return 0; - - return CBuffer.NumHalfTones; - } - - public float[] ToneWeigth(int player) - { - if (!_Initialized) - return null; - - return _Buffer[player].ToneWeigth; - } - - public ReadOnlyCollection RecordDevices() - { - if (!_Initialized) - return null; - - if (_Devices.Count == 0) - return null; - - return _Devices.AsReadOnly(); + base.Close(); } private PortAudioSharp.PortAudio.PaStreamCallbackResult _MyPaStreamCallback( @@ -275,34 +184,10 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio numBytes = frameCount * 2; byte[] recbuffer = new byte[numBytes]; - byte[] leftBuffer; - byte[] rightBuffer; // copy from managed to unmanaged memory Marshal.Copy(input, recbuffer, 0, (int)numBytes); - if (dev.Channels == 2) - { - leftBuffer = new byte[numBytes / 2]; - rightBuffer = new byte[numBytes / 2]; - //[]: Sample, L: Left channel R: Right channel - //[LR][LR][LR][LR][LR][LR] - //The data is interleaved and needs to be demultiplexed - for (int i = 0; i < frameCount; i++) - { - leftBuffer[i * 2] = recbuffer[i * 4]; - leftBuffer[i * 2 + 1] = recbuffer[i * 4 + 1]; - rightBuffer[i * 2] = recbuffer[i * 4 + 2]; - rightBuffer[i * 2 + 1] = recbuffer[i * 4 + 3]; - } - } - else - leftBuffer = rightBuffer = recbuffer; - - if (dev.PlayerChannel1 > 0) - _Buffer[dev.PlayerChannel1 - 1].ProcessNewBuffer(leftBuffer); - - if (dev.PlayerChannel2 > 0) - _Buffer[dev.PlayerChannel2 - 1].ProcessNewBuffer(rightBuffer); + _HandleData(dev, recbuffer); } } catch (Exception e) diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index 0dc33afe..fcf7e6f6 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -222,7 +222,7 @@ - + @@ -264,6 +264,7 @@ +