Главная » Программирование звука » Выбор устройства

0

Windows  поддерживает  произвольное  количество  устройств  воспроизведения звука, и выбор нужного может оказаться непростой задачей. Существуют два способа,  позволяющих  выяснить  возможности  этого  устройства.  Один  из  них  заключается  в  запросе  характеристик  устройства  (waveOutGetDevCaps)  и  применении битовой  матрицы  для  подбора  наиболее  подходящего  формата.  Подобный  подход ограничивает  нас  всего  лишь  тремя  возможными  значениями  частоты  дискретизации,  что  может  оказаться  затруднительным.  Кроме  того,  уместно  использовать специальную  форму  вызова  waveOutOpen для  того,  чтобы  проверить,  поддерживает ли какое-нибудь из устройств предпочитаемый вами формат.

Метод   SelectDEvice начинает   работу   с  вызова  методов   MinMaxChannels и   MinMaxSamplingRate,   определяющих   допустимый   диапазон   параметров   для других объектов обработки звука. После этого следует запрос к системе, с помощью которого определяется, может ли система работать с оптимальным форматом. Если приходит  отрицательный  ответ,  то  у  Windows  запрашивается  перечень  поддерживаемых  форматов  и  производится  поиск  стандартного  формата,  характеристики которого  соответствуют  диапазону  допустимых  параметров.  Если  один  из  перечисленных  способов  сработает,  то  станет  ясно,  какие  параметры  будут  использованы,     после     чего     можно     вызывать     методы     SetSamplingRateRecursive и    SetChanelsRecursive,    чтобы    окончательно    задать    параметры    остальных объектов обработки звука.

Листинг 6.3. Реализация класса WinPalyer (продолжение)

// Рассмотрены базовые  форматы, поддерживаемые  Windows static struct {

DWORD format;  // Константа.

UINT rate;     // Разделитель  для этой  константы.

UINT channels; UINT width;

} winFormats[] = {

{WAVE_FORMAT_1S16,

11025, 2,

16},

{WAVE_FORMAT_1S08,

11025, 2,

8},

{WAVE_FORMAT_1M16,

11025, 1,

16},

{WAVE_FORMAT_1M08,

11025, 1,

8},

{WAVE_FORMAT_2S16,

22050, 2,

16},

{WAVE_FORMAT_2S08,

22050, 2,

8},

{WAVE_FORMAT_2M16,

22050, 1,

16},

{WAVE_FORMAT_2M08,

22050, 1,

8},

{WAVE_FORMAT_4S16,

44100, 2,

16},

{WAVE_FORMAT_4S08,

44100, 2,

8},

{WAVE_FORMAT_4M16,

44100, 1,

16},

{WAVE_FORMAT_4M08,

{0,0,0,0}

44100, 1,

8},

};

// Согласуем  формат записи  и  открываем  подходящее

// устройство.

