Воспроизведение WAV-аудио

87

Платформа .NET Framework имеет небогатую историю поддержки звука. Версии 1.0 и 1.1 не предлагали никакого управляемого способа воспроизведения аудио, а когда долгожданная поддержка, наконец, появилась в .NET 2.0, она была представлена в форме не приводящего в восторг класса SoundPlayer (который можно найти в "малонаселенном" пространстве имен System.Media). Класс SoundPlayer довольно ограничен: он может воспроизводить только файлы в формате WAV, не поддерживает воспроизведения одновременно более одного звука и совсем не предоставляет возможностей управления никакими аспектами воспроизведения аудио (например, громкостью и балансом).

Чтобы получить эти возможности, разработчики, использующие Windows Forms, вынуждены были работать с библиотекой неуправляемого кода quartz.dll. Библиотека quartz.dll — ключевая часть DirectX, и она присутствует в проигрывателе Windows Media и операционной системе Windows. (Тот же компонент известен под названием DirectShow, а предыдущие версии назывались ActiveMovie.)

Класс SoundPlayer поддерживается в приложениях WPF. Если смириться с его существенными ограничениями, то можно сказать, что он предлагает наиболее простой и легкий способ добавления работы с аудио в приложения. Класс SoundPlayer также упаковывается в класс SoundPlayerAction. который позволяет воспроизводить звук через декларативный триггер (вместо написания нескольких строк кода C# в обработчике событий). В следующих разделах будет представлен краткий обзор обоих классов, а затем уже описания более мощных WPF-классов MediaPlayer и MediaElement.

Класс SoundPlayer

Чтобы воспроизвести звук с помощью класса SoundPlayer, понадобится выполнить перечисленные ниже шаги:

В следующем фрагменте кода демонстрируется простейший подход к загрузке и асинхронному воспроизведению аудиофайла:

SoundPlayer sp = new SoundPlayer();
sp.SoundLocation = "tada.wav";
sp.Load();
sp.PlayLooping()

До сих пор в коде предполагалось, что аудиофайл присутствует в том же каталоге, что и скомпилированное приложение. Однако загружать SoundPlayer-аудио из файла не обязательно. Для коротких звуков, которые воспроизводятся в нескольких местах приложения, возможно, разумнее встроить звуковые файлы непосредственно в скомпилированную сборку в виде двоичных ресурсов (не путайте их с декларативными ресурсами, определяемыми в коде разметки XAML). Эта техника работает со звуковыми файлами так же хорошо, как и с графическими изображениями.

Например, если добавить файл ding.wav как ресурс по имени Ding (просто перейдите к узлу Properties --> Resources (Свойства --> ресурсы) в окне Solution Explorer и воспользуйтесь поддержкой визуального конструктора), то можно будет применить следующий код для его воспроизведения:

SoundPlayer player = new SoundPlayer();
player.Stream = Properties.Resources.Ding;
player.Play();

Класс SoundPlayer не слишком хорошо работает с большими аудиофайлами, поскольку он должен загрузить в память весь файл целиком. Может показаться, что данную проблему можно разрешить, разбив большой аудиофайл на куски, однако класс SoundPlayer не предназначен для этого. Не существует простого способа такой синхронизации SoundPlayer, чтобы он мог воспроизвести множество аудиофрагментов друг за другом, поскольку он не обеспечивает никаких средств для организации очередей. Всякий раз, когда вызывается метод PlaySound() или Play(), текущее воспроизведение останавливается. Обходные пути возможны, но намного лучше вместо этого воспользоваться классом MediaElement.

Класс SoundPlayerAction

Класс SoundPlayerAction позволяет более удобно использовать класс SoundPlayer. Класс SoundPlayerAction унаследован от TriggerAction, который позволяет использовать его в ответ на любое событие.

Ниже приведена разметка кнопки, применяющей SoundPlayerAction для подключения события Click к звуку. Триггер организован так, что его можно применить к множеству кнопок (если перенести его в коллекцию Resources):

<Button Name="soundplayer" Content="Go">
              <Button.Triggers>
                            <EventTrigger RoutedEvent="Button.Click">
                                <EventTrigger.Actions>
                                    <SoundPlayerAction Source="tada.wav"></SoundPlayerAction>
                                </EventTrigger.Actions>
                            </EventTrigger>
              </Button.Triggers>
       </Button>

При использовании SoundPlayerAction звук всегда воспроизводится асинхронно.

Системные звуки

Одной из особенностей операционной системы Windows является ее способность отображать аудиофайлы на определенные системные события. Наряду с SoundPlayer в WPF также предоставлен класс SystemSounds, позволяющий получить доступ к наиболее часто используемым из этих звуков и задействовать их в собственных приложениях. Эта техника работает лучше, если все, что требуется — это простые короткие звуки, предназначенные для того, чтобы уведомить о завершении какой-то длительной операции или подать сигнал предупреждения.

К сожалению, класс SystemSounds основан на функции MessageBeep из API-интерфейса Win32, в результате чего он обеспечивает доступ только к следующим общим системным звукам:

Класс SystemSounds предоставляет свойство для каждого из этих звуков, возвращающее объект SystemSound, который можно использовать для воспроизведения звука с помощью метода Play(). Например, для воспроизведения звука Веер в коде служит следующая строка:

SystemSounds.Веер.Play();

Чтобы указать системе, какие файлы WAV следует применять для каждого системного звука, войдите в панель управления и выберите значок Звуки и аудиоустройства (в Windows ХР) либо Звук (в Windows Vista или Windows 7).

Пройди тесты
Лучший чат для C# программистов