Программирование звука в DirectSound

Уровни взаимодействия

DirectSound вводит четыре уровня взаимодействия (cooperation levels) приложений между собой и звуковым адаптером. Когда несколько приложений одновременно используют один и тот же адаптер, соотношение уровней взаимодействия определяет их приоритетность в использовании аппаратуры и создании звучания.

  • Обычный (normal) уровень фиксирует формат первичного буфера адаптера — 22 050 Гц, стерео, 8-разрядные отсчеты. Форматы вторичных буферов преобразуются в этот формат, и при переключении приложений подсистеме нет необходимости изменять формат первичного буфера. На этом уровне достигается наибольшая универсальность и, кроме того, эффективность, однако качество звука в таком формате весьма посредственно и не допускается уплотнение (оптимизация) внутренней памяти адаптера.
  • Приоритетный (priority) уровень позволяет приложению устанавливать формат первичного буфера и уплотнять внутреннюю память адаптера — то есть предоставляет приоритетный доступ к аппаратным ресурсам, когда окно приложения становится активным (foreground). Если происходит переключение между приложениями этого уровня, установившими различные форматы первичного буфера, — подсистема вынуждена переключать форматы, для чего необходим перезапуск адаптера, нередко порождающий щелчки и тому подобные помехи.
  • Исключительный (exclusive) уровень подобен приоритетному, но на время активности окна приложения ему предоставляется исключительный доступ к адаптеру, и звучание источников всех остальных приложений заглушается (но не останавливается).
  • Уровень доступа к первичному буферу (write-primary) разрешает приложению прямую запись в первичный буфер адаптера. Этот уровень доступен только для устройств, имеющих специализированный DirectSound-драйвер. На этом уровне приложение может работать только с первичным буфером, активизация вторичных буферов запрещена.
В начало

В начало

Потеря буферов

Когда приложение, запросившее высший (write-primary) уровень взаимодействия, становится активным, подсистеме приходится передавать ему управление первичным буфером, теряя при этом собственный контроль над ним. И наоборот, когда активным становится приложение с менее высоким уровнем, подсистема возвращает себе контроль над буфером, но теперь его теряет «уходящее в фон» приложение. В этой ситуации, называемой потерей буферов (buffer lose), буфер прекращает звучание и его содержимое теряется.

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

Приложения получают сообщение о потере буферов при попытках обращения к ним в виде кода ошибки DSERR_BUFFERLOST. Все приложения должны корректно обрабатывать эту ситуацию и выполнять восстановление потерянных буферов.

В начало

В начало

Эмуляция

Подсистема DirectSound может обходиться без поддержки со стороны драйвера. В этом случае нужная функциональность эмулируется через MME — традиционную звуковую подсистему Windows. Однако такая эмуляция крайне неэффективна, поскольку при этом подсистеме DirectSound приходится эмулировать первичный буфер в обычной памяти, смешивать в нем звуки из вторичных буферов, затем представлять его в виде цепочки буферов, передаваемых драйверу MME, который, в свою очередь, разбивает их на фрагменты и переносит в звуковой буфер адаптера. При этом каждое обращение к драйверу MME сопровождается переключением в 16-разрядный режим и обратно.

Отметим, что без наличия специализированного DirectSound-драйвера невозможно получить высший (write-primary) уровень взаимодействия с адаптером.

Тем не менее поддержка захвата (capture) звука в DirectSound реализована только методом эмуляции. Для драйверов DirectSound VxD определены лишь функции поддержки воспроизведения — дальше в унификации этого интерфейса Microsoft почему-то не пошла. Операции записи и воспроизведения с точки зрения адаптера почти идентичны и различаются в основном направлением движения данных. Однако прямой доступ к буферу адаптера в режиме записи позволил бы значительно повысить эффективность обработки входного сигнала в реальном времени. Поддержка записи звука определена только для драйверов WDM.

В начало

В начало

Задержки звука

Подсистема MME из-за переключений между 32- и 16-разрядными режимами и неоптимальной с точки зрения адаптера структуры буферов часто дает существенную задержку (latency) между подачей звукового блока драйверу и появлением звука на выходе, равно как и в обратном направлении (при записи). DirectSound, за счет более оптимального управления адаптером, вносит задержки на уровне около 20 мс. Однако при эмуляции, когда работа идет через подсистему MME, задержки могут возрасти до 100-150 мс.

В начало

В начало

Идентификация устройств