int WinPlayer::SelectDevice(void) {

// Остальные  предложения  по   форматам.

int channelsMin = 1, channelsMax = 2, channelsPreferred = 0; long rateMin = 8000, rateMax = 44100, ratePreferred = 22050; MinMaxChannels(&channelsMin,&channelsMax,&channelsPreferred); if (channelsMin > channelsMax) {

// He удалось согласовать  каналы.

cerr << "Couldn’t negotiate channels.\n";

exit (1);

} MinMaxSamplingRate(&rateMin,&rateMax,&ratePreferred); if (rateMin > rateMax) {

// He удалось согласовать  частоту

// дискретизации.

cerr << "Couldn’t negotiate rate.\n";

exit(1);

}

// Сначала проверяем  на   точное совпадение.

static const int NO_MATCH=100000; UINT matchingDevice = NO_MATCH; WAVEFORMATEX waveFormat; waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nChannels = channelsPreferred; waveFormat.nSamplesPerSec = ratePreferred;

waveFormat.wBitsPerSample = 8 * sizeof(Sample16);

waveFormat.nBlockAlign = waveFormat.nChannels

* waveFormat.wBitsPerSample / 8;

waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign

* waveFormat.nSamplesPerSec;

waveFormat.cbSize = 0;

MMRESULT err = waveOutOpen(0,WAVE_MAPPER,&waveFormat,

0,0,WAVE_FORMAT_QUERY);

if (err == 0) {

matchingDevice = WAVE_MAPPER;

channelsMax = channelsMin = channelsPreferred;

rateMax = rateMin = ratePreferred;

_sampleWidth = 16;

} else {

// WinPlay: He удалось использовать

// нестандартный формат, пробуем  стандартные.

cerr << "WinPlay: Custom format failed, ";7 cerr << "trying standard formats.\n";

}

// Пересчитываем  доступные  устройства.

UINT numDevs = waveOutGetNumDevs();

if (numDevs == 0) {

// Устройств вывода звука  не   найдено? cerr << "No sound output devices found?!\n"; exit(1);

}

// Проверяем все  доступные устройства.

for (UINT i=0; (i<numDevs) && (matchingDevice == NO_MATCH);

i++) {

// Какие форматы поддерживает  это  устройство?

WAVEOUTCAPS waveOutCaps; MMRESULT err =

waveOutGetDevCaps(i,&waveOutCaps,sizeof(waveOutCaps));

if (err != MMSYSERR_NOERROR) {

// He удалось  получить информацию  о  возможностях  устройства.

cerr << "Couldn’t get capabilities of device " << i <<

"\n";

continue;

}

// Проверяем  все  стандартные форматы.

for(UINT j=0; winFormats[j].format != 0; j++) {

if ((winFormats[j].format & waveOutCaps.dwFormats)

// Поддерживает?

&&(rateMin <= winFormats[j].rate)

// Частота подходит?

&&(rateMax >= winFormats[j].rate)

&&(channelsMin <= winFormats[j].channels)

// Количество каналов  подходит?

&&(channelsMax >= winFormats[j].channels)) {

// Устанавливаем  мои  параметры.

matchingDevice = i;

rateMin = rateMax = ratePreferred =

winFormats[j].rate;

channelsPreferred = winFormats[j].channels;

channelsMin = channelsMax = channelsPreferred;

_sampleWidth = winFormats[j].width;

// Соответственно устанавливаем структуру  WAVEFORMATEX. waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nChannels = winFormats[j].channels; waveFormat.nSamplesPerSec = winFormats[j].rate; waveFormat.wBitsPerSample = winFormats[j].width; waveFormat.nBlockAlign = waveFormat.wBitsPerSample / 8

* waveFormat.nChannels;

waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign

* waveFormat.nSamplesPerSec;

waveFormat.cbSize = 0;

}

}

}

if (matchingDevice == NO_MATCH) {

// Данный   формат  не   поддерживается.

// Далее  следуют параметры формата.

cerr << "Can’t handle this sound format.\n";

cerr << "Rate: " << rateMin << "-" << rateMax << "\n";

cerr << "Channels: " << channelsMin << "-" << channelsMax

<< "\n";

return 1;

}

// Если   удалось  найти  совпадающие параметры, задаем  все.

SetChannelsRecursive(channelsPreferred); SetSamplingRateRecursive(ratePreferred);

// Открываем подходящее  устройство.

MMRESULT err2 = waveOutOpen(&_device,matchingDevice,

&waveFormat, reinterpret_cast<DWORD>(WaveOutCallback), reinterpret_cast<DWORD>(this),CALLBACK_FUNCTION);

if (err2) {

// He удалось  открыть устройство  воспроизведения WAVE.

cerr << "Couldn’t open WAVE output device.\n";

exit (1);

}

return 0;

}

Источник: Кинтцель Т.  Руководство программиста по работе со звуком = A Programmer’s Guide to Sound: Пер. с англ. М.: ДМК Пресс, 2000. 432 с, ил. (Серия «Для программистов»).

По теме:

  • Комментарии