Работа с MCI (Звук)

    Итерфейс управления устройствами MCI (Media Control Interface) позволяет программам для Windows взаимодействовать со множеством устройств мультимедиа — компакт-диск-плейерами, цифровым аудио и МIDI-синтезаторами на звуковых платах, проигрывателями видеодисков, видеомагнитофонами и т.п. В этой главе мы продолжим с того же места, где остановились в конце предыдущей, и покажем вам, как можно воспроизводить WAV-файлы (оцифрованный звук) при помощи функций MCI. Затем мы спустимся этажом ниже и рассмотрим низкоуровневые звуковые фуцкции.

Использование MCI
    При помощи функций МСI мы можем управлять любым из перечисленных выше устройств, посылая ему специальные команды: начать воспроизведение, остановиться, переместиться в начало или конец файла и т.д. Во многом это похоже на манипуляции с кнопками на панели управления магнитофоном. Конкретный набор команд для каждого устройства определяется возможностями этого устройства. Например, устройство цифрового ввода-вывода на звуковой карте может записывать звук в файл, в то время как компакт-плейер может только воспроизводить. Любую команду, мы передаем МСI-устройству в качестве аргумента одной из функций интерфейса MCI. Кроме командных функций, интерфейс MCI включает еще и две функции поддержки.
    Все функции MCI начинаются с префикса mci и делятся на три группы:

    Последняя функция, mciSetYieldProc(), позволяет МСI продолжать диалог с вашим приложением после того, как вы дадите команду МСI с флагом WAIT. Этот флаг сообщает МСI о том, что управление должно вернуться к приложению только тогда, когда посланная команда будет полностью выполнена. Например, вы можете дать МСI команду воспроизведения MIDI-файла продолжительностью в несколько минут. Без флага WAIT МСI начнет воспроизводить файл и тут же вернет управление вашей программе — файл будет воспроизводиться в фоне. Если же вы используете флаг WAIT, то выполнение вашей программы будет "заморожено" до тех пор, пока файл не доиграет до конца. Оба метода обладают преимуществами и недостатками. mciSetYieldProc() позволяет следить за процессом выполнения команды с флагом WAIT. VC++ действительно поддерживает такой тип взаимодействия с API, однако для наших целей он не нужен.
    Два командных интерфейса высокого уровня, Command-Massage и Comand-String, выполняют примерно одни и те же функции. Они позволяют начать или остановить воспроизведение WAV- или MID-файла, перейти к седьмой дорожке на компакт-диске и т.п. — примерно то же самое, что вы можете сделать при помощи пульта дистанционного управления своей стереосистемой. Отличие между этими двумя интерфейсами заключается только в способе подачи команд и сводится к отличию между числами и словами —конечный результат всегда один и тот же.

Звук при помощи mciSendString() и mciSendCommand()
    Давайте спустимся на уровень ниже и исследуем возможности функций mciSendString() и mciSendCommand() —обе эти функции весьма полезны для воспроизведения WAV-файлов. mciSendString() проще, поэтому начнем именно с нее. Вы уже встречались с этой функцией в третьей главе , теперь же мы посмотрим на нее более внимательно. Описание этой функции выглядит следующим образом:MCIERRORmciSendString(LPTSTR IpszCommand

    Давайте разберемся с этими четырьмя параметрами, хотя пока нас интересует только первый — остальные три понадобятся нам чуть-чуть позже.
 
 
IpszCommand  Указывает на завершающуюся нулем строку с командой в следующей форме: [команда] [устройство] [параметры].
IpszReturnString Указывает на буфер для получения информации о результате. Если такая информация не нужна, этот параметр можно установить равным NULL.
cchReturn  Указывает размер (в символах) определенного предыдущим параметром буфера. Если буфер не нужен, этот параметр, должен быть равен 0.
hwndCallback Указывает на окно "отклика", если в командной строке указан параметр 'notify' (подтвердить). Если "notify" не указан, то этот параметр может быть NULL.
 

    Кроме mciSendString(), для воспроизведения WAV-файлов можно использовать и функцию mciSendCommand(), описывающуюся следующим образом:

MCIERROR mciSendCommand(MCIDEVICEID IDDevice, UINT uMsg, DWORD fdwConmnd,
DWORD dwParam);

 Для работы этой функции требуются следующие параметры:
 
 
IDDevice  Идентификатор MCI-устройства, которому адресуется команда. Этот параметр не используется для команды MCI_OPEN.
uMsg Командное сообщение.
fdwCommand  Флаги для командного сообщения.
dwParam Указатель на структуру с параметрами для командного сообщения.
 

    Обе эти функции возвращают величину типа MCIERROR, который на самом деле является ни чем иным, как типом DWORD. Если функция возвращает 0, то все в порядке — команда выполнена успешно. В случае какой-либо ошибки функции возвращают ненулевой код ошибки. Собственно, сам код находится в младшем байте слова. Если ошибка специфична для определенного устройства, то функция mciSendCommand() помещает в старший байт возвращаемого слова идентификатор устройства, в противном случае старший байт остается равным нулю.
    Обратите внимание на четвертый параметр — указатель на структуру с данными, необходимыми для выполнения команды. Мы ничего не сказали о типе этой структуры. Просто различные команды пользуются различными наборами исходных данных. Вызывая mciSendCommand(), мы создаем стуктуру с данными, необходимыми конкретной команде, и передаем функции указатель на нее. При помощи такой техники парни из Microsoft сумели свести множество операций МСI к одному интерфейсу. В любом другом случае вам понадобились бы отдельные функции для каждого действия, каждая со своим собственным набором параметров. Мы же вместо всего этого имеем возможность пользоваться одной-единственной функцией, сообщая ей, где найти необходимую информацию.