Программирование звука. Подготавливаемся к записи и воспроизведению:
Сегодня я заканчиваю рассказ о воспроизведении звука и немного затрону запись. Мы уже умеем воспроизводить звук, но только на устройстве установленном по умолчанию. Но у тебя может быть несколько плат и пользователь должен иметь право выбора (демократия всё же на дворе :)). Так что, я думаю, что ты понял о чём пойдёт сегодня речь.
В твоём компе может быть несколько устройств воспроизведения, точно так же, как и устройств записи. Чтобы узнать количество устройств вопроизведения можно воспользоваться функцией waveOutGetNumDevs. Возможности конкретного устройства можно узнать с помощью waveOutGetDevCaps. Это что касается воспроизведения. Для устройств записи существуют такие же функции, которые мы ещё не рассматривали. Сейчас нам это предстоит.
Начнём мы с waveOutGetNumDevs. Она выглядит так:
function waveOutGetNumDevs: UINT; stdcall;
Функция не имеет параметров, а только возвращает количество установленных в системе устройств воспроизведения.
Для получения количества устройств записи используется waveInGetNumDevs:
function waveInGetNumDevs: UINT; stdcall;
Эта функция так же не имеет параметров, а только возвращает количество установленных в системе устройств записи.
Теперь научимся получать инфу об установленных устройствах вопроизведения с помощью waveOutGetDevCaps. Эту функцию мы рассматривали в прошлый раз (когда изучали реальный пример) но сейчас я решил повторится, чтобы напомнить о чём идёт речь.
Для С/С++
MMRESULT waveOutGetDevCaps(
UINT uDeviceID, //Указатель на устройство воспроизведения
LPWAVEOUTCAPS pwoc,//Структура, куда будут записаны данные
UINT cbwoc //Размер структуры
);
Для Delphi
function waveOutGetDevCaps(
uDeviceID: UINT; //Указатель на устройство воспроизведения
lpCaps: PWaveOutCaps; //Структура, куда будут записаны данные
uSize: UINT //Размер структуры
): MMRESULT; stdcall;
Подробное описание смотри в прошлом номере (март 2001). Можешь посмотреть на описание waveInGetDevCaps ниже и всё станет понятно, потому что эти функции очень похожи. А я перехожу к функции, с помощью которой можно получить инфу об устройствах записи звука waveInGetDevCaps:
Для С/С++
MMRESULT waveInGetDevCaps(
UINT uDeviceID, //Указатель на устройство записи
LPWAVEINCAPS pwic, //Структура, куда будут записаны данные
UINT cbwic //Размер структуры
);
Для Delphi
function waveInGetDevCaps(
hwo: HWAVEOUT; //Указатель на устройство записи
lpCaps: PWaveInCaps; //Структура, куда будут записаны данные
uSize: UINT //Размер структуры
): MMRESULT; stdcall;
С первым параметром уже должно быть всё ясно. Второй параметр - структура типа ТWaveInCaps. Она выглядит так:
Для С/С++
typedef struct {
WORD wMid; //Идентификатор производителя
WORD wPid; //Идентификатор устройства
MMVERSION vDriverVersion; //Версия драйвера
CHAR szPname[MAXPNAMELEN]; //Название устройства
DWORD dwFormats; //Поддерживаемые форматы
WORD wChannels; //Количество каналов
WORD wReserved1; //Зарезервировано, но здесь хранятся свойства
} WAVEINCAPS;
Для Delphi
TWaveOutCaps = tagWAVEOUTCAPSA;
tagWAVEOUTCAPSA = record
wMid: Word; //Идентификатор производителя
wPid: Word; //Идентификатор устройства
vDriverVersion: MMVERSION; //Версия драйвера
szPname: array[0..MAXPNAMELEN-1] of AnsiChar; //Название устройства
dwFormats: DWORD; //Поддерживаемые форматы
wChannels: Word; //Количество каналов
dwSupport: DWORD; //Свойства
end;
Параметр Support может принимать значения:
WAVECAPS_LRVOLUME - поддерживается изменение правого и левого каналов.
WAVECAPS_SYNC - драйвер сихронный и будет блокировать работу пока играет музыка.
WAVECAPS_VOLUME - поддержка громкости.
WAVECAPS_SAMPLEACCURATE - возвращает позицию.
Параметр wChannels может быть 1 (для моно) и 2 (для стерео).
Параметр dwFormats может быть комбинацией следующих значений:
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
Вот и все функции, которые я хотел тебе сегодня показать. Давай теперь перейдём к реальному примеру.
Рис 1. Выбор устройств
Для примера я не стал изобретать велосипед, а модернизировал исходник из прошлого номера. Основные изменения коснулись создания новой формы, в которой можно выбирать устройство воспроизведения и записи (рис 1). Для заполнения параметров я изменил функцию FillDevice:
procedure TSounderForm.FillDevice;
var
Num,i:Integer;
WaveCaps:TWaveOutCaps;
pwoc:TWaveOutCaps;
begin
//Очищаю ComboBox в котором хранится инфа об устройствах воспроизведения
SoundOptionForm.AudioDeviceCBox.Items.Clear;
//Запрашиваю инфу о количестве устройств воспроизведения
Num:=waveOutGetNumDevs;
//Запрашиваю параметры каждого
for i:=0 to Num-1 do
begin
//Получить информацию об устройстве воспроизведения i
WaveOutGetDevCaps(i,@WaveCaps,sizeof(WaveCaps));
//Добавить новый элемент в ComboBox с именем устройства
SoundOptionForm.AudioDeviceCBox.Items.Add(WaveCaps.szPName);
end;
//Добавить новый элемент в ComboBox устройство по умолчанию
SoundOptionForm.AudioDeviceCBox.Items.Add('Automatic select audio device');
//Очищаю ComboBox в котором хранится инфа об устройствах записи
SoundOptionForm.RecDeviceCBox.Items.Clear;
//Запрашиваю инфу о количестве устройств записи
Num:=waveInGetNumDevs;
//Запрашиваю параметры каждого
for i:=0 to Num-1 do
begin
//Получить информацию об устройстве записи i
WaveInGetDevCaps(i,@WaveCaps,sizeof(WaveCaps));
//Добавить новый элемент в ComboBox с именем устройства
SoundOptionForm.RecDeviceCBox.Items.Add(WaveCaps.szPName);
end;
//Добавить новый элемент в ComboBox устройство по умолчанию
SoundOptionForm.RecDeviceCBox.Items.Add('Automatic select record device');
//Это мы разбирали в прошлый раз. Здесь изменения нет
waveOutGetDevCaps(w_DeviceID, @pwoc, sizeof(pwoc));
if (pwoc.dwSupport and WAVECAPS_VOLUME)>0 then
begin
VolumeLBar.Enabled:=true;
VolumeRBar.Enabled:=true;
end;
end;
На событие FormShow я добавил две строки, где устанавливаются значения по умолчанию для устройств:
procedure TSounderForm.FormShow(Sender: TObject);
begin
EnableBut(false);
RestartPlay:=false;
//Заполнить информацию об устройствах
FillDevice;
//Установить значение по умолчанию.
SoundOptionForm.AudioDeviceCBox.ItemIndex:=
SoundOptionForm.AudioDeviceCBox.Items.Count-1;
SoundOptionForm.RecDeviceCBox.ItemIndex:=
SoundOptionForm.RecDeviceCBox.Items.Count-1;
end;
Выбор записывающего устройства пока не используется, это мы сделаем позже, когда разберёмся с функциями записи звука. А для воспроизведения я всё сделал. Заглядываем в обработчик события "Когда нажали кнопку Play" :) и видим
procedure TSounderForm.PlayButtonClick(Sender: TObject);
begin
//Здесь всё старое
if ((w_Pause)and (w_hPlay<>0)) then
begin
waveOutRestart(w_hPlay);
w_Pause:=not w_Pause;
exit;
end;
if w_hPlay<>0 then StopButtonClick(nil);
SoundTimer.Enabled:=true;
w_Pause:=false; w_Restart:=false; w_Stop:=false;
w_PlayPosition:=PositionBar.Position*1000;
w_RestartPosition:=PositionBar.Position*1000;
//Вот здесь мы берём выбранное в настройках значение звукового устройства
w_DeviceID:=SoundOptionForm.AudioDeviceCBox.ItemIndex;
//Если выбран последний элемент (туда мы засунули устройство по
//умолчанию", то
if SoundOptionForm.AudioDeviceCBox.ItemIndex=
SoundOptionForm.AudioDeviceCBox.Items.Count-1 then
//Изменяем значение на WAVE_MAPPER.
w_DeviceID:=Integer(WAVE_MAPPER);
//Дальше уже всё ясно
CyDSounder1:=TSoundPlayer.Create(true);
CyDSounder1.Priority:=tpHigher;
CyDSounder1.Resume;
end;
Ну и самое главное :) я добавил кнопку, которая вызывает диалог с настройками устройств. По её нажатию я вызываю окно, которе ты видел на рис 2:
procedure TSounderForm.ToolButton3Click(Sender: TObject);
begin
SoundOptionForm.ShowModal;
end;
Вот и всё, теперь ты готов изучить тонкости записи звука. Это будет в следующий раз.