Fix bug with record devices with only 1 channel

This commit is contained in:
Flamefire committed 2014-03-15 18:33:00 +01:00
1 parent de0f4777e0
commit 5c2e0d5dd9
4 files changed
+73 -77

No files matched your search

@@ -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);
}
}
}
@@ -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;
@@ -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();
@@ -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)