Fix bug with record devices with only 1 channel
This commit is contained in:
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)
|
||||
|
||||
Reference in new issue
Block a user