В отличие от подсистем MME, идентификация устройств в DirectSound следует правилам COM и использует GUID (Globally Unique IDentifier — идентификатор, уникальный в мировом масштабе). Любой объект COM имеет свой идентификатор, по которому приложения могут обращаться к нему. Идентификаторы доступных устройств приложение получает в процессе перебора (enumeration) устройств заданного класса.

В начало

В начало

Уведомление о наступлении событий

Событием в подсистеме DirectSound считается достижение одной из заданных позиций в звуковом буфере. Для запроса уведомления о наступлении таких событий приложение может использовать специальный интерфейс IDirectSoundNotify, создавая соответствующие ему следящие объекты. При достижении указанных позиций следящий объект активизирует (set) заданные объекты события (event objects), которые могут быть опрошены приложением непосредственно, либо может быть создана отдельная задача (thread), ожидающая активизации одного или нескольких объектов событий.

В начало

В начало

Наборы свойств

DirectSound вводит понятие набора свойств (property set) — параметров, описывающих виды обработки звука. При помощи набора свойств можно описать параметры зала, голоса исполнителя, манеры пения, звучания инструментов и т.п. При наличии необходимых средств обработки одну и ту же звуковую картину можно представлять в разных ракурсах, активизируя нужные наборы свойств.

В данное время эти виды обработки почти не поддерживаются; наборы свойств введены в основном на будущее.

В начало

В начало

Именование интерфейсных функций

Различные интерфейсы имеют наборы функций (методов) с разными именами, поэтому в ссылках я буду приводить только имена методов, не снабжая их именем интерфейса. В прототипах имена всех методов приводятся полностью, с указанием интерфейса.

Поскольку ряд интерфейсов имеет схожую структуру (IDirectSound/IDirectSoundCapture, IDirectSoundBuffer/IDirectSound3DBuffer), многие методы являются общими для нескольких интерфейсов сразу. В таких случаях я буду упоминать имя интерфейса, только если в использовании одного и того же метода в разных интерфейсах существует принципиальная разница.

В начало

В начало

Совместимость

Интерфейсы DirecSound доступны для платформ Windows 98 или 2000 и выше. В Windows 95 интерфейсы становятся доступными после установки пакета DirectX. В Windows NT 4/SP3 доступен только базовый уровень функциональности — интерфейсы IDirectSound и IDirectSoundBuffer.

В начало

В начало

Общая схема взаимодействия программы и DirectSound

Приложение начинает работу с DirectSound, создавая объект устройства с интерфейсом IDirectSound — для воспроизведения звука или IDirectSoundCapture — для захвата (записи) звука. Объект устройства воспроизведения создается функцией DirectSoundCreate, объект устройства захвата — DirectSoundCaptureCreate.

При создании объекта устройства указывается идентификатор устройства, которое будет через него программироваться. Приложение может либо запросить доступ к устройству по умолчанию, либо получить перечень идентификаторов доступных устройств функцией перебора — DirectSoundEnumerate или DirectSoundCaptureEnumerate.

Функции перебора требуют указания локальной перебирающей функции приложения (callback), которая будет вызываться для каждого доступного устройства. Перебирающая функция может либо самостоятельно выбрать подходящее устройство, либо сформировать полный список устройств, из которого пользователь сделает выбор по своему усмотрению.

Созданный объект устройства может быть опрошен методом GetCaps, возвращающим его характеристики и возможности. Таким образом может быть, например, найдено минимально и оптимально подходящее для целей приложения устройство из всех имеющихся в системе.

Перед началом работы с устройством необходимо установить уровень взаимодействия методом SetCooperativeLevel.

Работа со звуком начинается с создания объектов звуковых буферов. Если приложение работает на обычном уровне взаимодействия, первичный буфер не создается. На остальных уровнях необходимо создать первичный буфер методом CreateSoundBuffer и задать его формат методом SetFormat. На обычном уровне взаимодействия формат первичного буфера фиксирован — 22 050 Гц, стерео, восемь разрядов.

Объекты вторичных звуковых буферов также создаются при помощи метода CreateSoundBuffer — по одному для каждого источника звука; в этом же вызове задаются и форматы буферов. Для коротких звуков длительностью до нескольких секунд удобнее создавать статические буферы, целиком вмещающие цифровое представление звуков. Для длительных звуков рекомендуется создавать небольшие (порядка десятков-сотен килобайт) потоковые буферы, через которые будут непрерывно «прогоняться» фрагменты длительного звучания.

