3.6.3. Программное определение возможностей звуковых устройств мультимедиа В системе могут быть установлены устройства для записи и воспроизведения звука методом импульсно-кодовой модуляции PCM (waveform audio), устройства для записи и проигрывания музыкальных MIDI-файлов, дополнительные (auxiliary) устройства (например, проигрыватель звуковых компакт-дисков) и другие. Библиотека mmsystem.dll содержит набор функций, с помощью которых приложение может определить состав устройств и их возможности. Не имеющая параметров функция waveOutGetNumDevs возвращает количество устройств, способных воспроизводить записанные с использование импульсно-кодовой модуляции звуковые данные; функция waveInGetNumDevs возвращает количество устройств, способных записывать такие данные. Количество пригодных для записи и воспроизведения MIDI-файлов устройств можно узнать при помощи функций midiOutGetNumDevs и midiInGetNumDevs соответственно. Для определения дополнительных устройств предназначена функция auxGetNumDevs. Для определения возможностей устройств используются функции waveOutGetDevCaps (возможности устройств вывода данных, записанных методом импульсно-кодовой модуляции), waveInGetDevCaps (возможности устройств записи данных методом импульсно-кодовой модуляции), midiOutGetDevCaps (возможности устройств воспроизведения в формате MIDI) и auxGetDevCaps (возможности дополнительных устройств). Для вышеперечисленных функций с суффиксом GetDevCaps в качестве первого параметра указывается идентификатор устройства, изменяющийся от нуля (для первого устройства) до полученного с помощью функций waveOutGetNumDevs, waveInGetNumDevs, midiOutGetNumDevs, midiInGetNumDevs и auxGetNumDevs значения. Второй параметр является дальним указателем на структуру, формат которой зависит от типа устройства. Это может быть структура AUXCAPS (дополнительное устройство), MIDIINCAPS (устройство для ввода данных MIDI), MIDIOUTCAPS (устройство вывода MIDI-данных), WAVEINCAPS (устройство ввода данных, записанных методом импульсно-кодовой модуляции) или WAVEOUTCAPS (устройство вывода данных, записанных методом импульсно-кодовой модуляции). Третий параметр определяет размер соответствующей структуры в байтах. Структура AUXCAPS определяется следующим образом typedef struct auxcaps_tag { UINT wMid; // код разработчика драйвера UINT wPID; // код устройства VERSION vDriverVersion; // версия драйвера char szPname[MAXPNAMELEN]; // название устройства UINT wTechnology; // тип устройства DWORD dwSupport; // поддерживаемые функции } AUXCAPS; typedef AUXCAPS *PAUXCAPS; typedef AUXCAPS NEAR *NPAUXCAPS; typedef AUXCAPS FAR *LPAUXCAPS; Поля wMid, wPid, vDriverVersion и szPname определены во всех структурах, используемых для определения возможностей устройств мультимедиа. Поле wTechnology специфично для структуры AUXCAPS. В нем могут быть установлены флаги AUXCAPS_AUXIN (имеется звуковой вход от внутреннего устройства проигрывания компакт-дисков) и AUXCAPS_AUXIN (предусмотрен звуковой вход от входной линии, расположенной на плате звукового адаптера). Поле dwSupport может содержать флаги AUXCAPS_VOLUME (есть возможность регулировки громкости) и AUXCAPS_LRVOLUME (есть возможность раздельной регулировки громкости для левого и правого канала). Структура MIDIINCAPS содержит только те поля, которые являются общими для всех структур, предназначенных для определения возможностей устройств мультимедиа typedef struct midiincaps_tag { UINT wMid; UINT wPid; VERSION vDriverVersion; char szPname[MAXPNAMELEN]; } MIDIINCAPS; typedef MIDIINCAPS *PMIDIINCAPS; typedef MIDIINCAPS NEAR *NPMIDIINCAPS; typedef MIDIINCAPS FAR *LPMIDIINCAPS; Структура MIDIOUTCAPS дополнительно содержит поля wTechnology (тип устройства), wVoices (количество голосов для встроенного синтезатора), wChannelMask (количество каналов для встроенного синтезатора) и dwSupport (поддерживаемые функции) typedef struct midioutcaps_tag { UINT wMid; UINT wPid; VERSION vDriverVersion; char szPname[MAXPNAMELEN]; UINT wTechnology; UINT wVoices; UINT Notes; UINT wChannelMask; DWORD dwSupport; } MIDIOUTCAS; typedef MIDIOUTCAPS *PMIDIOUTCAPS; typedef MIDIOUTCAPS NEAR *NMIDIOUTCAPS: typedef MIDIOUTCAPS FAR *LPMIDIOUTCAPS; В поле wTechnology могут находиться значения MOD_MIDIPORT (устройство является аппаратным портом MIDI), MOD_SQSYNTH (устройство является синтезатором с выходным сигналом прямоугольной формы), MOD_FMSYNTH (FM-синтезатор - т.е. синтезатор с частотной модуляцией) и MOD_MAPPER (устройство отображения Microsoft MIDI Mapper). Структура WAVEINCAPS предназначена для определения возможностей устройств ввода звуковых сигналов с использованием импульсно-кодовой модуляции typedef struct waveincaps_tag { UINT wMid; UINT wPid; VERSION vDriverVersion; char szPname[MAXPNAMELEN]; UINT wFormats; UINT wChannels; } WAVEINCAPS; typedef WAVEINCAPS *PWAVEINCAPS; typedef WAVEINCAPS NEAR *NPWAVEINCAPS; typedef WAVEINCAPS FAR *LPWAVEINCAPS; В поле wChannels содержится количество каналов (1 для моно и 2 для стерео). В поле dwFormats могут располагаться флаги, соответствующие стандартным форматам звуковых данных, поддерживаемых данным устройством. Флаги объединяются при помощи логической операции ИЛИ, для них в файле mmsystem.h определены нижеследующие символические константы Константа Частота дискретизации, количество каналов (моно, стерео) и количество бит для представления сигнала WAVE_FORMAT_1M08 11,025 kГц, моно, 8 бит WAVE_FORMAT_1S08 11,025 kГц, стерео, 8 бит WAVE_FORMAT_1M16 11,025 kГц, моно, 16 бит WAVE_FORMAT_1S16 11,025 kГц, стерео, 16 бит WAVE_FORMAT_2M08 22,5 kГц, моно, 8 бит WAVE_FORMAT_2S08 22,5 kГц, стерео, 8 бит WAVE_FORMAT_2M16 22,5 kГц, моно, 16 бит WAVE_FORMAT_2S16 22,5 kГц, стерео, 16 бит WAVE_FORMAT_4M08 44,1 kГц, моно, 8 бит WAVE_FORMAT_4S08 44,1 kГц, стерео, 8 бит WAVE_FORMAT_4M16 44,1 kГц, моно, 16 бит WAVE_FORMAT_4S16 44,1 kГц, стерео, 16 бит Структура WAVEOUTCAPS предназначена для определения возможностей устройств вывода звуковых сигналов с использованием импульсно-кодовой модуляции typedef struct waveoutcaps_tag { UINT wMid; UINT wPid; VERSION vDriverVersion; char szPname[MAXPNAMELEN]; UINT wFormats; UINT wChannels; DWORD dwSupport; } WAVEOUTCAPS; typedef WAVEOUTCAPS *PWAVEOUTCAPS; typedef WAVEOUTCAPS NEAR *NPWAVEOUTCAPS; typedef WAVEOUTCAPS FAR *LPWAVEOUTCAPS; Поле dwSupport содержит флаги, соответствующие различным возможностям вывода, символические константы для них определены в файле mmsystem.h и представлены ниже Константа Описание WAVECAPS_PITCH Поддерживается изменение высоты тона WAVECAPS_PLAYBACKRATE Изменение скорости проигрывания WAVECAPS_VOLUME Управление громкостью WAVECAPS_LRVOLUME Раздельное управление громкостью для левого и правого каналов WAVECAPS_SYNC Драйвер устройства вывода работает в синхронном режиме (во время проигрывания работа приложения приостанавливается) В работе [6] приведен полный С-код приложения DRVLIST, служащего для исследования установленных в системе конфигурации драйверов устройств мультимедиа. 3.6.4. Воспроизведение звука Для воспроизведения звуковых файлов на низком уровне после определения возможностей устройства вывода необходимо открыть устройство, это удобно сделать с помощью функции waveOutOpen. UINT waveOutOpen(LPHWAVEOUT lphWaveOut, UINT wDeviceID, LPWAVEFORMAT lpFormat, DWORD dwCallbackInstance, DWORD dwFlags); Здесь lphWaveOut - дальний указатель на переменную типа HWAVEOUT. В эту переменную будет записан идентификатор устройства вывода, который необходим для выполнения всех операций с устройством. Функция waveOutOpen также может быть использована для определения возможности воспроизведения звуковых данных заданного формата (в том числе нестандартного), в этом случае параметр lphWaveOut может иметь значение NULL, дополнительно в параметре dwFlags следует установить флаг WAVE_FORMAT_QUERY. Через параметр wDeviceID приложение должно передать функции waveOutOpen номер устройства вывода, которое оно собирается открыть или константу WAVE_MAPPER, определенную в файле mmsystem.h. В первом случае номер устройства может лежать в пределах от нуля до полученного с помощью функции waveOutGetNumDevs значения. Обычно используется константа WAVE_MAPPER, при этом функция waveOut-Open пытается самостоятельно выбрать и открыть устройство вывода, подходящее для проигрывания звуковых данных указанного формата. Через параметр lpFormat приложение должно передать функции waveOutOpen адрес заполненной структуры WAVEFORMAT (эта структура и указатели на нее описаны выше). Параметр dwCallback передает функции waveOutOpen адрес функции обратного вызова. Эту функцию будет вызывать драйвер устройства вывода при возникновении событий, имеющих отношение к проигрыванию блока данных. При использовании функции обратного вызова в параметре dwFlags следует установить флаг CALLBACK_FUNCTION. При использовании функции обратного вызова могут возникнуть проблемы, связанные с имеющимися ограничениями на функционирование подобных функций; поэтому с целью извещения приложения о возникновении события заключается в посылке сообщений оконной функции. Для этого параметр dwCallback должен содержать идентификатор окна, а в параметре dwFlags необходимо установить флаг CALLBACK_WINDOW. Параметр dwCallbackInstance является идентификатором данных, передаваемым функции обратного вызова (этот параметр не используется совместно с флагом CALLBACK_WINDOW). В поле dwFlags можно указывать следующие флаги Идентификатор флага Описание WAVE_FORMAT_QUERY Функция waveOutOpen вызывается только с целью проверки возможности использования формата звуковых данных, определенных в структуре WAVEFPRMAT, адрес которой передается через параметр lpFormat. Этим способом можно проверить, способно ли данное устройство работать с нестандартной частотой дискретизации WAVE_ALLOWSYNC Флаг необходимо использовать для открытия синхронного устройства вывода, во время работы которого все приложения блокируются CALLBACK_WINDOW Для извещения о наступлении событий используется окно, идентификатор которого передается через параметр dwCallback CALLBACK_FUNCTION Для извещения о наступлении событий используется функция обратного вызова, адрес которой передается через параметр dwCallback При нормальном завершении функция waveOutOpen возвращает нулевое значение, в противном случае - описанный в нижележащей таблице код ошибки Код ошибки Описание ошибки MMSYSERR_BADDEVICEID Указан неправильный номер устройства вывода MMSYSERR_ALLOCATED Это устройство уже открыто MMSYSERR_NOMEM Для выполнения операции недостаточно памяти WAVEERR_BADFORMAT Указанный формат звуковых данных не поддерживается драйвером устройства вывода WAVEERR_SYNC Была выполнена попытка открыть синхронное устройство вывода без использования флага WAVE_ALLOWSYNC Обычно при проигрывании WAV-файлов приложение вызывает функцию waveOutOpen дважды. Первый раз она вызывается для проверки возможности проигрывания звуковых данных заданного формата if (waveOutOpen(NULL, WAVE_MAPPER, (WAVEFORMAT FAR *) lpwiocb->lpFmt, NULL, 0L, WAVE_FORMAT_QUERY | WAVE_ALLOWSYNC)) { // сообщение о том, что воспроизведение невозможно } Если указанный формат поддерживается драйвером, приложение может открыть устройство вывода, например, следующим образом rc=waveOutOpen(&hWaveOut, WAVE_MAPERR, (WAVEFORMAT FAR *) lpwiocb->lpFmt, (UINT) hwnd, 0L, CALLBACK_WINDOW | WAVE_ALLOWSYNC); Указанная методика позволяет определить возможность работы с нестандартными форматами. После открытия устройства можно приступать собственно к проигрыванию WAV-файла или звуковых данных; для чего необходимо подготовить и передать драйверу устройства вывода блоки данных, содержащие звуковую информацию (формат этих данных должен соответствовать указанному при открытии устройства). Блоки данных, передаваемые драйверу, должны быть заказаны у системы как глобальные с флагами GMEM_MOVEABLE и GMEM_SHARE. Перед передачей блока драйверу необходимо его подготовить при помощи функции waveOutPrepareHeader UINT waveOutPrepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT wSize); Здесь hWaveOut - полученный ранее от функции waveOutOpen идентификатор устройства вывода, lpWaveOutHdr - адрес описывающей передаваемый блок данных заполненной структуры WAVEHDR; описание данной структуры приведено ниже typedef struct wavehdr_tag { LPSTR lpData; // адрес блока данных DWORD dwBufferLength; // размер блока данных DWORD dwBytesRecorded; // количество записанных байт // (только при записи) DWORD dwUser; // пользовательские данные DWORD dwFlags; // флаги состояния буфера данных DWORD dwLoops; // кратность проигрывания файла // (только при воспроизведении) struct wavehdr_tag far *lpNext; // зарезервировано DWORD reserved; // зарезервировано (не используется) } WAVEHDR; typedef WAVEHDR *PWAVEHDR; typedef WAVEHDR NEAR *NPWAVEHDR; typedef WAVEHDR FAR *LPWAVEHDR; После заказа блока памяти функцией GlobalAlloc с флагами GMEM_MOVEABLE и GMEM_SHARE необходимо зафиксировать его функцией GlobalLock; полученный в результате фиксирования адрес блока записывается в поле lpData структуры WAVEHDR, а размер блока - в поле dwBufferLength. Теоретически размер блока памяти для воспроизводимых данных может иметь очень большой размер (определяется двойным словом), однако существует практическое ограничение на размер блока памяти - он должен помещаться целиком в оперативную память (иначе его невозможно зафиксировать). Поэтому в некоторых случаях (при проигрывании очень длинных WAV-файлов) имеет смысл создать два или более блоков, попеременно заполняя их из файла с аудиоданными и передавая драйверу для проигрывания в асинхронном режиме. Структура WAVEHDR используется не только для воспроизведения, но и для записи; в этом случае после завершения записи блока в поле dwBytesRecorded будет находиться количество записанных байт данных (при воспроизведении это поле не используется). Через поле dwUser приложение может передать функции обратного вызова или обработчику сообщения для данного устройства любую дополнительную информацию. Поле dwFlag после прихода сообщения о событии или передачи управления функции обратного вызова будет содержать информацию о состоянии блока; в этом случае могут быть установлены следующие флаги Идентификатор флага Описание WHDR_DONE Работа с буфером данных закончена; данные из буфера были успешно проиграны или записаны, после чего драйвер вернул буфер приложению WHDR_BEGINLOOP Данный буфер является первым в цикле (флаг используется только при воспроизведении). При желании проиграть в цикле только один блок он должен быть отмечен и флагом WHDR_BEGINLOOP и флагом WHDR_ENDLOOP WHDR_PREPARED Буфер подготовлен для воспроизведения функцией waveOutPrepareHeader или для записи функцией waveInPrepareHeader Приложение может указать драйверу, что блок необходимо проиграть несколько раз подряд, для этого следует указать число повторов в поле dwLoops. При нормальном завершении функция waveOutPrepareHeader возвращает нуль, в противном случае указанный в таблице код ошибки. Код ошибки Описание ошибки MMSYSERR_INVALHANDLE Указан неправильный идентификатор устройства MMSYSERR_NOMEM Недостаток памяти для выполнения операции После обработки блока памяти функцией waveOutPrepareHeader его можно проиграть с помощью вызова функции waveOutWrite. UINT waveOutWrite(HWAVEOUT hWaveOut, // идентификатор устройства LPWAVEHDR lpWaveOutHdr, // указатель на ст-ру WAVEHDR UINT wSize); // размер структуры WAVEHDR При нормальном завершении функция waveOutWrite возвращает нуль, в противном случае нижеуказанный код ошибки Код ошибки Описание ошибки MMSYSERR_INVALHANDLE Указан неправильный идентификатор устройства MMSYSERR_UNPREPARED Переданный блок функции не был подготовлен функцией waveOutPrepareHeader Реально проигрывание блока начинается после вызова функции waveOutWrite, в случае проигрывания блока до конца или остановки проигрывания определенная указанным при открытии устройства через параметр dwCallback идентификатором оконная функция получит сообщение MM_WOM_DONE. После получения приложением сообщения MM_WOM_DONE оно должно передать блок функции waveOutUnprepareHeader, затем разблокировать его функцией GlobalUnlock и освободить (если этот блок памяти больше не нужен) функцией GlobalFree. Формат вызова функции waveOutUnprepareHeader приведен ниже UINT waveOutUnprepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT wSize); При нормальном завершении функция waveOutUnprepareHeader возвращает нуль, в противном случае нижеуказанный код ошибки Код ошибки Описание ошибки MMSYSERR_INVALHANDLE Указан неправильный идентификатор устройства MMSYSERR_STILLPLAYING Указанный блок все еще находится в очереди для проигрывания После завершения работы с устройством его необходимо закрыть, вызвав функцию waveOutClose UINT waveOutClose(HWAVEOUT hWaveOut); // идентификатор устройства При нормальном завершении функция waveOutClose возвращает нуль, в противном случае нижеуказанный код ошибки Код ошибки Описание ошибки MMSYSERR_INVALHANDLE Указан неправильный идентификатор устройства MMSYSERR_STILLPLAYING Очередь данного устройства еще содержит блоки для проигрывания 3.6.5.Запись звука Процесс записи имеет много общего с процессом воспроизведения. В начале необходимо открыть устройство записи, вызвав функцию waveInOpen UINT waveInOpen(LPHWAVEIN lpWaveIn, UINT wDeviceID, LPWAVEFORMAT lpFormat, DWORD dwCallback, DWORD dwFlags); Здесь lpWaveOut - дальний указатель на переменную типа HWAVEIN. В эту переменную будет записан идентификатор устройства вывода, который необходим для выполнения всех операций с устройством. Функция waveInOpen может быть использована для определения возможностей записи звуковых данных в заданном формате (возможно, нестандартном), в этом случае параметр lphWaveIn может иметь значение NULL (дополнительно в параметре dwFlags следует установить флаг WAVE_FORMAT_QUERY). Через параметр wDeviceID приложение должно передать функции waveInOpen номер устройства ввода, которое оно собирается открыть или константу WAVE_MAPERR (в первом случае номер устройства может лежать от нуля до полученного с помощью функции waveInGetNumDevs, во втором случае функция waveInOpen пытается самостоятельно выбрать и открыть подходящее для записи звуковых данных указанного формата устройство вывода). При нормальном завершении функция waveInOpen возвращает нуль, в противном случае - нижеприведенный код ошибки Код ошибки Описание ошибки MMSYSERR_NODRIVER В системе нет нужного для работы с устройством ввода драйвера MMSYSERR_BADDEVICEID Указан неправильный номер устройства MMSYSERR_ALLOCATED Это устройство уже открыто MMSYSERR_NOMEM Для выполнения операции недостаточно памяти MMSYSERR_BADFORMAT Указанный формат звуковых данных не поддерживается драйвером устройства MMSYSERR_SYNC Попытка открыть синхронное устройство ввода без использования флага WAVE_ALLOWSYNC После открытия устройства необходимо подготовить один или несколько блоков памяти, в которые будет записана введенная звуковая информация (требования к блокам памяти при этом такие же, как и при воспроизведении). Перед передачей блока драйверу его необходимо подготовить функцией waveInPrepareHeader, входные параметры и коды ошибок которой практически повторяют таковые функции waveOutPrepareHeader UINT waveInPrepareHeader(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr, UINT wSize); Подготовленный таким образом блок памяти передается драйверу устройства ввода функцией waveInAddBuffer UINT waveInAddBuffer(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr, UINT wSize); При нормальном завершении функция waveInAddBuffer возвращает нуль, в противном случае - нижеприведенный код ошибки Код ошибки Описание ошибки MMSYSERR_INVALHANDLE Указан неправильный идентификатор устройства MMSYSERR_UNPREPARED Переданный блок данных не был подготовлен функцией waveInPrepareHeader Для реального начала записи необходимо вызвать функцию waveInStart UINT waveInStart(HWAVEIN hWaveIn); В качестве входного параметра передается полученный ранее от функции waveInOpen идентификатор вводного устройства. При нормальном завершении функция возвращает нуль, иначе - код MMSYSERR_INVALHANDLE, означающий указание неправильного идентификатора устройства. Запись будет производиться до тех пор, пока не будет записан весь буфер или пока устройство ввода не будет остановлено функцией waveInStop UINT waveInStop(HWAVEIN hWaveIn); При нормальном завершении функция waveInStop возвращает нуль, иначе - код MMSYSERR_INVALHANDLE, означающий указание неправильного идентификатора устройства. При записи блока до конца или при принудительной остановке записи вызывается оконная функция (как в случае функции waveOutWrite). Вызовы waveUnprepareHeader, GlobalUnlock, GlobalFree и waveInClose синтаксически подобны описанным выше. 3.6.6. Дополнительные функции низкого уровня Библиотека mmsystem.dll содержит несколько весьма полезных функций, предназначенных для работы со звуком на низком уровне. Функции waveInGetErrorText и waveOutGetErrorText (подобно функции mciGetErrorString) преобразуют код ошибки в текстовое описание ее в виде строки символов. Функции waveInGetID и waveInGetID позволяют определить реальный номер устройства, выбранного функцией открытия устройства ввода/вывода с указанием константы WAVE_MAPPER (режим автоматического поиска подходящего из установленных в системе устройств). Функции waveInReset и waveOutReset выполняют останов устройств ввода или вывода соответственно и сброс текущей позиции для устройства в нуль. Для запуска устройства ввода используется ранее рассмотренная функция waveInStart, для продолжения работы ранее приостановленного устройства вывода используется функция waveOutRestart. Останов устройства ввода используется ранее описанная функция waveInStop, временный останов работы устройства вывода следует воспользоваться функцией waveOutPause. Определение текущей позиции в блоке при записи и воспроизведении производится функциями waveInGetPosition и waveOutGetPosition соответственно (при этом используется структура MMTIME, описанная в файле mmsystem.h) typedef struct mmtime_tag { UINT wType; // формат времени union { DWORD ms; // миллисекунды DWORD sample; // выборки сигнала DWORD cb; // счетчик байт struct // формат SMPTE { BYTE hour; // часы BYTE min; // минуты BYTE sec; // секунды BYTE frame; // фреймы BYTE fps; // фреймы в секунду BYTE dummy; // байт для выравнивания } smpte; struct // формат MIDI { DWORD songptpos; // указатель позиции в мелодии } MIDI; } u; } MMTIME; typedef MMTIME *PMMTIME; typedef MMTIME NEAR *NPMMTIME; typedef MMTIME FAR *LPMMTIME; Для установки громкости следует использовать функцию waveOutSetVolume, прочитать текущее значение громкости можно функцией waveOutGetVolume. В работе [6] приведен полный С-код приложения WAVE, служащего для записи и воспроизведения WAV-файлов. 3.7. Управление устройством CD-ROM Как было сказано, данные на компакт-диске записаны вдоль одной спирали; в первом приближении можно считать, что на музыкальных дисках эта спираль (логически) разбита на несколько участков (дорожек), каждая из которых содержит отдельную запись (например, музыкальное произведение). Приложение имеет возможность устанавливать лазерное устройство чтения в произвольное место спирали, причем драйвер обеспечивает позиционирование в режиме прямого доступа как на начало любой дорожки, так и в произвольную позицию внутри дорожки (позиционирование может занимать до 0,5 сек). Устройство чтения CD-ROM имеет два звуковых выхода. Один из них обычно расположен на лицевой панели и предназначен для подключения головных телефонов (там же находится регулятор громкости), второй выведен на заднюю панель и подключается кабелем к входу звукового адаптера. Приложения мультимедиа поэтому могут выполнять не только проигрывание звуковых компакт-дисков, но и синхронную запись WAV-файлов. Работа с устройством CD-ROM возможна при помощи интерфейса управляющих строк MCI или интерфейса управляющих сообщений MCI. 4.7.1. Интерфейс управляющих строк MCI Для передачи управляющей строки устройству чтения CD-ROM необходимо использовать функцию mciSendString (подробнее см. подраздел 2.4). Перед началом работы с устройством необходимо его открыть, передав управляющую строку open, указав при этом имя устройства как cdaudio (допускается использование алиаса - альтернативного имени) open cdaudio alias cd wait Операция открытия устройства CD-ROM может выполняться несколько секунд, поэтому целесообразно перед продолжением работы приложения дождаться ее завершения, указав параметр wait. С целью достижения возможности использования данного устройства несколькими приложениями одновременно можно указать параметр shareable (этот параметр должны указать все приложения, желающие иметь одновременный доступ к устройству). Так как драйвер устройства CD-ROM не работает с файлами, путь к конкретному файлу в управляющей строке open не указывается. Команда close служит для закрытия устройства, особенностей не имеет, в качестве параметра необходимо указать имя устройства cdaudo (или алиас, если устройство было открыто с использованием альтернативного имени) close cd Справочные команды. Команда sysinfo требует один параметр - строку cdaudio (даже если при открытии был использован алиас); для команды info можно указывать только параметр product. Команда capability с параметром can eject позволяет определить, имеет ли устройство CD-ROM возможность автоматического извлечения компакт-дисков. Можно использовать иные параметры (с целью определения соответствующих возможностей устройства) - can play, can record, can save, compound device, device type, has audio, has video, uses file. Для определения текущего состояния CD-ROM следует использовать команду status, можно указывать следующие параметры Параметр команды status Что определяется current track Номер текущей дорожки length Общая длина length track track_number Длина заданной дорожки media present При наличии в устройстве вставленного компакт-диска возвращается строка true mode Текущий режим работы - not ready (не готов), playing (проигрывание), stopped (останов), recording (запись), seeking (позиционирование) number of track Количество дорожек position Текущая позиция position track track_number Текущая позиция на заданной дорожке ready При готовности устройства возвращается строка true start position Начальная позиция time formar Текущий формат времени Команды установки режимов работы. Команда break позволяет определить код виртуальной клавиши, предназначенный для прерывания процесса выполнения текущей команды (по умолчанию используется комбинация клавиш <Control+Break>). Для команды set можно указывать следующие параметры Параметр команды set Действие audio all off Отключение звукового выхода audio all on Включение звукового выхода audio left off Отключение левого канала audio left on Включение левого канала audio right off Отключение правого канала audio right on Включение правого канала door closed Загрузка компакт-диска и фиксирование его в устройстве (поддерживается не всеми устройствами) door open Извлечение компакт-диска (поддерживается не всеми устройствами) time format miiliseconds В качестве единицы измерения при позиционировании используются миллисекунды (вместо miiliseconds можно использовать ms) time format msf В качестве единицы измерения при позиционировании используются минуты, секунды и фреймы (разделитель - двоеточие); этот формат используется по умолчанию time format tmsf В качестве единицы измерения при позиционировании используются дорожки, минуты, секунды и фреймы Команды для воспроизведения, записи и позиционирования. Команда play предназначена для запуска проигрывания и имеет следующий формат (необязательные параметры отмечены квадратными скобками) play device_id [from position [to position]] [notify] [wait] Здесь и далее device_id - идентификатор устройства, использованный при открытии устройства командой open (например, если устройство было открыто командой open c:\windows\ding.wav alias ding, то в качестве параметра device_id можно использовать алиас ding) . Если не указан параметр from position, проигрывание начинается с текущей позиции (сразу после открытия текущая позиция устанавливается в начало первой дорожки); параметр to position позволяет указать конечную позицию, при достижении которой проигрывание прекращается (перед использованием параметров from ... и to ... необходимо установить формат для позиционирования при помощи команды set). В нижеследующем примере выполняется проигрывание 10-й дорожки звукового компакт-диска open cdaudio alias cd wait set cd time format tmsf wait play cd from 10 to 11 wait close cd Нижеследующая команда проигрывает фрагмент 12-й дорожки, начало которого отстоит на 10 сек от начала дорожки, а длительность составляет 16 сек play cd from 12:0:10 to 12:0:16 wait Останов проигрывания реализуется командой stop, единственным параметром которой является идентификатор устройства device_id. Команда pause device_id для устройства чтения CD-ROM работает как команда полного останова stop, при этом команда продолжения работы после останова resume не поддерживается. Позиционирование с последующим остановом реализуется командой seek (перед использованием этой команды необходимо задать формат времени командой set time format) seek device_id parameter [notify] [wait] Параметр parameter является необязательным и может принимать значение одной из нижеуказанных строк Значение parameter Описание to position Позиционирование в заданное место компакт-диска to start Позиционирование в начало to end Позиционирование в конец 3.7.2. Интерфейс управляющих сообщений MCI Большинство разработанных с использованием языка C/C++ приложений используют для управления устройством CD-ROM интерфейс управляющих сообщений MCI (напомним, что управляющие сообщения при этом посылаются устройствам с помощью функции mciSendCommand, см. подраздел 2.5). Команда MCI_OPEN открывает устройство, предварительно необходимо подготовить структуру MCI_OPEN_PARMS и передать ее адрес через четвертый параметр функции mciSendCommand. Поле lpstrDeviceType структуры MCI_OPEN_PARMS содержит указатель на строку имени устройства или его идентификатор. Для устройства чтения CD-ROM можно указывать имя "cdaudio" или константу MCI_DEVTYPE_CD_AUDIO. Параметр lpstrElementName не используется, так как устройство чтения компакт-дисков не работает с файлами. Приведенный ниже фрагмент кода открывает устройство чтения компакт-дисков MCIOpen.lpstrDeviceType=(LPSTR) MCI_DEVTYPE_CD_AUDIO; dwrc=maciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD) (LPVOID) &MCIOpen); После выполнения этого фрагмента кода в переменную dwrc будет записан код результата выполнения, при успешном выполнении в поле wDeviceID структуры mciOpen будет находиться идентификатор открытого устройства. Команда MCI_CLOSE закрывает устройство, MCI_PLAY запускает проигрывание, MCI_STOP останавливает выполнение проигрывания компакт-диска, MCI_PAUSE действует аналогично MCI_STOP, MCI_SEEK выполняет позиционирование, MCI_BREAK устанавливает виртуальный код клавиши прерывания операции (по умолчанию <Control+Break>). С помощью команды MCI_GETDEVCAPS можно определить возможности устройства чтения компакт-дисков. Для этого используется блок параметров в формате нижеописанной структуры MCI_GETDEVCAPS_PARMS typedef struct tagMACI_GETDEVCAPS_PARMS { DWORD dwCallback; DWORD dwReturn; DWORD dwItem; } MCI_GETDEVCAPS_PARMS; typedef MCI_GETDEVCAPS_PARMS FAR \ *LPMCI_GETDEVCAPS_PARMS; В поле dwReturn после возврата из функции mciSendCommand будет записано значение требуемого параметра (код нужного параметра следует записать в поле dwItem перед вызовом функции mciSendCommand) Значение параметра dwItem Описание MCI_GETDEVCAPS_CAN_EJECT Если устройство может выталкивать компакт-диск, после возврата из функции mciSendCommand в поле dwReturn будет ненулевое значение TRUE MCI_GETDEVCAPS_CAN_PLAY Устройство может проигрывать MCI_GETDEVCAPS_CAN_RECORD Устройство может записывать MCI_GETDEVCAPS_CAN_SAVE Устройство может сохранять записанные данные в файле MCI_GETDEVCAPS_COMPOUND_ DEVICE Устройство может работать с файлами MCI_GETDEVCAPS_DEVICE_TYPE Требуется определить тип устройства MCI_GETDEVCAPS_HAS_AUDIO Устройство имеет звуковой выход MCI_GETDEVCAPS_HAS_VIDEO Устройство имеет видеовыход MCI_GETDEVCAPS_USES_FILES При открытии устройства требуется указывать имя файла Команда MCI_INFO дает возможность получить информацию об устройстве чтения CD-ROM в виде текстовой строки, при этом используется блок параметров в виде структуры MCI_INFO_PARMS typedef struct tagMCI_INFO_PARMS { DWORD dwCallback; LPSTR lpstrReturn; DWORD dwRetSize; } MCI_INFO_PARMS; typedef MCI_INFO_PARMS FAR *LPMCI_INFO_PARMS; Поле lpstrReturn должно содержать указатель на буфер, в который будет записана строка информации, размер этого буфера следует передать через поле dwRetSize. Ниже приведен набор флагов для команды MCI_INFO, допустимых к использованию при работе с устройством чтения компакт-дисков Идентификатор флага Описание MCI_NOTIFY Если установлен этот флаг, после завершения команды оконной функции, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIF MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса MCI_INFO_PRODUCT Требуется получить описание аппаратуры устройства Команда MCI_SYSINFO позволяет получить системную информацию об устройстве в виде текстовой строки, команда MCI_STATUS используется для определения текущего состояния устройства (формат соответствующего блока параметров описывается структурой MCI_STATUS_PARMS) typedef struct tagMCI_STATUS_PARMS { DWORD dwCallback; DWORD dwReturn; DWORD dwItem; DWORD dwTrack; } MCI_STATUS_PARMS; typedef MCI_STATUS_PARMS FAR *LPMCI_STATUS_PARMS; Через поле dwReturn передается возвращаемая информация, вид запрашиваемой информации определяется содержимым поля dwItem. Для устройства чтения компакт-дисков в поле dwTrack можно указать размер или номер дорожки (ниже приведены возможные значения параметра dwItem) Значение параметра dwItem Описание получаемой информации MCI_STATUS_CURRENT_ TRACK Номер текущей дорожки MCI_STATUS_LENGTH Общий размер всех дорожек компакт-диска MCI_STATUS_NUMBER_ OF_TRACKS Общее количество дорожек, которые можно проиграть MCI_STATUS_POSITION Текущая позиция MCI_STATUS_READY При готовности устройства возвращается TRUE, иначе - FALSE MCI_STATUS_MODE Текущий режим устройства; может иметь следующие значения - MCI_MODE_NOT_READY (не готово), MCI_MODE_PAUSE (пауза), MCI_MODE_PLAY (проигрывание), MCI_MODE_STOP (останов), MCI_MODE_OPEN (открывание), MCI_MODE_RECORD (запись), MCI_MODE_SEEK (позиционирование) MCI_STATUS_TIME_ FORMAT Текущий формат времени; может иметь следующие значения - MCI_FORMAT_MILLISECONDS, MCI_FORMAT_MSF, MCI_FORMAT_TMSF MCI_STATUS_START Начальная позиция MCI_STATUS_TRACK В поле dwTrack записывается либо начальная позиция заданной дорожки (если дополнительно используется MCI_STATUS_POSITION), либо размер дорожки (если дополнительно используется MCI_STSTUS_LENGTH) MCI_STATUS_MEDIA_ PRESENT Если компакт-диск вставлен в устройство, возвращается TRUE Команда MCI_SET предназначена для установки режима работы устройства, совместно с ней используется блок параметров в формате структуры MCI_SET_PARMS typedef struct tagMCI_SET_PARMS { DWORD dwCallback; DWORD dwTimeFormat; DWORD dwAudio; } MCI_SET_PARMS; typedef MCI_SET_PARMS FAR *LPMCI_SET_PARMS; Поле dwTimeFormat определяет формат времени для устройства, поле dwAudio задает выходной канал. Совместно с командой MCI_SET используются следующие флаги Идентификатор флага Описание MCI_NOTIFY При установке этого флага после завершения команды оконной функции, адрес которой передан через поле dwCallback, будет послано сообщение MM_MCINOTIFY MCI_WAIT Функция mciSendCommand вернет управление только после завершения процесса MCI_SET_AUDIO Включение или выключение каналов; используется вместе с флагами MCI_SET_ON и MCI_SET_OFF. Поле dwAudio содержит номера канала, дополнительно можно указать следующие константы - MCI_SET_AUDIO_ALL (все каналы), MCI_SET_AUDIO_LEFT (левый канал), MCI_SET_AUDIO_RIGHT (правый канал) MCI_SET_DOOR_CLOSED Команда защелкивания компакт-диска устройством MCI_SET_DOOR_OPEN Освобождение носителя данных MCI_SET_VIDEO Включение или выключение видеосигнала, используется вместе с флагами MCI_SET_ON и MCI_SET_OFF MCI_SET_TIME_FORMAT Устанавливает формат времени, используется совместно со следующими константами - MCI_FORMAT_MSF (минуты, секунды, фреймы), MCI_FORMAT_MILLSECONDS (миллисекунды), MCI_FORMAT_TMSF (треки, минуты, секунды, фреймы) MCI_SET_ON Включение заданного канала MCI_SET_OFF Выключение заданного канала При использовании формата времени MCI_FORMAT_MSF старший байт старшего слова поля dwTimeFormat не используется, а младший содержит номер фрейма. Старший байт младшего слова содержит секунды, младший - минуты. Формат времени MCI_FORMAT_TMSF аналогичен вышеприведенному за исключением того, что старший байт старшего слова содержит номер дорожки. В работе [6] приведен полный С-код приложения MCICDPL, служащего для управления устройством чтения CD-ROM при помощи управляющих сообщений MCI. 3.8. Проигрывание MIDI-файлов Файлы в стандарте MIDI (Musical Instrument Digital Interface, был разработан в 1982 г.) имеют расширения MID и содержат заголовок и информацию для музыкального синтезатора; используется также стандарт RIFF (содержащие сообщения MIDI и соответствующие стандарту RIFF файлы имеют обычно расширения RMI). MIDI-файлы создаются с помощью музыкальной клавиатуры и соответствующего программного обеспечения (и, разумеется, некоторых музыкальных способностей). При воспроизведении MIDI-файлов могут возникнуть трудности, связанные с тем, что не все синтезаторы имеют одинаковое распределение каналов и инструментов; поэтому рекомендуется воспроизводить в среде Windows только авторизованные для этой ОС файлы MIDI-формата (при отсутствии авторизации Windows выдает предупреждающее сообщение). 3.8.1. Интерфейс управляющих строк MCI Для работы с входящим в комплект звукового адаптера музыкальным синтезатором используется драйвер mciseq.drv (название суть производная от слова sequencer - ‘устройство задания последовательности’ - именно так в терминологии мультимедиа называется предназначенное для работы с файлами в стандарте MIDI устройство). При работе с MID-файлами на уровне управляющих строк MCI допустимо пользоваться практически всеми командами, рассмотренными ранее в подразделе 2.7.1; не поддерживаются команды resume, record и save. Например, следующая последовательность команд выполнит проигрывание файла canion.mid, входящего в состав дистрибутива ОС Windows open c:\windows\canyon.mid alias music wait play music wait close music Драйвер mciseq.drv не поддерживает следующие параметры команды set - audio all off, audio all on, audio left on, audio left off, audio right on, audio right off. Дополнитель
|