Проблемы с качеством звука при использовании NAudio для воспроизведения нескольких файлов WAV одновременно - PullRequest
2 голосов
/ 31 мая 2011

Моя цель заключается в следующем: позволить пользователям моей программы .NET выбирать свои собственные файлы .wav для звуковых эффектов. Эти эффекты могут быть воспроизведены одновременно. NAudio показался мне лучшим выбором.

Я решил использовать WaveMixerStream32. Одна из первых проблем заключалась в том, что у моих пользователей были файлы .wav разных форматов, поэтому, чтобы иметь возможность смешивать их вместе с WaveMixerStream32, мне нужно было «нормализовать» их в общем формате. Мне не удалось найти хороший пример для подражания, поэтому я подозреваю, что моя проблема - результат неправильного выполнения этой части.

Моя проблема в том, что когда воспроизводятся некоторые звуки, на их конце появляются очень заметные звуки "щелчка". Я могу воспроизвести это сам.

Кроме того, мои пользователи жаловались на то, что иногда звуки вообще не воспроизводятся или являются "скрипучими" на всем протяжении. Я не смог воспроизвести это в процессе разработки, но я слышал это для себя в нашей производственной среде.

Я сам воспроизводил wav-файлы пользователя с помощью Windows Media и VLC, поэтому я знаю, что файлы не повреждены. Должно быть проблема в том, как я их использую с NAudio.

Моя версия NAudio v1.4.0.0.

Вот код, который я использовал. Чтобы настроить микшер:

_mixer = new WaveMixerStream32 { AutoStop = false, };
_waveOutDevice = new WaveOut(WaveCallbackInfo.NewWindow())
{
    DeviceNumber = -1,
    DesiredLatency = 300,
    NumberOfBuffers = 3,
};
_waveOutDevice.Init(_mixer);
_waveOutDevice.Play();

Удивительно, но если я установил «NumberOfBuffers» на 2, я обнаружил, что качество звука было ужасным, с слышимыми «тиками», возникающими несколько раз в секунду.

Чтобы инициализировать звуковой файл, я сделал это:

var sample = new AudioSample(fileName);
sample.Position = sample.Length; // To prevent the sample from playing right away
_mixer.AddInputStream(sample);

AudioSample - это мой класс. Его конструктор отвечает за "нормализацию" формата файла wav. Это выглядит так:

private class AudioSample : WaveStream
{
private readonly WaveChannel32 _channelStream;
public AudioSample(string fileName)
{
    MemoryStream memStream;
    using (var fileStream = File.OpenRead(fileName))
    {
        memStream = new MemoryStream();
        memStream.SetLength(fileStream.Length);
        fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
    }
    WaveStream originalStream = new WaveFileReader(memStream);
    var pcmStream = WaveFormatConversionStream.CreatePcmStream(originalStream);
    var blockAlignReductionStream = new BlockAlignReductionStream(pcmStream);
    var waveFormatConversionStream = new WaveFormatConversionStream(
        new WaveFormat(44100, blockAlignReductionStream.WaveFormat.BitsPerSample, 2), blockAlignReductionStream);
    var waveOffsetStream = new WaveOffsetStream(waveFormatConversionStream);
    _channelStream = new WaveChannel32(waveOffsetStream);
}

По сути, AudioSample делегирует свой объект _channelStream. Чтобы воспроизвести AudioSample, мой код устанавливает его «Положение» в 0. Этот код, который делает это, направляется в поток пользовательского интерфейса.

Это почти прекрасно работает. Я могу играть несколько звуков одновременно. К сожалению, качество звука плохое, как описано выше. Может кто-нибудь помочь мне понять, почему?

1 Ответ

4 голосов
/ 01 июня 2011

Несколько баллов в ответ на ваш вопрос:

  • Да, вы должны иметь все входы с одинаковой частотой дискретизации, прежде чем вводить их в смеситель. Это просто, как работает цифровой звук. Преобразование частоты дискретизации ACM, обеспечиваемое потоком WaveFormatConversion, не является блестящим (не имеет защиты наложения имен). С какой частотой дискретизации обычно используются ваши входные файлы?
  • Вы передаете каждый вход через два WaveFormatConversionStreams. Делайте это только в случае крайней необходимости.
  • Я удивлен, что вы получаете плохой звук с NumberOfBuffers = 2, который сейчас используется по умолчанию в NAudio. Вы делали паузу и возобновляли работу, потому что была ошибка, из-за которой буфер мог быть отброшен (исправлено в последней версии и будет исправлено в NAudio 1.4 final)
  • Щелчок в конце файла может означать, что он не заканчивается на нулевой выборке. Вам нужно добавить затухание, чтобы устранить это (многие медиаплееры делают это автоматически)
  • Всякий раз, когда вы устраняете проблему плохого звука, я всегда рекомендую использовать WaveFileWriter для преобразования вашего WaveStream в файл WAV (стараясь не создавать бесконечный файл!), Чтобы вы могли прослушивать его в другом медиаплеере. Это позволяет быстро определить, является ли проблема причиной обработки звука или самого воспроизведения.
...