Аудиоэффекты

119

Класс MediaElement является высокоуровневой оболочкой для воспроизведения звука и видео. Он предоставляет множество полезных средств и очень гибок в использовании. Его можно применять для воспроизведения музыки в фоновом режиме или для создания пользовательского видеопроигрывателя.

Однако класс MediaElement не очень хорошо приспособлен для приложений, манипулирующих аудиосодержимым в реальном времени. Например, если вы захотите применить звук в компьютерной игре или создать музыкальный синтезатор, класс MediaElement в этой роли будет как минимум неуклюжим. Вы столкнетесь со следующими проблемами:

В силу указанных причин во многих случаях лучше применить классы SoundEffect и SoundEffectInstance, расположенные в пространстве имен Microsoft.Xna.Framework.Audio. Чтобы они были доступными, необходимо добавить в проект ссылку на сборку Microsoft.Xna.Fremework.dll.

Класс SoundEffect

Этот класс предоставляет простой низкоуровневый способ воспроизведения аудиофайлов с различными звуковыми эффектами. Для применения класса SoundEffect нужно создать его экземпляр (в коде C#, но не в разметке XAML) и передать ему ресурс аудиоданных. После этого можно запускать видеоклип на воспроизведение в любой момент времени неограниченное количество раз. При этом задержка будет минимальной.

В отличие от класса MediaElement, который не поддерживает аудиоформат WAV, класс SoundEffect поддерживает только WAV. К тому же для класса SoundEffect неприемлемы старые версии формата WAV. Класс SoundEffect принимает только файлы с кодировкой PCM (моно или стерео), с размерами выборки 8 и 16 бит и частотой дискретизации 22.5, 44.1 и 48 КГц. Ниже приведен простейший пример воспроизведения аудиофайла с помощью класса SoundEffect:

// Получение аудиофайла
StreamResourceInfo sri = Application.GetResourceStream(
        new Uri("SilverlightMedia;component/Alarm01.wav", UriKind.RelativeOrAbsolute));

// Загрузка звука
SoundEffect sound = SoundEffect.FromStream(sri.Stream);

// Асинхронное воспроизведение звука
sound.Play();

В данном примере предполагается, что проект называется SilverlightMedia и содержит ресурс Alarm01.wav. В отличие от класса MediaElement, класс SoundEffect не может воспроизводить файлы содержимого. Файл нужно добавить в ресурс сборки.

При вызове метода Play() реакция будет практически мгновенная. На слух вы не сможете заметить никакой задержки.

Если планируется воспроизводить определенный звук более одного раза, можете сохранить объект SoundEffect как поле на текущей странице. Загрузите все потоки во время инициализации страницы и воспроизводите их в необходимые моменты времени.

В оперативной памяти можно одновременно хранить много объектов SoundEffect, их количество ограничено только объемом памяти. Кроме того, можно одновременно выполнять сколько угодно объектов SoundEffect (конечно, производительность других задач от этого существенно ухудшится).

Изменение параметров воспроизведения

Метод SoundEffect.Play() позволяет гибко настраивать параметры воспроизведения. Доступна перегруженная версия, принимающая три значения, которые задают громкость, тональность и баланс каналов:

// Заданы громкость 0.8, тональность 1.0 и баланс -0.3
sound.Play(0.8f, 1f, -0.3f);

Символ f после каждого параметра сообщает компилятору о том, что передается значение типа float, а не double. Если опустить f, компилятор сгенерирует сообщение об ошибке времени компиляции.

Значение громкости может изменяться от 0 (полная тишина) до 1 (максимальная громкость, определяемая текущими настройками компьютера). Значение тональности может изменяться от -1 (на одну октаву ниже) до 1 (на одну октаву выше). Нормальная тональность равна нулю. Значение баланса изменяется от -1 (включен только левый канал) до 1 (включен только правый канал). При значении 0 (оно установлено по умолчанию) оба канала равноправные.

Перекрытие звуков с помощью SoundEffectInstance

Кроме SoundEffect, для приложения Silverlight доступен еще один класс, довольно похожий на него — SoundEffectInstance. После загрузки звука в SoundEffect можно создать еще и объект SoundEffectInstance. Для этого нужно вызвать метод SoundEffect.CreateInstance():

SoundEffectInstance sound1 = sound.CreateInstance();
SoundEffectInstance sound2 = sound.CreateInstance();

Дополнительные экземпляры полезны, когда нужно манипулировать несколькими копиями одного и того же звука, накладывая их друг на друга. В этом случае создание нескольких экземпляров SoundEffectInstance — более эффективный процесс, чем повторная загрузка WAV в дополнительные объекты SoundEffect. Ниже приведен пример комбинации трех звуков:

// Низкий мягкий звук
sound1.Pitch = -0.5f;
sound1.Volume = 0.8f;

// Баланс сдвинут, тональность повышена 
sound2.Pitch = 1.5f;
sound2.Pan = -0.9f;
sound2.Volume = 0.7f;

// Одновременное воспроизведение трех звуков
sound.Play();
sound1.Play();
sound2.Play();

Класс SoundEffect предоставляет также свойство MasterVolume, которое сначала имеет значение 1. При меньшем значении уменьшается громкость класса SoundEffect и создаваемых объектов SoundEffectInstance. Свойство MasterVolume определяет значение SoundEffectInstance.Volume.

При использовании рассматриваемой методики часто полезно отложить воспроизведение одного из звуков. Один из простых и эффективных способов задержки без блокирования приложения состоит в использовании специального таймера DispatcherTimer, который генерирует событие Tick даже в потоке пользовательского интерфейса Silverlight:

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(0.5);

// Воспроизведение первых двух звуков
sound.Play();
sound1.Play();

// Запуск третьего звука через полсекунды
timer.Tick += delegate
{
       timer.Stop();
       sound2.Play();
};
            
timer.Start();

Чтобы запись была краткой, обработчик события Timer.Tick объявлен встроенным в текущий код с помощью анонимного метода. Задача кода — всего лишь остановить таймер и запустить звук, поэтому создавать дополнительный метод не имеет смысла.

Воспроизведение звука в цикле

Еще одна причина использования класса SoundEffectInstance вместо SoundEffect состоит в том, что он предоставляет ряд дополнительных свойств. Наиболее полезное из них — свойство IsLooped, позволяющее воспроизводить аудиодорожку циклически в фоновом режиме:

sound2.IsLooped = true;

Для управления циклическим воспроизведением можно использовать методы Pause(), Resume() и Stop(). В классе SoundEffect ни одного из них нет.

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