Обратите внимание на то, что
WAVE_FORMAT_1M08
|
11.025 kHz, mono, 8-bit
|
WAVE_FORMAT_1M16
|
11.025 kHz, mono, 16-bit |
WAVE_FORMAT_1S08
|
11.025 kHz, stereo, 8-bit |
WAVE_FORMAT_1S16
|
11.025 kHz, stereo, 16-bit |
WAVE_FORMAT_2M08
|
22.05 kHz, mono, 8-bit |
WAVE_FORMAT_2M16
|
22.05 kHz, mono, 16-bit |
WAVE_FORMAT_2S08
|
22.05 kHz, stereo, 8-bit |
WAVE_FORMAT_2S16
|
22.05 kHz, stereo, 16-bit |
WAVE_FORMAT_4M08
|
44.1 kHz, mono, 8-bit |
WAVE_FORMAT_4M16
|
44.1 kHz, mono, 16-bit |
WAVE_FORMAT_4S08
|
44.1 kHz, stereo, 8-bit |
WAVE_FORMAT_4S16
|
44.1 kHz, stereo, 16-bit |
Обратите внимание на то, что подавляющее большинство (если не все) звуковые карты поддерживают промежуточные режимы записи-воспроизведения. Т.е. вполне возможно на карте с максимальной частотой дискретизации 44100 выборок/сек производить запись со скоростью 16000 выборок/сек, хотя это и не сообщается по запросу waveInGetDevCaps.
wChannels: Word - количество входных каналов (1-моно, 2-стерео)
wReserved1: Word - зарезервировано
Функция
waveInGetErrorText возвращает текстовое описание возникших в ходе выполнения ошибок.
function waveInGetErrorText(
mmrError: MMRESULT;
lpText: PChar;
uSize: UINT
): MMRESULT; stdcall;
mmrError - код ошибки;
lpText - адрес с которого будет размещена нуль-терминированная строка-описание;
uSize - размер участка памяти, на который ссылается lpText;
Ниже приведен пример процедуры, выводящей сведения об устройствах аудиоввода.
uses Windows, MMSystem; type TModeDescr=record mode: DWORD; // код режима работы descr: string[32]; // словесное описание end; const // массив содержит сопоставления режима работы и словесного описания modes: array [1..12] of TModeDescr=((mode: WAVE_FORMAT_1M08; descr:'11.025 kHz, mono, 8-bit'), (mode: WAVE_FORMAT_1M16; descr:'11.025 kHz, mono, 16-bit'), (mode: WAVE_FORMAT_1S08; descr:'11.025 kHz, stereo, 8-bit'), (mode: WAVE_FORMAT_1S16; descr:'11.025 kHz, stereo, 16-bit'), (mode: WAVE_FORMAT_2M08; descr:'22.05 kHz, mono, 8-bit'), (mode: WAVE_FORMAT_2M16; descr:'22.05 kHz, mono, 16-bit'), (mode: WAVE_FORMAT_2S08; descr:'22.05 kHz, stereo, 8-bit'), (mode: WAVE_FORMAT_2S16; descr:'22.05 kHz, stereo, 16-bit'), (mode: WAVE_FORMAT_4M08; descr:'44.1 kHz, mono, 8-bit'), (mode: WAVE_FORMAT_4M16; descr:'44.1 kHz, mono, 16-bit'), (mode: WAVE_FORMAT_4S08; descr:'44.1 kHz, stereo, 8-bit'), (mode: WAVE_FORMAT_4S16; descr:'44.1 kHz, stereo, 16-bit')); procedure ShowInfo; var WaveNums, i, j: integer; WaveInCaps: TWaveInCaps; // структура в которую помещается информация об устройстве begin WaveNums:=waveInGetNumDevs; if WaveNums>0 then // если в системе есть устройства аудиоввода,то begin for i:=0 to WaveNums-1 do // получаем характеристики всех имеющихся устройств begin waveInGetDevCaps(i,@WaveInCaps,sizeof(TWaveInCaps)); // добавляем наименование устройства MainForm.Memo.Lines.Add(PChar(@WaveInCaps.szPname)); for j:=1 to High(modes) do begin // выводим поддерживаемые устройством режимы работы if (modes[j].mode and WaveInCaps.dwFormats)=modes[j].mode then Memo.Lines.Add(modes[j].descr); end; end; end; end; |
Рис 1. Сведения, выводимые процедурой ShowInfo.
Теперь Вы можете определить количество устройств аудиоввода Waveform audio и поддерживаемые ими режимы. Далее рассмотрим еще несколько функций, непосредственно обеспечивающих работу с звуковыми устройствами. Функция
waveInOpen открывает имеющееся устройство ввода Waveform audio для оцифровки сигнала.
function waveInOpen( lphWaveIn: PHWAVEIN;
uDeviceID: UINT;
lpFormatEx: PWaveFormatEx;
dwCallback,
dwInstance,
dwFlags: DWORD
): MMRESULT; stdcall; Здесь
lphWaveIn - указатель на идентификатор открытого Waveform audio устройства. Идентификатор используется после того, как устройство открыто, в других функциях Waveform audio;
uDeviceID - номер открываемого устройства (см.
waveInGetNumDevs). Это может быть также идентификатор уже открытого ранее устройства. Вы можете использовать значение
WAVE_MAPPER для того, чтобы функция автоматически выбрала совместимое с требуемым форматом данных устройство;
lpFormatEx - указатель на структуру типа TWaveFormatEx
type TWaveFormatEx = packed record wFormatTag: Word; { format type }
nChannels: Word; { number of channels (i.e. mono, stereo, etc.) }
nSamplesPerSec: DWORD; { sample rate }
nAvgBytesPerSec: DWORD; { for buffer estimation }
nBlockAlign: Word; { block size of data }
wBitsPerSample: Word; { number of bits per sample of mono data }
cbSize: Word; { the count in bytes of the size of }
end; В этой структуре значения полей следующее:
wFormatTag - формат Waveform audio. Мы будем использовать значение
WAVE_FORMAT_PCM (это означает импульсно-кодовая модуляция) другие возможные значения смотрите в заголовочном файле MMREG.H;
nChannels - количество каналов. Обычно 1 (моно) или 2(стерео);
nSamplesPerSec - частота дискретизации. Для формата PCM - в классическом смысле, т.е. количество выборок в секунду. Согласно теореме отсчетов должна вдвое превышать частоту оцифровываемого сигнала. Обычно находится в диапазоне от 8000 до 44100 выборок в секунду;
nAvgBytesPerSec - средняя скорость передачи данных. Для PCM равна nSamplesPerSec*nBlockAlign;
nBlockAlign - для PCM равен (nChannels*wBitsPerSample)/8;
wBitsPerSample - количество бит в одной выборке. Для PCM равно 8 или 16;
cbSize - равно 0. Подробности в Microsoft Multimedia Programmer's Reference;
dwCallback - адрес callback-функции, идентификатор окна или потока, вызываемого при наступлении события;
dwInstance - пользовательский параметр в callback-механизме. Сам по себе не используется
dwFlags - флаги для открываемого устройства:
CALLBACK_EVENT | dwCallback-параметр - код сообщения (an event handle); |
CALLBACK_FUNCTION | dwCallback-параметр - адрес процедуры-обработчика; |
CALLBACK_NULL | dwCallback-параметр не используется; |
CALLBACK_THREAD | dwCallback-параметр - идентификатор потока команд; | |
CALLBACK_WINDOW | dwCallback-параметр - идентификатор окна; |
WAVE_FORMAT_DIRECT | если указан этот флаг, ACM-драйвер не выполняет преобразование данных; |
WAVE_FORMAT_QUERY | функция запрашивает устройство для определения, поддерживает ли оно указанный формат, но не открывает его; |
В случае использование Callback процедуры она имеет следующий вид:
procedure waveInProc(hwi: HWAVEIN; uMsg,dwInstance, dwParam1,dwParam2: DWORD);stdcall; begin // что-то делаем end; Параметры процедуры имеют следующее значение:
hwi - идентификатор связанного с функцией открытого устройства;
uMsg - Waveform audio сообщение. Может принимать значения:
WIM_CLOSE | посылается, когда устройство закрывается функцией waveInClose; |
WIM_DATA | устройство завершило передачу данных в блок памяти, установленный процедурой waveInAddBuffer; |
WIM_OPEN | сообщение посылается если устройство открыто функцией waveInOpen; |
dwInstance - данные, определенные пользователем при вызове
waveInOpen;
dwParam1, dwParam2 - параметры сообщения.
Необходимо заметить, что в Microsoft Multimedia Programmer's Reference написано, что из callback-процедуры нельзя вызывать никаких системных функций кроме:
EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, и timeSetEvent , поскольку это вызывает deadlock.
Я столкнулся с весьма серьезным препятствием из-за этого ограничения, и решил все-таки рискнуть. В ходе небольших экспериментов я выяснил, что данное ограничение не распространяется на группу
waveInAddBuffer, waveInReset и waveInClose, и возможно, некоторые другие. Не было проблем и с использованием функций Reset, BlockWrite, BlockRead, CloseFile. Говоря более точно, я так и не обнаружил возникновения deadlock, какие бы функции не вызывал изнутри waveInProc. Самое главное - не инициировать бесконечный рекурсивный вызов waveInProc. Для этого необходимо хорошо продумать обработчики поступающих в waveInProc сообщений.
Вообще, рекомендую использовать механизм оконных сообщений вместо callback. Это позволяет избежать ненужных экспериментов и возможной неработоспособности программы в других версиях ОС. Более подробно реализация этого механизма приведена в примере. Функция
waveInPrepareHeader выполняет подготовку буфера для операции загрузки данных:
function waveInPrepareHeader( hWaveIn: HWAVEIN;
lpWaveInHdr: PWaveHdr;
uSize: UINT
): MMRESULT; stdcall; Здесь:
hWaveIn - идентификатор открытого устройства;
lpWaveInHdr - адрес структуры
WaveHdr:
type TWaveHdr = record lpData: PChar; { pointer to locked data buffer }
dwBufferLength: DWORD; { length of data buffer }
dwBytesRecorded: DWORD; { used for input only }
dwUser: DWORD; { for client's use }
dwFlags: DWORD; { assorted flags}
dwLoops: DWORD; { loop control counter }
lpNext: PWaveHdr; { reserved for driver }
reserved: DWORD; { reserved for driver }
end; lpData - адрес буфера для загрузки данных;
dwBufferLength - длина буфера в байтах;
dwBytesRecorded - для режима загрузки данных определяет количество загруженных в буфер байт;
dwUser - пользовательские данные
dwFlags - флаги. Могут иметь следующие значения:
WHDR_DONE | устанавливается драйвером при завершении загрузки буфера данными; |
WHDR_PREPARED | устанавливается системой. Показывает готовность буфера к загрузке данных; |
WHDR_INQUEUE | устанавливается системой когда буфер установлен в очередь; |
dwLoops - используется только при воспроизведении. При записи звука всегда 0;
lpNext - зарезервировано;
reserved - зарезервировано;
uSize - размер структуры WaveHdr в байтах;
Функция waveInPrepareHeader вызывается только один раз для каждого устанавливаемого в очередь загрузки буфера. Существует функция
waveInUnprepareHeader, с такими же параметрами, которая освобождает ресурсы системы по сопровождению выделенного под загрузку блока.
waveInUnprepareHeader должна быть вызвана до удаления выделенного под буфер загрузки блока памяти.
Функция
waveInAddBuffer ставит в очередь на загрузку данными буфер памяти. Когда буфер заполнен, система уведомляет об этом приложение (см. выше waveInOpen).
function waveInAddBuffer( hWaveIn: HWAVEIN;
lpWaveInHdr: PWaveHdr;
uSize: UINT
): MMRESULT; stdcall;
Здесь:
hWaveIn - идентификатор открытого Waveform audio устройства ввода;
lpWaveInHdr - адрес структуры TWaveHdr;
uSize - размер WaveHdr в байтах;
Функция
waveInReset останавливает операцию загрузки данных. Все текущие буферы отмечаются как обработанные и приложение уведомляется о завершении загрузки данных (см. waveInOpen).
function waveInReset( hWaveIn: HWAVEIN ): MMRESULT; stdcall; Здесь:
hWaveIn - идентификатор открытого Waveform audio устройства.
Функция
waveInClose закрывает открытое устройство ввода:
function waveInClose(
hWaveIn: HWAVEIN
): MMRESULT; stdcall;
hWaveIn - идентификатор открытого устройства;
MMRESULT может принимать следующие значения:
MMSYSERR_NOERROR | нет ошибок; |
MMSYSERR_ALLOCATED | указанный ресурс уже выделен; |
MMSYSERR_BADDEVICEID | указанный идентификатор устройства вне диапазона; |
MMSYSERR_NODRIVER | отсутствует драйвер устройства; |
MMSYSERR_NOMEM | невозможно выделить или зафиксировать блок памяти; | |
WAVERR_BADFORMAT | попытка открытия с неподдерживаемым форматом данных; |
MMSYSERR_INVALHANDLE | параметром является недопустимый идентификатор; |
WAVERR_STILLPLAYING | указанный буфер все еще в очереди; |
WAVERR_UNPREPARED | буфер не был подготовлен; |
Пример реализации описанного в статье механизма (Delphi 3) Вы можете скачать
(17.7 K)
Александр Галилов
Содержание Назад Вперед