Создав вторичный буфер, приложение должно заполнить его звуковыми данными. Процедуру занесения данных в буфер открывает метод Lock, возвращающий указатели доступных участков буфера. Эти участки заполняются данными, после чего вызывается метод Unlock, завершающий процедуру обновления данных.

При желании приложение может разделить один и тот же экземпляр звучания между несколькими объектами буферов, создавая объекты-копии методом DuplicateSoundBuffer. Впоследствии, изменяя параметры звучания, можно получать различные звуки на основе одной и той же оцифровки, не расходуя дополнительную память.

Для запуска воспроизведения буфера вызывается метод Play, для остановки — Stop. Чтобы определить, какой фрагмент звучит в данный момент, используется метод GetCurrentPosition, для запуска звучания с определенного места — SetCurrentPosition.

При необходимости приложение может изменить параметры звучания в буфере: частоту дискретизации (SetFrequency), громкость (SetVolume), положение на панораме (SetPan). Для пространственных источников возможно изменение координат, ориентации, скорости движения и т.п.

Для корректной работы приложение должно отслеживать ситуацию потери буферов. Получив от методов Lock или Play сообщение о потере буфера, необходимо приостановить генерацию звука и периодически выполнять метод Restore до тех пор, пока он не даст положительного результата. После этого буфер следует вновь заполнить звуковыми данными.

Захват (запись) звука производится с помощью объектов устройств IDirectSoundCapture. Здесь нет разделения на первичный и вторичные буферы, поэтому методом CreateCaptureBuffer создается единственный буфер захвата, которому этим же методом приписывается нужный формат. Затем методом Start запускается захват звука, который может быть остановлен методом Stop. Для извлечения звуковых данных из буфера служат методы Lock и Unlock. Процесс захвата во многом симметричен процессу воспроизведения, поэтому в описании интерфейсов захвата упомянуты лишь их отличия от основных интерфейсов.

При желании приложение может воспользоваться интерфейсом уведомления IDirectSoundNotify, запрашивая его у объектов тех буферов, для которых требуются уведомления, и заказывая установку заданных объектов программных событий (event objects) по достижении определенных позиций в буфере.

Завершая работу, приложение уничтожает методом Release объекты буферов, а затем — объекты устройств.

В начало

В начало

Программирование в DirectSound

Средства разработки, включаемые файлы и библиотеки

Описывается программирование на языке C++ в среде Microsoft Visual C++. DirectSound поддерживает программирование и из обычного C, однако использование C++ позволяет более естественно оформлять работу с интерфейсами и не ведет к какому бы то ни было увеличению объектного кода по сравнению с C, поскольку модель DirectSound изначально ориентирована на объекты и методы обращения к ним из C++.

Полный комплект DirectX 7.0a SDK занимает 128 Мбайт, однако наиболее важные его части доступны отдельно. Набор документации включаемых заголовочных файлов и библиотек занимает 1,3 Мбайт и доступен по ссылке http://download.microsoft.com/download/win98SE/DXSDK/7.0/W9X/EN-US/dx7libhdr.exe.

Вместе с демонстрационной программой к статье прилагаются файлы dsound.h и dsound.lib из комплекта DirectX SDK 7.0a. Тем не менее одних этих файлов недостаточно для построения примера; среда разработки должна поддерживать хотя бы одну из версий DirectX.

В начало

В начало

Структуры, используемые при работе с подсистемой

Все структуры имеют поле dwSize, в которое при инициализации структуры необходимо занести ее размер в байтах. Размер используется для определения версии интерфейса. Это единственное поле, которое требует обязательной инициализации во всех структурах; остальные поля заполняются, только если они являются входными.

В начало

В начало

DSCAPS — параметры устройства воспроизведения

Данная структура описывает возможности и параметры устройства воспроизведения. Для удобства определен тип LPCDSCAPS — константный указатель на тип DSCAPS.

