Я работаю со звуковой картой с несколькими входами и хочу добиться живого микширования нескольких входов. Все входы стерео, поэтому мне нужно сначала разделить их, смешать выбранные каналы и предоставить их как монопоток.
Целью будет что-то вроде этого микса Channel1[левый] + Channel3[правый] + Channel4[правый] -> монопоток.
Я уже реализовал такую цепочку процессов:
1) WaveIn -> создать BufferedWaveProvider для каждого канала -> добавить образцы (только для текущего канала) в каждый BufferedWaveProvider с помощью wavein.DataAvailable += { buffwavprovider[channel].AddSamples(...)... Это дает мне хороший список нескольких BufferdWaveProvider. Разделение звуковой части здесь реализовано корректно.
2) Выберите несколько BufferedWaveProviders и передайте их MixingWaveProvider32. Затем создайте WaveStream (используя WaveMixerStream32 и IWaveProvider).
3) MultiChannelToMonoStream берет этот WaveStream и генерирует микс. Это также работает.
Но результат в том, что звук прерывается. Вроде какая-то беда с буфером....
Это правильный способ решения этой проблемы или есть лучшее решение?
редактировать - добавлен код:
public class AudioSplitter
{
public List<NamedBufferedWaveProvider> WaveProviders { private set; get; }
public string Name { private set; get; }
private WaveIn _wavIn;
private int bytes_per_sample = 4;
/// <summary>
/// Splits up one WaveIn into one BufferedWaveProvider for each channel
/// </summary>
/// <param name="wavein"></param>
/// <returns></returns>
public AudioSplitter(WaveIn wavein, string name)
{
if (wavein.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
throw new Exception("Format must be IEEE float");
WaveProviders = new List<NamedBufferedWaveProvider>(wavein.WaveFormat.Channels);
Name = name;
_wavIn = wavein;
_wavIn.StartRecording();
var outFormat = NAudio.Wave.WaveFormat.CreateIeeeFloatWaveFormat(wavein.WaveFormat.SampleRate, 1);
for (int i = 0; i < wavein.WaveFormat.Channels; i++)
{
WaveProviders.Add(new NamedBufferedWaveProvider(outFormat) { DiscardOnBufferOverflow = true, Name = Name + "_" + i });
}
bytes_per_sample = _wavIn.WaveFormat.BitsPerSample / 8;
wavein.DataAvailable += Wavein_DataAvailable;
}
/// <summary>
/// add samples for each channel to bufferedwaveprovider
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Wavein_DataAvailable(object sender, WaveInEventArgs e)
{
int channel = 0;
byte[] buffer = e.Buffer;
for (int i = 0; i < e.BytesRecorded - bytes_per_sample; i = i + bytes_per_sample)
{
byte[] channel_buffer = new byte[bytes_per_sample];
for (int j = 0; j < bytes_per_sample; j++)
{
channel_buffer[j] = buffer[i + j];
}
WaveProviders[channel].AddSamples(channel_buffer, 0, channel_buffer.Length);
channel++;
if (channel >= _wavIn.WaveFormat.Channels)
channel = 0;
}
}
}
Использование Audiosplitter для каждого канала дает список буферизованных волновых провайдеров (моно 32-битное число с плавающей запятой).
var mix = new MixingWaveProvider32(_waveProviders);
var wps = new WaveProviderToWaveStream(mix);
MultiChannelToMonoStream mms = new MultiChannelToMonoStream(wps);
new Thread(() =>
{
byte[] buffer = new byte[4096];
while (mms.Read(buffer, 0, buffer.Length) > 0 && isrunning)
{
using (FileStream fs = new FileStream("C:\\temp\\audio\\mono_32.wav", FileMode.Append, FileAccess.Write))
{
fs.Write(buffer, 0, buffer.Length);
}
}
}).Start();