From 5c2e0d5dd9e1da40f3f1acc02c46934756b9a114 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Sat, 15 Mar 2014 18:33:00 +0100 Subject: [PATCH] Fix bug with record devices with only 1 channel --- .../Record/DirectSound/CDirectSoundRecord.cs | 64 ++++++++--------- .../DirectSound/CSampleDataEventArgs.cs | 4 +- .../Record/DirectSound/CSoundCardSource.cs | 10 +-- .../Record/PortAudio/CPortAudioRecord.cs | 72 +++++++++---------- 4 files changed, 73 insertions(+), 77 deletions(-) diff --git a/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs index 33ef285b..5707db98 100644 --- a/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs +++ b/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs @@ -16,6 +16,8 @@ #endregion using System.Collections.ObjectModel; +using System.Linq; +using System.Runtime.InteropServices; using SlimDX.DirectSound; using System; using System.Collections.Generic; @@ -82,29 +84,18 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound foreach (CBuffer buffer in _Buffer) buffer.Reset(); - var active = new bool[_Devices.Count]; - var guid = new Guid[_Devices.Count]; - var channels = new short[_Devices.Count]; - for (int dev = 0; dev < _Devices.Count; dev++) + foreach (CRecordDevice device in _Devices) { - active[dev] = false; - if (_Devices[dev].PlayerChannel1 > 0 || _Devices[dev].PlayerChannel2 > 0) - active[dev] = true; - guid[dev] = new Guid(_Devices[dev].Driver); - channels[dev] = (short)_Devices[dev].Channels; - } - - for (int i = 0; i < _Devices.Count; i++) - { - if (active[i]) + if (device.PlayerChannel1 > 0 || device.PlayerChannel2 > 0) { - var source = new CSoundCardSource(guid[i], channels[i]) {SampleRateKhz = 44.1}; + var source = new CSoundCardSource(device.Driver, (short)device.Channels) {SampleRateKhz = 44.1}; source.SampleDataReady += _OnDataReady; source.Start(); _Sources.Add(source); } } + return true; } @@ -200,32 +191,37 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound private void _OnDataReady(object sender, CSampleDataEventArgs e) { - if (_Initialized) - { - var leftBuffer = new byte[e.Data.Length / 2]; - var rightBuffer = new byte[e.Data.Length / 2]; + if (!_Initialized) + return; + 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 / 2; i++) + for (int i = 0; i < e.Data.Length / 4; i++) { - leftBuffer[i] = e.Data[i * 2 - (i % 2)]; - rightBuffer[i] = e.Data[i * 2 - (i % 2) + 2]; - } - - foreach (CRecordDevice device in _Devices) - { - if (device.Driver == e.Guid.ToString()) - { - if (device.PlayerChannel1 > 0) - _Buffer[device.PlayerChannel1 - 1].ProcessNewBuffer(leftBuffer); - - if (device.PlayerChannel2 > 0) - _Buffer[device.PlayerChannel2 - 1].ProcessNewBuffer(rightBuffer); - } + 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); } } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/Record/DirectSound/CSampleDataEventArgs.cs b/Vocaluxe/Lib/Sound/Record/DirectSound/CSampleDataEventArgs.cs index 695cd5a3..22a9fcd1 100644 --- a/Vocaluxe/Lib/Sound/Record/DirectSound/CSampleDataEventArgs.cs +++ b/Vocaluxe/Lib/Sound/Record/DirectSound/CSampleDataEventArgs.cs @@ -5,9 +5,9 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound public class CSampleDataEventArgs : EventArgs { public readonly byte[] Data; - public readonly Guid Guid; + public readonly string Guid; - public CSampleDataEventArgs(byte[] data, Guid guid) + public CSampleDataEventArgs(byte[] data, string guid) { Data = data; Guid = guid; diff --git a/Vocaluxe/Lib/Sound/Record/DirectSound/CSoundCardSource.cs b/Vocaluxe/Lib/Sound/Record/DirectSound/CSoundCardSource.cs index cb99d629..b3a7d5c4 100644 --- a/Vocaluxe/Lib/Sound/Record/DirectSound/CSoundCardSource.cs +++ b/Vocaluxe/Lib/Sound/Record/DirectSound/CSoundCardSource.cs @@ -20,10 +20,10 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound private int _BufferPortionSize; private WaitHandle[] _WaitHandles; private double _SampleRate; - private readonly Guid _Guid; + private readonly string _Guid; private readonly short _Channels; - public CSoundCardSource(Guid guid, short channels) + public CSoundCardSource(string guid, short channels) { _Guid = guid; _Channels = channels; @@ -53,7 +53,7 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound throw new InvalidOperationException(); if (_CaptureDevice == null) - _CaptureDevice = new DirectSoundCapture(_Guid); + _CaptureDevice = new DirectSoundCapture(new Guid(_Guid)); _WaveFormat.FormatTag = WaveFormatTag.Pcm; // Change to WaveFormatTag.IeeeFloat for float _WaveFormat.BitsPerSample = 16; // Set this to 32 for float @@ -77,7 +77,7 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound for (int i = 0; i < _BufferPortionCount; i++) { - var notification = new NotificationPosition { Offset = _BufferPortionCount - 1 + (_BufferPortionSize * i), Event = new AutoResetEvent(false) }; + var notification = new NotificationPosition {Offset = _BufferPortionCount - 1 + (_BufferPortionSize * i), Event = new AutoResetEvent(false)}; _Notifications.Add(notification); } @@ -87,7 +87,7 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound for (int i = 0; i < _Notifications.Count; i++) _WaitHandles[i] = _Notifications[i].Event; - _CaptureThread = new Thread(_DoCapture) { Name = "DirectSoundCapture", IsBackground = true }; + _CaptureThread = new Thread(_DoCapture) {Name = "DirectSoundCapture", IsBackground = true}; _Running = true; _CaptureThread.Start(); diff --git a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs index 5c05be0a..156b0938 100644 --- a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs @@ -117,38 +117,30 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio for (int i = 0; i < _RecHandle.Length; i++) _RecHandle[i] = IntPtr.Zero; - var active = new bool[_Devices.Count]; for (int dev = 0; dev < _Devices.Count; dev++) { - active[dev] = false; if (_Devices[dev].PlayerChannel1 > 0 || _Devices[dev].PlayerChannel2 > 0) - active[dev] = true; - } - - for (int i = 0; i < _RecHandle.Length; i++) - { - if (active[i]) { PortAudioSharp.PortAudio.PaStreamParameters? inputParams = new PortAudioSharp.PortAudio.PaStreamParameters { - channelCount = _Devices[i].Channels, - device = _Devices[i].ID, + channelCount = _Devices[dev].Channels, + device = _Devices[dev].ID, sampleFormat = PortAudioSharp.PortAudio.PaSampleFormat.paInt16, - suggestedLatency = PortAudioSharp.PortAudio.Pa_GetDeviceInfo(_Devices[i].ID).defaultLowInputLatency + suggestedLatency = PortAudioSharp.PortAudio.Pa_GetDeviceInfo(_Devices[dev].ID).defaultLowInputLatency }; PortAudioSharp.PortAudio.PaStreamParameters? outputParams = null; if (_ErrorCheck("OpenStream (rec)", PortAudioSharp.PortAudio.Pa_OpenStream( - out _RecHandle[i], + out _RecHandle[dev], ref inputParams, ref outputParams, 44100, 882, PortAudioSharp.PortAudio.PaStreamFlags.paNoFlag, _MyRecProc, - new IntPtr(i)))) + new IntPtr(dev)))) return false; - if (_ErrorCheck("Start Stream (rec)", PortAudioSharp.PortAudio.Pa_StartStream(_RecHandle[i]))) + if (_ErrorCheck("Start Stream (rec)", PortAudioSharp.PortAudio.Pa_StartStream(_RecHandle[dev]))) return false; } } @@ -274,36 +266,44 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio { try { - frameCount *= 4; if (frameCount > 0 && input != IntPtr.Zero) { - var recbuffer = new byte[frameCount]; - var leftBuffer = new byte[frameCount / 2]; - var rightBuffer = new byte[frameCount / 2]; + CRecordDevice dev = _Devices[userData.ToInt32()]; + uint numBytes; + if (dev.Channels == 2) + numBytes = frameCount * 4; + else + numBytes = frameCount * 2; + + byte[] recbuffer = new byte[numBytes]; + byte[] leftBuffer; + byte[] rightBuffer; // copy from managed to unmanaged memory - Marshal.Copy(input, recbuffer, 0, (int)frameCount); - - // copy into left/right Buffer - for (int i = 0; i < frameCount / 2; i++) + Marshal.Copy(input, recbuffer, 0, (int)numBytes); + if (dev.Channels == 2) { - leftBuffer[i] = recbuffer[i * 2 - (i % 2)]; - rightBuffer[i] = recbuffer[i * 2 - (i % 2) + 2]; - } - - for (int i = 0; i < _RecHandle.Length; i++) - { - if (new IntPtr(i) == userData) + 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++) { - if (_Devices[i].PlayerChannel1 > 0) - _Buffer[_Devices[i].PlayerChannel1 - 1].ProcessNewBuffer(leftBuffer); - - if (_Devices[i].PlayerChannel2 > 0) - _Buffer[_Devices[i].PlayerChannel2 - 1].ProcessNewBuffer(rightBuffer); - - break; + 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); } } catch (Exception e)