Вопрос или проблема
Пожалуйста, помогите. Я новичок. Я пытаюсь сделать инструмент, который будет разделять многоканальный вход на несколько стереовыходов. Для начала я пытаюсь просто отправить первые два канала из 6-канального входа на стереовыход, но звук выходит искаженным.
Вот мой код – ПОЖАЛУЙСТА, ПОМОГИТЕ!
public partial class Form1 : Form
{
private WasapiCapture inputCupture;
WasapiLoopbackCapture waveIn;
private BufferedWaveProvider waveBuffer;
private MediaFoundationResampler resampler;
private ChannelDivider channelDivider;
private BufferedWaveProvider waveOutBuffer;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MMDevice inputDevice = null;
MMDevice outputDevice = null;
MMDevice[] AudioDevices = new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).ToArray();
foreach (MMDevice device in AudioDevices)
{
string deviceType = device.DataFlow == DataFlow.Capture ? "INPUT" : "OUTPUT";
string deviceLabel = $"{deviceType}: {device.FriendlyName}";
Console.WriteLine(deviceLabel);
if (device.FriendlyName.Contains("Line 2")) inputDevice = device;
if (device.FriendlyName.Contains("DELL")) outputDevice = device;
}
Console.WriteLine("input: " + inputDevice.FriendlyName);
Console.WriteLine("output: " + outputDevice.FriendlyName );
inputCupture = inputDevice.DataFlow == DataFlow.Render ? new WasapiLoopbackCapture(inputDevice) : new WasapiCapture(inputDevice, true, 10);
Console.WriteLine("ch: " +inputCupture.WaveFormat.Channels);
inputCupture.DataAvailable += OnDataAvailable;
WaveFormat f = inputCupture.WaveFormat;
channelDivider = new ChannelDivider(f);
inputCupture.StartRecording();
WaveFormat w = new WaveFormat(inputCupture.WaveFormat.SampleRate, inputCupture.WaveFormat.BitsPerSample, 2);
//w = new WaveFormat(44100, 16, 2);
Console.WriteLine("format: " + w.SampleRate + "," + w.BitsPerSample);
waveOutBuffer = new BufferedWaveProvider(w);
waveOutBuffer.DiscardOnBufferOverflow = true;
WasapiOut waveOut = new WasapiOut(outputDevice, AudioClientShareMode.Shared,true, 60);
waveOut.Init(waveOutBuffer);
waveOut.Play();
}
private void OnDataAvailable(object sender, WaveInEventArgs e)
{
//waveOutBuffer.AddSamples(e.Buffer, 0, e.BytesRecorded);
//для каждого канала
int channel = 1;
for (int i = 0; i < e.BytesRecorded; i += inputCupture.WaveFormat.BitsPerSample)
{
if (channel <= 2)
{
waveOutBuffer.AddSamples(e.Buffer, i, inputCupture.WaveFormat.BitsPerSample);
}
channel++;
if (channel > inputCupture.WaveFormat.Channels) channel = 1;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
inputCupture.StopRecording();
inputCupture.Dispose();
}
}
Я пытался разделить его на несколько каналов, беря каждый набор битов из образца (BitsPerSample), думая, что именно так образец содержит разные данные для разных каналов.
Ответ или решение
Для начала, давайте подробно разберём вашу задачу с использованием библиотеки NAudio для разделения многоканального аудиовхода и отправки первых двух каналов на стереовыход. В вашем исходном коде присутствует несколько моментов, которые требуют корректировки, чтобы устранить искажения звука и успешно настроить работу с аудиопотоком.
Анализ существующего кода
Ваш код создает устройство для захвата аудио и вывода, а затем обрабатывает данные аудиопотока, однако есть несколько ошибок в логике обработки, которые приводят к искажениям звука. Основные проблемы заключаются в неправильной обработке входных данных, а также в том, как вы передаёте выборку аудиоданных в выходной буфер.
-
Определение каналов: Ваша текущая логика для выбора каналов не совсем корректна. Вы используете переменную
channel
, которая инкрементируется в цикле, но не обеспечиваете правильное считывание и распределение аудиоданных. Для многоканального звука нужно учитывать, сколько байтов соответствует каждому каналу. -
Размеры данных: Убедитесь, что вы берете правильное количество байтов с каждого канала в зависимости от формата (количество бит на образец).
Исправленный код
Вот исправленный вариант вашей функции OnDataAvailable
, который корректно обрабатывает многоканальный вход и извлекает только первые два канала:
private void OnDataAvailable(object sender, WaveInEventArgs e)
{
int bytesPerSample = inputCupture.WaveFormat.BitsPerSample / 8;
int channels = inputCupture.WaveFormat.Channels;
// Подсчёт количества выходных сэмплов (только для первых двух каналов)
int outputSamples = e.BytesRecorded / bytesPerSample; // Общее количество образцов
byte[] outputBuffer = new byte[outputSamples * 2 * bytesPerSample]; // Буфер для 2 каналов
for (int i = 0, j = 0; i < e.BytesRecorded; i += bytesPerSample * channels)
{
// Извлечение первых двух каналов
if (channels >= 1)
{
// Первый канал
Buffer.BlockCopy(e.Buffer, i, outputBuffer, j, bytesPerSample);
j += bytesPerSample;
}
if (channels >= 2)
{
// Второй канал
Buffer.BlockCopy(e.Buffer, i + bytesPerSample, outputBuffer, j, bytesPerSample);
j += bytesPerSample;
}
}
waveOutBuffer.AddSamples(outputBuffer, 0, j);
}
Пояснение изменений
-
Извлечение данных: Мы используем
Buffer.BlockCopy
для извлечения данных для каждого канала. Мы подразумеваем, что входной звук содержит несколько каналов, и корректно извлекаем только первые два. -
Код для любительского уровня: На любой интерфейс добавляем использование форматирования переменных для лучшего управления потоками.
Финальные мысли
После внесения предложенных изменений, выполните тестирование вашего приложения, чтобы убедиться, что звук передаётся корректно без искажений. Возможно, вам потребуется протестировать разные устройства и их настройки, чтобы получить оптимальный результат в зависимости от конфигурации оборудования.
Надеюсь, что мои рекомендации помогут вам справиться с задачей. Если у вас возникнут дополнительные вопросы, не стесняйтесь обращаться за помощью!