DWORD   dwSize;
 DWORD   dwFlags;
 DWORD   dwMinSecondarySampleRate;
 DWORD   dwMaxSecondarySampleRate;
 DWORD   dwPrimaryBuffers;
 DWORD   dwMaxHwMixingAllBuffers;
 DWORD   dwMaxHwMixingStaticBuffers;
 DWORD   dwMaxHwMixingStreamingBuffers;
 DWORD   dwFreeHwMixingAllBuffers;
 DWORD   dwFreeHwMixingStaticBuffers;
 DWORD   dwFreeHwMixingStreamingBuffers;
 DWORD   dwMaxHw3DAllBuffers;
 DWORD   dwMaxHw3DStaticBuffers;
 DWORD   dwMaxHw3DStreamingBuffers;
 DWORD   dwFreeHw3DAllBuffers;
 DWORD   dwFreeHw3DStaticBuffers;
 DWORD   dwFreeHw3DStreamingBuffers;
 DWORD   dwTotalHwMemBytes;
 DWORD   dwFreeHwMemBytes;
 DWORD   dwMaxContigFreeHwMemBytes;
 DWORD   dwUnlockTransferRateHwBuffers;
 DWORD   dwPlayCpuOverheadSwBuffers;
 DWORD   dwReserved1;
 DWORD   dwReserved2;
  • dwSize — размер структуры в байтах;
  • dwFlags — флаги характеристик устройства. Имена флагов имеют префикс DSCAPS_:

CONTINUOUSRATE

Устройство поддерживает любые значения частоты дискретизации — от минимальной до максимальной с точностью примерно до 10 Гц. Отсутствие этого флага означает поддержку только стандартных частот — 8000, 11 025, 22 050 и т.д.

PRIMARY16BIT

В первичном буфере поддерживаются 16-разрядные форматы

PRIMARY8BIT

В первичном буфере поддерживаются 8-разрядные форматы

PRIMARYMONO

В первичном буфере поддерживаются монофонические форматы

PRIMARYSTEREO

В первичном буфере поддерживаются стереофонические форматы

SECONDARY16BIT

Аппаратный микшер поддерживает вторичные буферы в 16-разрядных форматах

SECONDARY8BIT

Аппаратный микшер поддерживает вторичные буферы в 8-разрядных форматах

SECONDARYMONO

Аппаратный микшер поддерживает вторичные буферы в монофонических форматах

SECONDARYSTEREO

Аппаратный микшер поддерживает вторичные буферы в стереофонических форматах

EMULDRIVER

Устройство не имеет специализированного драйвера, и DirectSound эмулирует интерфейсы посредством стандартной подсистемы MME/Wave

CERTIFIED

Драйвер устройства проверен и сертифицирован Microsoft

  • dwMinSecondarySampleRate, dwMaxSecondarySampleRate — минимальная и максимальная частота дискретизации, поддерживаемая для аппаратных вторичных буферов;
  • dwPrimaryBuffers — количество поддерживаемых первичных буферов. В текущей модели всегда равно единице;
  • dwMaxHwMixingAllBuffers — максимальное общее количество поддерживаемых буферов с аппаратным смешиванием. Может быть меньше суммы числа статических и потоковых буферов из-за различия способов их организации в аппаратуре;
  • dwMaxHwMixingStaticBuffers — максимальное количество статических звуковых буферов с аппаратным смешиванием;
  • dwMaxHwMixingStreamingBuffers — максимальное количество потоковых звуковых буферов с аппаратным смешиванием;
  • dwFreeHwMixingAllBuffers, dwFreeHwMixingStaticBuffers, dwFreeHwMixingStreamingBuffers — количество свободных буферов с аппаратным смешиванием — всех, статических и потоковых;
  • dwMaxHw3DAllBuffers, dwMaxHw3DStaticBuffers, dwMaxHw3DStreamingBuffers — максимальное количество аппаратных буферов для источников объемного звука — всех, статических и потоковых;
  • dwFreeHw3DAllBuffers, dwFreeHw3DStaticBuffers, dwFreeHw3DStreamingBuffers — количество свободных аппаратных буферов для источников объемного звука — всех, статических и потоковых.
  • dwTotalHwMemBytes — общий объем внутренней памяти адаптера, доступной для размещения статических буферов;
  • dwFreeHwMemBytes — объем свободной внутренней памяти адаптера;
  • dwMaxContigFreeHwMemBytes — объем наибольшего непрерывного участка внутренней памяти адаптера;
  • dwUnlockTransferRateHwBuffers — скорость пересылки данных из основной памяти в память адаптера (Кбайт/с). Пересылка выполняется при вызове метода Unlock, время отработки метода может быть определено из значения этого поля и объема занесенных в буфер звуковых данных;
  • dwPlayCpuOverheadSwBuffers — приблизительная доля времени центрального процессора (в %), необходимая для смешивания звука из буферов, расположенных в основной памяти;
  • dwReserved1, dwReserved2 — служебные поля.
В начало

В начало

Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует