// --------------------------------------------------------------------------------------- // ds3d_init() // // Initialize the DirectSound3D system. Call the initialization for the pDS3D_listener // // returns: -1 => init failed // 0 => success int ds3d_init(int voice_manager_required) { if (DS3D_inited == TRUE) return 0; #ifndef USE_OPENAL if (voice_manager_required == 1) { LPKSPROPERTYSET pset; pset = (LPKSPROPERTYSET)ds_get_property_set_interface(); if (pset == NULL) { nprintf(("Sound", "Disabling DirectSound3D since unable to get property set interface\n")); return -1; } HRESULT hr; unsigned long driver_support = 0; hr = pset->QuerySupport(DSPROPSETID_VoiceManager_Def, DSPROPERTY_VMANAGER_MODE, &driver_support); if (FAILED(hr)) { nprintf(("Sound", "Driver does not support Voice Manager extension, so abort DirectSound3D initialization\n")); return -1; } if ((driver_support & KSPROPERTY_SUPPORT_SET | KSPROPERTY_SUPPORT_GET) != (KSPROPERTY_SUPPORT_SET | KSPROPERTY_SUPPORT_GET)) { nprintf(("Sound", "Driver does not support Voice Manager extension, so abort DirectSound3D initialization\n")); return -1; } VmMode vmode = DSPROPERTY_VMANAGER_MODE_AUTO; hr = pset->Set(DSPROPSETID_VoiceManager_Def, DSPROPERTY_VMANAGER_MODE, NULL, 0, &vmode, sizeof(float)); if (FAILED(hr)) { nprintf(("Sound", "Driver does not support Voice Manager extension, so abort DirectSound3D initialization\n")); return -1; } } #endif if (ds3d_init_listener() != 0) { return -1; } DS3D_inited = TRUE; return 0; }
//=========================================================================== // EAXSetf //=========================================================================== void EAXSetf(DWORD prop, float value) { if(!eaxListener) return; eaxListener->Set(DSPROPSETID_EAX_ListenerProperties, prop | DSPROPERTY_EAXLISTENER_DEFERRED, NULL, 0, &value, sizeof(float)); }
//=========================================================================== // EAXCommitDeferred //=========================================================================== void EAXCommitDeferred(void) { if(!eaxListener) return; eaxListener->Set(DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_COMMITDEFERREDSETTINGS, NULL, 0, NULL, 0); }
//=========================================================================== // EAXMuldw // Linear multiplication for a logarithmic property. //=========================================================================== void EAXMuldw(DWORD prop, float mul) { DWORD retBytes; LONG value; if(!eaxListener) return; if(FAILED(hr = eaxListener->Get(DSPROPSETID_EAX_ListenerProperties, prop, NULL, 0, &value, sizeof(value), &retBytes))) { /*if(!ignore_eax_errors) Con_Message("DS_EAXMuldw (prop:%i) get failed. Result: %x.\n", prop, hr & 0xffff);*/ return; } EAXSetdw(prop, LinLog(pow(10, value/2000.0f) * mul)); }
//=========================================================================== // DS_Shutdown //=========================================================================== void DS_Shutdown(void) { if(!initOk) return; if(eaxListener) eaxListener->Release(); if(dsListener) dsListener->Release(); if(primary) primary->Release(); if(dsound) dsound->Release(); eaxListener = NULL; dsListener = NULL; primary = NULL; dsound = NULL; initOk = false; }
//----------------------------------------------------------------------------- // Установка eax параметров // на входе : prop - указатель на eax интерфейс // type - тип интерфейса (слушатель или буфер) // version - версия интерфейса // data - указатель на данные для установки // на выходе : успешность установки параметров //----------------------------------------------------------------------------- int eax_Set(LPKSPROPERTYSET prop, int type, int version, void* data) { // проверка параметров if ((!prop) || (version == 0) || (type > EAX_BUFFER)) return false; // установка параметров if (prop->Set(EAX_Guid[type][version], EAX_Param[type][version], NULL, 0, data, EAX_StructSize[type][version]) != DS_OK) return false; return true; }
//----------------------------------------------------------------------------- // Проверка возможности чтения и записи // на входе : prop - указатель на eax интерфейс // type - тип интерфейса (слушатель или буфер) // version - версия интерфейса // на выходе : успешность возможности чтения и записи //----------------------------------------------------------------------------- int eax_TestQuerySupport(LPKSPROPERTYSET prop, int type, int version) { unsigned long support; // проверка параметров if (!prop) return false; // проверим поддержку слушателя if (prop->QuerySupport(EAX_Guid[type][version], EAX_Param[type][version], & support) == DS_OK) { // проверка возможности чтения и записи if ((support & KSPROPERTY_SUPPORT_GET) && (support & KSPROPERTY_SUPPORT_SET)) return true; } return false; }
//=========================================================================== // EAXMulf // Linear multiplication for a linear property. //=========================================================================== void EAXMulf(DWORD prop, float mul, float min, float max) { DWORD retBytes; float value; if(!eaxListener) return; if(FAILED(hr = eaxListener->Get(DSPROPSETID_EAX_ListenerProperties, prop, NULL, 0, &value, sizeof(value), &retBytes))) { /* if(!ignore_eax_errors) Con_Message("DS_EAXMulf (prop:%i) get failed. Result: %x.\n", prop, hr & 0xffff);*/ return; } value *= mul; if(value < min) value = min; if(value > max) value = max; EAXSetf(prop, value); }
//----------------------------------------------------------------------------- // Установка предустановленного eax окружения // на входе : direct - указатель на объект воспроизведения // version - версия интерфейса // на выходе : успешность устаноки окружения //----------------------------------------------------------------------------- int eax_TestSupport(LPDIRECTSOUND direct, int version) { // объявление переменных WAVEFORMATEX wfx; // формат звука DSBUFFERDESC dsbd; // дескриптор int ok; // флаг инициализации EAX интерфейса LPDIRECTSOUNDBUFFER Buffer; LPDIRECTSOUND3DBUFFER Buffer3D; LPKSPROPERTYSET ListenerPropSet; LPKSPROPERTYSET BufferPropSet; // заполним структуру с форматом wfx.wFormatTag = 1; wfx.nChannels = 2; wfx.nSamplesPerSec = 44100; wfx.wBitsPerSample = 16; wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) >> 3; wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; wfx.cbSize = 0; // обнулим параметры ok = false; Buffer = 0; Buffer3D = 0; ListenerPropSet = 0; BufferPropSet = 0; // проверка наличия объекта воспроизведения if (direct) { // занесение данных вторичного буфера ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRL3D; dsbd.dwBufferBytes = 128; dsbd.lpwfxFormat = &wfx; // Создание вторичного буфера ok = (direct->CreateSoundBuffer(&dsbd, & Buffer, NULL) == DS_OK) ? true : false; // получим интерфейс для работы с EAX слушателем if (ok) ok = (Buffer->QueryInterface(IID_IKsPropertySet, (void * *) &ListenerPropSet) == DS_OK) ? true : false; // Создание интерфейса для трехмерного звука if (ok) ok = (Buffer->QueryInterface(IID_IDirectSound3DBuffer, (VOID * *) &Buffer3D) == DS_OK) ? true : false; // получение интерфейсов ListenerPropSet = eax_GetBufferInterface(Buffer); BufferPropSet = eax_GetBuffer3DInterface(Buffer3D); // проверка возможности чтения и записи слушателя if (ok) ok = eax_TestQuerySupport(ListenerPropSet, EAX_LISTENER, version); if (ok) ok = eax_TestQuerySupport(ListenerPropSet, EAX_BUFFER, version); // освободим EAX источник if (BufferPropSet) { BufferPropSet->Release(); BufferPropSet = 0; } // освободим 3D буфер if (Buffer3D) { Buffer3D->Release(); Buffer3D = 0; } // освободим EAX слушателя if (ListenerPropSet) { ListenerPropSet->Release(); ListenerPropSet = 0; } // освободим буфер if (Buffer) { Buffer->Release(); Buffer = 0; } } return ok; }
//=========================================================================== // DS_Init //=========================================================================== int DS_Init(void) { HWND hWnd; DSBUFFERDESC desc; LPDIRECTSOUNDBUFFER bufTemp; if(initOk) return true; // Are we in verbose mode? if((verbose = ArgExists("-verbose"))) Con_Message("DS_Init(Compat): Initializing sound driver...\n"); // Get Doomsday's window handle. hWnd = (HWND) DD_GetInteger(DD_WINDOW_HANDLE); hr = DS_OK; if(ArgExists("-noeax") || FAILED(hr = EAXDirectSoundCreate(NULL, &dsound, NULL))) { // EAX can't be initialized. Use normal DS, then. if(FAILED(hr)) Error("DS_Init", "EAX 2 couldn't be initialized."); if(FAILED(hr = DirectSoundCreate(NULL, &dsound, NULL))) { Error("DS_Init", "Failed to create dsound interface."); return false; } } // Set the cooperative level. if(FAILED(hr = dsound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY))) { Error("DS_Init", "Couldn't set dSound coop level."); return false; } // Get the primary buffer and the listener. primary = NULL; memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); desc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER; dsListener = NULL; if(SUCCEEDED(dsound->CreateSoundBuffer(&desc, &primary, NULL))) { // Query the listener interface. primary->QueryInterface(IID_IDirectSound3DListener, (void**) &dsListener); } else { // Failure; get a 2D primary buffer, then. desc.dwFlags = DSBCAPS_PRIMARYBUFFER; dsound->CreateSoundBuffer(&desc, &primary, NULL); } // Start playing the primary buffer. if(primary) { if(FAILED(hr = primary->Play(0, 0, DSBPLAY_LOOPING))) Error("DS_Init", "Can't play primary buffer."); } // Try to get the EAX listener property set. // Create a temporary secondary buffer for it. eaxListener = NULL; if(SUCCEEDED(CreateDSBuffer(DSBCAPS_STATIC | DSBCAPS_CTRL3D, DSBSIZE_MIN, 22050, 8, 1, &bufTemp))) { // Now try to get the property set. if(SUCCEEDED(hr = bufTemp->QueryInterface(IID_IKsPropertySet, (void**) &eaxListener))) { DWORD support = 0, revsize = 0; // Check for support. if(FAILED(hr = eaxListener->QuerySupport( DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ENVIRONMENT, &support)) || ((support & NEEDED_SUPPORT) != NEEDED_SUPPORT)) { Error("DS_Init", "Sufficient EAX2 support not present."); eaxListener->Release(); eaxListener = NULL; } else { // EAX is supported! if(verbose) Con_Message("DS_Init(Compat): EAX2 is available.\n"); } } // Release the temporary buffer interface. bufTemp->Release(); } // Get the caps. dsCaps.dwSize = sizeof(dsCaps); dsound->GetCaps(&dsCaps); if(verbose) Con_Message("DS_Init(Compat): Number of hardware 3D " "buffers: %i\n", dsCaps.dwMaxHw3DAllBuffers); // Configure the DS3D listener. if(dsListener) { dsListener->SetDistanceFactor(1/36.0f, DS3D_DEFERRED); dsListener->SetDopplerFactor(2, DS3D_DEFERRED); } // Success! initOk = true; return true; }
LPKSPROPERTYSET CSoundDriverDSound::createPropertySet(CSourceDSound *source) { if (_Sources.empty()) return NULL; LPDIRECTSOUND3DBUFFER8 d3dBuffer; if (source == NULL) d3dBuffer = (*_Sources.begin())->_3DBuffer; else { d3dBuffer = source->_3DBuffer; } LPKSPROPERTYSET propertySet; d3dBuffer->QueryInterface(IID_IKsPropertySet, (void**) &propertySet); // some checking code { if (propertySet != 0) { char *listenerProperties[] = { "DSPROPERTY_EAXLISTENER_NONE", "DSPROPERTY_EAXLISTENER_ALLPARAMETERS", "DSPROPERTY_EAXLISTENER_ROOM", "DSPROPERTY_EAXLISTENER_ROOMHF", "DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR", "DSPROPERTY_EAXLISTENER_DECAYTIME", "DSPROPERTY_EAXLISTENER_DECAYHFRATIO", "DSPROPERTY_EAXLISTENER_REFLECTIONS", "DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY", "DSPROPERTY_EAXLISTENER_REVERB", "DSPROPERTY_EAXLISTENER_REVERBDELAY", "DSPROPERTY_EAXLISTENER_ENVIRONMENT", "DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE", "DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION", "DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF", "DSPROPERTY_EAXLISTENER_FLAGS" }; uint i; for (i=DSPROPERTY_EAXLISTENER_NONE; i<= DSPROPERTY_EAXLISTENER_FLAGS; ++i) { ULONG ulSupport = 0; propertySet->QuerySupport(DSPROPSETID_EAX_ListenerProperties, i, &ulSupport); if ( (ulSupport&(KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET) ) { // nlwarning("CSoundDriverDSound::createPropertySet : listener property %s not supported", listenerProperties[i]); } } char *bufferProperties[] = { "DSPROPERTY_EAXBUFFER_NONE", "DSPROPERTY_EAXBUFFER_ALLPARAMETERS", "DSPROPERTY_EAXBUFFER_DIRECT", "DSPROPERTY_EAXBUFFER_DIRECTHF", "DSPROPERTY_EAXBUFFER_ROOM", "DSPROPERTY_EAXBUFFER_ROOMHF", "DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR", "DSPROPERTY_EAXBUFFER_OBSTRUCTION", "DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO", "DSPROPERTY_EAXBUFFER_OCCLUSION", "DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO", "DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO", "DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF", "DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR", "DSPROPERTY_EAXBUFFER_FLAGS" }; for (i=DSPROPERTY_EAXBUFFER_NONE; i<=DSPROPERTY_EAXBUFFER_FLAGS; ++i) { ULONG ulSupport = 0; propertySet->QuerySupport(DSPROPSETID_EAX_BufferProperties, i, &ulSupport); if ( (ulSupport&(KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET) ) { // nlwarning("CSoundDriverDSound::createPropertySet : buffer property %s not supported", bufferProperties[i]); } } } else { nlwarning("CSoundDriverDSound::createPropertySet : propertie set not available !"); } } return propertySet; }
// Given a DirectX device identified by "guid", // find the corresponding wave device ID and return it in "waveID". // Inspired by DirectSoundEnumeratorDlg.cpp on chrisnet.net (via google.com/codesearch) HRESULT GetWaveDeviceIDFromGUID(LPGUID lpGUID, DIRECTSOUNDDEVICE_DATAFLOW dataflowType, DWORD* waveID) { HRESULT hr; LPKSPROPERTYSET propSet = NULL; DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA deviceDescription; PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA deviceDescriptionPtr = NULL; ULONG ulBytesReturned = 0; /* Assume we're going to fail. If we succeed, this will be overwritten. */ *waveID = -666; /* If we're passed a NULL GUID-ptr, we assume it's on purpose. */ if (!lpGUID) { *waveID = -1; return S_OK; } IClassFactory *factory = dsound_GetClassFactory(CLSID_DirectSoundPrivate); if (factory == NULL) { DPRINTF(("ERROR GetWaveDeviceIDFromGUID(): cannot obtain class factory\n")); hr = CLASS_E_CLASSNOTAVAILABLE; goto error; } hr = factory->CreateInstance(NULL, IID_IKsPropertySet,(LPVOID *)&propSet); if (FAILED(hr)) { DPRINTF(("ERROR GetWaveDeviceIDFromGUID(): cannot instantiate property-set\n")); goto error; } // An anonymous DirectX team member tipped off Mr. Chrisnet.net that it's // necessary to call Get() twice. Good to know. memset(&deviceDescription, 0, sizeof(deviceDescription)); deviceDescription.DeviceId = *lpGUID; deviceDescription.DataFlow = dataflowType; deviceDescription.WaveDeviceId = 666; // so we can see if it's changed. // On the first call the final size is unknown so pass the size of the struct in order to receive // "Type" and "DataFlow" values, ulBytesReturned will be populated with bytes required for struct+strings. hr = propSet->Get(DSPROPSETID_DirectSoundDevice, DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, NULL, 0, &deviceDescription, sizeof(deviceDescription), &ulBytesReturned ); if (FAILED(hr)) { DPRINTF(("ERROR GetWaveDeviceIDFromGUID(): property-get 1 failed\n")); goto error; } if (!ulBytesReturned) { // I don't know what to make of this situation... why would the return code // be successful, but the byte-count be zero? Oh well, it may never happen. DPRINTF(("ERROR GetWaveDeviceIDFromGUID(): failed to get byte-size for description\n")); hr = ERROR_INVALID_HANDLE; // not sure what the correct error-value; this is in the ballpark goto error; } // On the first call it notifies us of the required amount of memory in order to receive the strings. // Allocate the required memory, the strings will be pointed to the memory space directly after the struct. deviceDescriptionPtr = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA)malloc(ulBytesReturned); if (!deviceDescriptionPtr) { DPRINTF(("ERROR GetWaveDeviceIDFromGUID(): failed to dynamically allocate for description\n")); hr = ERROR_NOT_ENOUGH_MEMORY; goto error; } *deviceDescriptionPtr = deviceDescription; hr = propSet->Get(DSPROPSETID_DirectSoundDevice, DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, NULL, 0, deviceDescriptionPtr, ulBytesReturned, &ulBytesReturned ); if (FAILED(hr)) { DPRINTF(("ERROR GetWaveDeviceIDFromGUID(): property-get 2 failed\n")); goto error; } DPRINTF(("OBTAINED DEVICE INFO: \n\ttype/waveID: %d/%d\n\tdescription: %s\n\tmodule: %s\n\tinterface: %s\n", deviceDescriptionPtr->Type, deviceDescriptionPtr->WaveDeviceId, deviceDescriptionPtr->Description, deviceDescriptionPtr->Module, deviceDescriptionPtr->Interface)); // All of that bullshit for one little integer. *waveID = deviceDescriptionPtr->WaveDeviceId; hr = S_OK; error: if (propSet) { propSet->Release(); } if (factory) { factory->Release(); } if (deviceDescriptionPtr) { free(deviceDescriptionPtr); } return hr; // return the last result, which should be appropriate }