Использование DirectSound
Публикую с сокращениями, ибо ограничение по размеру.
Сэмпл - http://zlos.nm.ru/download/ds_for_gd_ru.zip
Обзор DirectSound.
Библиотека DirectSound является частью DirectX. Она, как и весь DirectX, построена на COM. Я не буду касаться этого вопроса подробнее, надеюсь, что вы все это уже знаете.
Инициализация.
Для инициализации DirectSound нам необходимо создать экземпляр IDirectSound8, установить приоритет и параметры первичного буфера. Не самый очевидный и интересный пункт, конечно, но не бывает только интересной работы, иногда необходимо делать и нудную и скучную.
Интерфейс IDirectSound8 может быть создан 2-я путями. Самый простой – DirectSoundCreate8. В SDK он описан так:
HRESULT DirectSoundCreate8(
LPCGUID lpcGuidDevice,
LPDIRECTSOUND8 * ppDS8,
LPUNKNOWN pUnkOuter
);
Первым параметром идет GUID типа устройства. Мы будем использовать устройство по умолчанию, или DSDEVID_DefaultPlayback. Далее передается указатель на указатель интерфейса IDirectSound8 и NULL.
Второй путь лежит через CoCreateInstance, требует некоторых дополнительных телодвижений.
В итоге инициализация типично выглядит следующим образом:
IDirectSound8 *pDS;
HRESULT hr;
if (FAILED(hr = DirectSoundCreate8(&DSDEVID_DefaultPlayback, &pDS, NULL))) {
return DXTRACE_ERR(_T(“DirectSoundCreate8”));
}
Теперь нам необходимо указать, с каким приоритетом мы хотим воспроизводить звук. Вообще, существует 4 варианта приоритета, я коснусь 2-х.
1. Нормальный – наиболее безопасен, ест наименьший объем ресурсов, но дает низкое качество звука – всего 8 бит.
2. Приоритетный – мы можем самостоятельно указывать параметры основного буфера, задавать частоту и битность.
Я сначала пытаюсь установить приоритетный режим (чтобы обеспечить высокое качество), если не получается – устанавливаю обычный. Игрок в последнем случае будет слышать не самый качественный звук, но ведь будет!
Устанавливается приоритет посредством метода SetCooperativeLevel. Нам надо передать туда окно нашей программы и приоритет:
if (SUCCEEDED(hr = pDS-> SetCooperativeLevel(g_hWnd, DSSCL_PRIORITY))) { if (SUCCEEDED(InitPrimaryBuffer(pDS))) { m_pDS = pDS; return S_OK; } } if (SUCCEEDE(hr = pDS->SetCooperativeLevel(g_hWnd, DSSCL_NORMAL))) { m_pDS = pDS; return S_OK; } pDS->Release(); return E_FAIL;
Инициализация первичного буфера является простой, но не самой интеллектуальной задачей. Я просто приведу код:
WAVEFORMATEX waveFormat;
ZeroMemory(&waveFormat, sizeof(waveFormat));
const int bitCount = 16;
const int channelCount = 2;
const int sampleRate = 44100;
waveFormat.cbSize = sizeof(WAVEFORMATEX);
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = channelCount;
waveFormat.nSamplesPerSec = sampleRate;
waveFormat.nBlockAlign = channelCount * bitCount / 8;
waveFormat.nAvgBytesPerSec = sampleRate * waveFormat.nBlockAlign;
waveFormat.wBitsPerSample = sampleRate;
DSBUFFERDESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DSBUFFERDESC));
bufferDesc.dwSize = sizeof(DSBUFFERDESC);
bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
bufferDesc.dwBufferBytes = 0;
bufferDesc.lpwfxFormat = 0;
IDirectSoundBuffer *pdsPrimaryBuffer;
if (SUCCEEDED(hr = pDS->CreateSoundBuffer(&bufferDesc, &pdsPrimaryBuffer, 0))) {
if (SUCCEEDED(hr = pdsPrimaryBuffer->SetFormat(&waveFormat))) {
m_pdsPrimaryBuffer = pdsPrimaryBuffer;
return S_OK;
}
pdsPrimaryBuffer->Release();
}
retuen hr;
[/code]
Мы заполняем структуру с описанием звукового формата и описание буфера. Потом мы просим у IDirectSound8 создать нам его, и мы пытаемся установить на нем нужный формат. Если получается – ура, у игрока будет хороший звук!
Воспроизведение статического звука
Как я сказал выше, главной частью DirectSound являются буфера. Буфера бывают статические (содержат один загруженный звук) и потоковыми (через которые длинный звук как бы «пропускается»).
Звуковой буфер (в терминологии DirectSound – вторичный) создается почти так же, как и первичный. Для загрузки звука мы должны получить информацию о звуковом файле и создать звуковой буфер с соответствующими параметрами. В коде это выглядит опять-таки достаточно просто: