Использование NAudio для воспроизведения WAV с пользовательским кодеком

У меня есть файл WAV, записанный с использованием пользовательского кодека. Кодек был установлен на моем компьютере, и файл WAV отлично воспроизводится на моем компьютере с помощью проигрывателя Windows Media. Я использую подпрограммы NAudio, чтобы попытаться воспроизвести файл WAV с помощью кода C#. Значения пользовательского формата выглядят странно, но я тщательно проверил их, проанализировав заголовок файла WAV. Вот лучший код C#, который я придумал для воспроизведения файла:

WaveFormat wfOKI = WaveFormat.CreateCustomFormat(WaveFormatEncoding.DialogicOkiAdpcm, 8000, 1, 3000, 48, 3);
WaveStream wsRaw = new WaveFileReader(txtFileName.Text);
wsRaw = WaveFormatConversionStream.CreatePcmStream(wsRaw);    // Line A
wsRaw = new BlockAlignReductionStream(wsRaw);                 // Line B
WaveStream wsOKI = new RawSourceWaveStream(wsRaw, wfOKI);

WaveOut woCall = new WaveOut();
woCall.Init(wsOKI);    // <-- This line gives an error.
woCall.Play();

while (woCall.PlaybackState == PlaybackState.Playing)
{
    System.Threading.Thread.Sleep(300);
}

Init() вызывает следующую ошибку: в NAudio.dll произошло необработанное исключение типа «NAudio.MmException». Дополнительная информация: WaveBadFormat вызывает waveOutOpen.

Является ли код правильной стратегией для воспроизведения WAV с пользовательским кодеком? Я пробовал все четыре комбинации комментирования/в строках A и B (без разницы в сообщении об ошибке).

Я использую 64-разрядную версию Windows 7, профессиональную версию Visual Studio 2010 (проект установлен на x86) и версию 1.6 NAudio. Я очень новичок в NAudio, но у меня получилось несколько строк, которые воспроизводили «стандартный» WAV (то есть файл, в котором не использовался пользовательский кодек).


person Andrew Jens    schedule 31.10.2012    source источник


Ответы (1)


Если у вас есть WAV-файл, то RawSourceWaveStream не нужен. Вы можете воспроизводить преобразованный поток напрямую.

var wsRaw = new WaveFileReader(txtFileName.Text);
wsRaw = WaveFormatConversionStream.CreatePcmStream(wsRaw);
WaveOut woCall = new WaveOut();
woCall.Init(wsRaw);
woCall.Play();

Кроме того, вы не должны вызывать thread.sleep, чтобы дождаться его завершения, если вы используете WaveOut. Вместо этого попробуйте WaveOutEvent, если вы не используете его из приложения с графическим интерфейсом.

person Mark Heath    schedule 31.10.2012
comment
Я не смогу попробовать это до завтра, но спасибо, что нашли время ответить. Код будет запускаться из приложения Windows Form. Еще одна вещь, вы говорите, что мне не нужно определять и использовать специальный WaveFormat (для моего файла WAV, который воспроизводится только в Windows с соответствующим кодеком)? - person Andrew Jens; 31.10.2012
comment
WaveFormat уже находится в файле WAV, поэтому программа чтения файлов WAV должна обработать его и правильно передать в CreatePcmStream, который проверит его на всех кодеках, установленных на вашем ПК. - person Mark Heath; 01.11.2012
comment
Хорошо, я думаю, это имеет смысл. Я попробовал предложенный вами код (но для компиляции мне пришлось изменить переменную на WaveStream), однако я получил следующую ошибку в строке Play(): в NAudio.dll произошло необработанное исключение типа «NAudio.MmException». Дополнительная информация: AcmNotPossible вызывает acmStreamSize. - person Andrew Jens; 02.11.2012
comment
это позор. Вероятно, лучше всего просмотреть код NAudio в отладчике, чтобы выяснить, возражает ли кодек ACM слишком большие буферы или он вообще не поддерживает вызовы acmStreamSize. - person Mark Heath; 02.11.2012
comment
Привет, и еще раз спасибо. Я понял больше о том, что происходит. - person Andrew Jens; 05.11.2012
comment
Привет, и еще раз спасибо. Я понял больше о том, что происходит. Ошибка возникает в подпрограмме AcmStream.DestToSource(). В шестой раз через эту подпрограмму вызов MmException.Try(AcmInterop.acmStreamSize(...), acmStreamSize); вызывает бросок AcmNotPossible в Try(). Самое интересное в этом то, что если я удаляю оболочку MmException.Try(...) (т. е. просто вызываю AcmInterop.acmStreamSize(...) напрямую), я не получаю сбоя и слышу звук. Тем не менее, определенно есть проблема, потому что звук очень прерывистый (как будто он появляется и исчезает несколько раз в секунду). - person Andrew Jens; 05.11.2012
comment
С кодеками с плохим поведением я часто использую классы Acm более низкого уровня в NAudio, чтобы дать мне больше контроля над кодеком. Кроме того, WaveFormatConversionStream был написан с учетом кодеков CBR, а с кодеками VBR, вероятно, не следует задействовать DestToSource и SourceToDest. - person Mark Heath; 05.11.2012
comment
Хорошо, спасибо. Я буду исследовать. Есть ли пример проекта, демонстрирующий базовое использование классов Acm более низкого уровня? - person Andrew Jens; 05.11.2012
comment
Взгляните на проект NAudioDemo в классе AcmChatCodec - person Mark Heath; 05.11.2012
comment
Спасибо, я посмотрю на это. Я (почти) уверен, что проблема связана с обработкой WAV-файла VBR, как если бы это был WAV-файл CBR. Есть ли пример кода, показывающий, как обрабатывать wav-файл, закодированный с помощью VBR (или он должен просто выпадать из-под промывки с классами Acm)? - person Andrew Jens; 07.11.2012
comment
Проблема с VBR заключается в том, что вы не можете гарантировать преобразование всего буфера, поэтому кодек должен точно сообщать, сколько байтов из исходного буфера было преобразовано. Затем вы оставляете все остатки, чтобы снова передать их для следующего прохода. - person Mark Heath; 07.11.2012
comment
Начиная с версии 1.7 и далее, NAudio воспроизводит мой необычный файл WAV с помощью простого кода: var player = new WaveOut(); var reader = новый AudioFileReader (txtFileName.Text); player.Init(читатель); игрок.Играть(); Спасибо за обновления. - person Andrew Jens; 11.12.2012