int dsound_is_3d_buffer ( LPDIRECTSOUNDBUFFER buffer ) { DSBCAPS caps; unsigned int dsrval; memset ( &caps, 0, sizeof ( caps ) ); caps.dwSize = sizeof ( caps ); #ifdef _WIN32 dsrval = IDirectSoundBuffer_GetCaps ( buffer, &caps ); if ( dsrval != DS_OK ) { debug_log ( "Unable to get caps of the sound buffer: %s", get_dsound_error_message ( dsrval ) ); } #endif if ( caps.dwFlags & DSBCAPS_CTRL3D ) { return ( TRUE ); } else { return ( FALSE ); } }
static HRESULT test_block_align(LPGUID lpGuid) { HRESULT rc; LPDIRECTSOUND dso=NULL; LPDIRECTSOUNDBUFFER secondary=NULL; DSBUFFERDESC bufdesc; DSBCAPS dsbcaps; WAVEFORMATEX wfx; int ref; /* Create the DirectSound object */ rc=DirectSoundCreate(lpGuid,&dso,NULL); ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); if (rc!=DS_OK) return rc; init_format(&wfx,WAVE_FORMAT_PCM,11025,16,2); ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec + 1; bufdesc.lpwfxFormat=&wfx; rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); ok(rc==DS_OK,"IDirectSound_CreateSoundBuffer() " "should have returned DS_OK, returned: %s\n", DXGetErrorString8(rc)); if (rc==DS_OK && secondary!=NULL) { ZeroMemory(&dsbcaps, sizeof(dsbcaps)); dsbcaps.dwSize = sizeof(dsbcaps); rc=IDirectSoundBuffer_GetCaps(secondary,&dsbcaps); ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() should have returned DS_OK, " "returned: %s\n", DXGetErrorString8(rc)); if (rc==DS_OK) ok(dsbcaps.dwBufferBytes==(wfx.nAvgBytesPerSec + wfx.nBlockAlign), "Buffer size not a multiple of nBlockAlign: requested %ld, " "got %ld, should be %ld\n", bufdesc.dwBufferBytes, dsbcaps.dwBufferBytes, wfx.nAvgBytesPerSec + wfx.nBlockAlign); ref=IDirectSoundBuffer_Release(secondary); ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d references, " "should have 0\n",ref); } ref=IDirectSound_Release(dso); ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); if (ref!=0) return DSERR_GENERIC; return rc; }
static ALuint DSoundPlaybackProc(ALvoid *ptr) { ALCdevice *Device = (ALCdevice*)ptr; DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData; DSBCAPS DSBCaps; DWORD LastCursor = 0; DWORD PlayCursor; VOID *WritePtr1, *WritePtr2; DWORD WriteCnt1, WriteCnt2; BOOL Playing = FALSE; DWORD FrameSize; DWORD FragSize; DWORD avail; HRESULT err; SetRTPriority(); memset(&DSBCaps, 0, sizeof(DSBCaps)); DSBCaps.dwSize = sizeof(DSBCaps); err = IDirectSoundBuffer_GetCaps(data->Buffer, &DSBCaps); if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); ALCdevice_Lock(Device); aluHandleDisconnect(Device); ALCdevice_Unlock(Device); return 1; } FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); FragSize = Device->UpdateSize * FrameSize; IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &LastCursor, NULL); while(!data->killNow) { // Get current play cursor IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &PlayCursor, NULL); avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; if(avail < FragSize) { if(!Playing) { err = IDirectSoundBuffer_Play(data->Buffer, 0, 0, DSBPLAY_LOOPING); if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); ALCdevice_Lock(Device); aluHandleDisconnect(Device); ALCdevice_Unlock(Device); return 1; } Playing = TRUE; } avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE); if(avail != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); continue; } avail -= avail%FragSize; // Lock output buffer WriteCnt1 = 0; WriteCnt2 = 0; err = IDirectSoundBuffer_Lock(data->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); // If the buffer is lost, restore it and lock if(err == DSERR_BUFFERLOST) { WARN("Buffer lost, restoring...\n"); err = IDirectSoundBuffer_Restore(data->Buffer); if(SUCCEEDED(err)) { Playing = FALSE; LastCursor = 0; err = IDirectSoundBuffer_Lock(data->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); } } // Successfully locked the output buffer if(SUCCEEDED(err)) { // If we have an active context, mix data directly into output buffer otherwise fill with silence aluMixData(Device, WritePtr1, WriteCnt1/FrameSize); aluMixData(Device, WritePtr2, WriteCnt2/FrameSize); // Unlock output buffer only when successfully locked IDirectSoundBuffer_Unlock(data->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else { ERR("Buffer lock error: %#lx\n", err); ALCdevice_Lock(Device); aluHandleDisconnect(Device); ALCdevice_Unlock(Device); return 1; } // Update old write cursor location LastCursor += WriteCnt1+WriteCnt2; LastCursor %= DSBCaps.dwBufferBytes; } return 0; }
int DSSetupSound() { HRESULT dsval; WAVEFORMATEX pcmwf; dsval = DirectSoundCreate(NULL,&lpDS,NULL); if(dsval != DS_OK) { MessageBox(hWMain,"DirectSoundCreate!","Error",MB_OK); return -1; } if(DS_OK != IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) { if(DS_OK != IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) { MessageBox(hWMain,"SetCooperativeLevel!","Error",MB_OK); return -1; } } memset(&dsbd,0,sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwBufferBytes = 0; dsbd.lpwfxFormat = NULL; dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); if(dsval != DS_OK) { MessageBox(hWMain, "CreateSoundBuffer (Primary)", "Error",MB_OK); return -1; } memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); pcmwf.wFormatTag = WAVE_FORMAT_PCM; pcmwf.nChannels = 2; pcmwf.nBlockAlign = 4; pcmwf.nSamplesPerSec = SAMPLE_RATE; pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; pcmwf.wBitsPerSample = 16; dsval = IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); if(dsval != DS_OK) { MessageBox(hWMain, "SetFormat!", "Error",MB_OK); return -1; } dscaps.dwSize = sizeof(DSCAPS); dsbcaps.dwSize = sizeof(DSBCAPS); IDirectSound_GetCaps(lpDS,&dscaps); IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // NT4 hack! sizeof(DSBUFFERDESC); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; dsbdesc.dwBufferBytes = SOUNDSIZE; dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); if(dsval != DS_OK) { dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); if(dsval != DS_OK) { MessageBox(hWMain,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); return -1; } } dsval = IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); if(dsval != DS_OK) { MessageBox(hWMain,"Play (Primary)","Error",MB_OK); return -1; } dsval = IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); if(dsval != DS_OK) { MessageBox(hWMain,"Play (Secondary1)","Error",MB_OK); return -1; } // init some play vars LastWrite = 0x00000000; LastPlay = 0; return 0; }
static void test_hw_buffers(void) { IDirectSound8 *ds; IDirectSoundBuffer *primary, *primary2, **secondaries, *secondary; IDirectSoundBuffer8 *buf8; DSCAPS caps; DSBCAPS bufcaps; DSBUFFERDESC bufdesc; WAVEFORMATEX fmt; UINT i; HRESULT hr; hr = pDirectSoundCreate8(NULL, &ds, NULL); ok(hr == S_OK || hr == DSERR_NODRIVER || hr == DSERR_ALLOCATED || hr == E_FAIL, "DirectSoundCreate8 failed: %08x\n", hr); if(hr != S_OK) return; caps.dwSize = sizeof(caps); hr = IDirectSound8_GetCaps(ds, &caps); ok(hr == S_OK, "GetCaps failed: %08x\n", hr); ok(caps.dwPrimaryBuffers == 1, "Got wrong number of primary buffers: %u\n", caps.dwPrimaryBuffers); /* DSBCAPS_LOC* is ignored for primary buffers */ bufdesc.dwSize = sizeof(bufdesc); bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE | DSBCAPS_PRIMARYBUFFER; bufdesc.dwBufferBytes = 0; bufdesc.dwReserved = 0; bufdesc.lpwfxFormat = NULL; bufdesc.guid3DAlgorithm = GUID_NULL; hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &primary, NULL); ok(hr == S_OK, "CreateSoundBuffer failed: %08x\n", hr); if(hr != S_OK){ IDirectSound8_Release(ds); return; } bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE | DSBCAPS_PRIMARYBUFFER; hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &primary2, NULL); ok(hr == S_OK, "CreateSoundBuffer failed: %08x\n", hr); ok(primary == primary2, "Got different primary buffers: %p, %p\n", primary, primary2); if(hr == S_OK) IDirectSoundBuffer_Release(primary2); buf8 = (IDirectSoundBuffer8 *)0xDEADBEEF; hr = IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer8, (void**)&buf8); ok(hr == E_NOINTERFACE, "QueryInterface gave wrong failure: %08x\n", hr); ok(buf8 == NULL, "Pointer didn't get set to NULL\n"); fmt.wFormatTag = WAVE_FORMAT_PCM; fmt.nChannels = 2; fmt.nSamplesPerSec = 48000; fmt.wBitsPerSample = 16; fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; fmt.nAvgBytesPerSec = fmt.nBlockAlign * fmt.nSamplesPerSec; fmt.cbSize = 0; bufdesc.lpwfxFormat = &fmt; bufdesc.dwBufferBytes = fmt.nSamplesPerSec * fmt.nBlockAlign / 10; bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE | DSBCAPS_CTRLVOLUME; secondaries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectSoundBuffer *) * caps.dwMaxHwMixingAllBuffers); /* try to fill all of the hw buffers */ trace("dwMaxHwMixingAllBuffers: %u\n", caps.dwMaxHwMixingAllBuffers); trace("dwMaxHwMixingStaticBuffers: %u\n", caps.dwMaxHwMixingStaticBuffers); trace("dwMaxHwMixingStreamingBuffers: %u\n", caps.dwMaxHwMixingStreamingBuffers); for(i = 0; i < caps.dwMaxHwMixingAllBuffers; ++i){ hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &secondaries[i], NULL); ok(hr == S_OK || hr == E_NOTIMPL || broken(hr == DSERR_CONTROLUNAVAIL) || broken(hr == E_FAIL), "CreateSoundBuffer(%u) failed: %08x\n", i, hr); if(hr != S_OK) break; bufcaps.dwSize = sizeof(bufcaps); hr = IDirectSoundBuffer_GetCaps(secondaries[i], &bufcaps); ok(hr == S_OK, "GetCaps failed: %08x\n", hr); ok((bufcaps.dwFlags & DSBCAPS_LOCHARDWARE) != 0, "Buffer wasn't allocated in hardware, dwFlags: %x\n", bufcaps.dwFlags); } /* see if we can create one more */ hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &secondary, NULL); ok((i == caps.dwMaxHwMixingAllBuffers && hr == DSERR_ALLOCATED) || /* out of hw buffers */ (caps.dwMaxHwMixingAllBuffers == 0 && hr == DSERR_INVALIDCALL) || /* no hw buffers at all */ hr == E_NOTIMPL || /* don't support hw buffers */ broken(hr == DSERR_CONTROLUNAVAIL) || /* vmware winxp, others? */ broken(hr == E_FAIL) || /* broken AC97 driver */ broken(hr == S_OK) /* broken driver allows more hw bufs than dscaps claims */, "CreateSoundBuffer(%u) gave wrong error: %08x\n", i, hr); if(hr == S_OK) IDirectSoundBuffer_Release(secondary); for(i = 0; i < caps.dwMaxHwMixingAllBuffers; ++i) if(secondaries[i]) IDirectSoundBuffer_Release(secondaries[i]); HeapFree(GetProcessHeap(), 0, secondaries); IDirectSoundBuffer_Release(primary); IDirectSound8_Release(ds); }
static DWORD CALLBACK MCICDA_playLoop(void *ptr) { WINE_MCICDAUDIO *wmcda = (WINE_MCICDAUDIO*)ptr; DWORD lastPos, curPos, endPos, br; void *cdData; DWORD lockLen, fragLen; DSBCAPS caps; RAW_READ_INFO rdInfo; HRESULT hr = DS_OK; memset(&caps, 0, sizeof(caps)); caps.dwSize = sizeof(caps); hr = IDirectSoundBuffer_GetCaps(wmcda->dsBuf, &caps); fragLen = caps.dwBufferBytes/CDDA_FRAG_COUNT; curPos = lastPos = 0; endPos = ~0u; while (SUCCEEDED(hr) && endPos != lastPos && WaitForSingleObject(wmcda->stopEvent, 0) != WAIT_OBJECT_0) { hr = IDirectSoundBuffer_GetCurrentPosition(wmcda->dsBuf, &curPos, NULL); if ((curPos-lastPos+caps.dwBufferBytes)%caps.dwBufferBytes < fragLen) { Sleep(1); continue; } EnterCriticalSection(&wmcda->cs); rdInfo.DiskOffset.QuadPart = wmcda->start<<11; rdInfo.SectorCount = min(fragLen/RAW_SECTOR_SIZE, wmcda->end-wmcda->start); rdInfo.TrackMode = CDDA; hr = IDirectSoundBuffer_Lock(wmcda->dsBuf, lastPos, fragLen, &cdData, &lockLen, NULL, NULL, 0); if (hr == DSERR_BUFFERLOST) { if(FAILED(IDirectSoundBuffer_Restore(wmcda->dsBuf)) || FAILED(IDirectSoundBuffer_Play(wmcda->dsBuf, 0, 0, DSBPLAY_LOOPING))) { LeaveCriticalSection(&wmcda->cs); break; } hr = IDirectSoundBuffer_Lock(wmcda->dsBuf, lastPos, fragLen, &cdData, &lockLen, NULL, NULL, 0); } if (SUCCEEDED(hr)) { if (rdInfo.SectorCount > 0) { if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_RAW_READ, &rdInfo, sizeof(rdInfo), cdData, lockLen, &br, NULL)) WARN("CD read failed at sector %d: 0x%x\n", wmcda->start, GetLastError()); } if (rdInfo.SectorCount*RAW_SECTOR_SIZE < lockLen) { if(endPos == ~0u) endPos = lastPos; memset((BYTE*)cdData + rdInfo.SectorCount*RAW_SECTOR_SIZE, 0, lockLen - rdInfo.SectorCount*RAW_SECTOR_SIZE); } hr = IDirectSoundBuffer_Unlock(wmcda->dsBuf, cdData, lockLen, NULL, 0); } lastPos += fragLen; lastPos %= caps.dwBufferBytes; wmcda->start += rdInfo.SectorCount; LeaveCriticalSection(&wmcda->cs); } IDirectSoundBuffer_Stop(wmcda->dsBuf); SetEvent(wmcda->stopEvent); /* A design bug in native: the independent CD player called by the * MCI has no means to signal end of playing, therefore the MCI * notification is left hanging. MCI_NOTIFY_SUPERSEDED will be * signaled by the next command that has MCI_NOTIFY set (or * MCI_NOTIFY_ABORTED for MCI_PLAY). */ return 0; }
/* ================== SndSys_InitDirectSound DirectSound 5 support ================== */ static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested) { DSBUFFERDESC dsbuf; DSBCAPS dsbcaps; DWORD dwSize; DSCAPS dscaps; WAVEFORMATEXTENSIBLE format, pformat; HRESULT hresult; int reps; if (! SndSys_BuildWaveFormat(requested, &format)) return SIS_FAILURE; if (!hInstDS) { hInstDS = LoadLibrary("dsound.dll"); if (hInstDS == NULL) { Con_Print("Couldn't load dsound.dll\n"); return SIS_FAILURE; } pDirectSoundCreate = (HRESULT (__stdcall *)(GUID *, LPDIRECTSOUND *,IUnknown *))GetProcAddress(hInstDS,"DirectSoundCreate"); if (!pDirectSoundCreate) { Con_Print("Couldn't get DS proc addr\n"); return SIS_FAILURE; } } while ((hresult = pDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK) { if (hresult != DSERR_ALLOCATED) { Con_Print("DirectSound create failed\n"); return SIS_FAILURE; } if (MessageBox (NULL, "The sound hardware is in use by another app.\n\n" "Select Retry to try to start sound again or Cancel to run Quake with no sound.", "Sound not available", MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) { Con_Print("DirectSoundCreate failure\n hardware already in use\n"); return SIS_NOTAVAIL; } } dscaps.dwSize = sizeof(dscaps); if (DS_OK != IDirectSound_GetCaps (pDS, &dscaps)) { Con_Print("Couldn't get DS caps\n"); } if (dscaps.dwFlags & DSCAPS_EMULDRIVER) { Con_Print("No DirectSound driver installed\n"); SndSys_Shutdown (); return SIS_FAILURE; } if (DS_OK != IDirectSound_SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE)) { Con_Print("Set coop level failed\n"); SndSys_Shutdown (); return SIS_FAILURE; } // get access to the primary buffer, if possible, so we can set the // sound hardware format memset (&dsbuf, 0, sizeof(dsbuf)); dsbuf.dwSize = sizeof(DSBUFFERDESC); dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbuf.dwBufferBytes = 0; dsbuf.lpwfxFormat = NULL; memset(&dsbcaps, 0, sizeof(dsbcaps)); dsbcaps.dwSize = sizeof(dsbcaps); primary_format_set = false; // COMMANDLINEOPTION: Windows DirectSound: -snoforceformat uses the format that DirectSound returns, rather than forcing it if (!COM_CheckParm ("-snoforceformat")) { if (DS_OK == IDirectSound_CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL)) { pformat = format; if (DS_OK != IDirectSoundBuffer_SetFormat (pDSPBuf, (WAVEFORMATEX*)&pformat)) { Con_Print("Set primary sound buffer format: no\n"); } else { Con_Print("Set primary sound buffer format: yes\n"); primary_format_set = true; } } } // COMMANDLINEOPTION: Windows DirectSound: -primarysound locks the sound hardware for exclusive use if (!primary_format_set || !COM_CheckParm ("-primarysound")) { HRESULT result; // create the secondary buffer we'll actually work with memset (&dsbuf, 0, sizeof(dsbuf)); dsbuf.dwSize = sizeof(DSBUFFERDESC); dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE; dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE(requested); dsbuf.lpwfxFormat = (WAVEFORMATEX*)&format; memset(&dsbcaps, 0, sizeof(dsbcaps)); dsbcaps.dwSize = sizeof(dsbcaps); result = IDirectSound_CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL); if (result != DS_OK || requested->channels != format.Format.nChannels || requested->width != format.Format.wBitsPerSample / 8 || requested->speed != format.Format.nSamplesPerSec) { Con_Printf("DS:CreateSoundBuffer Failed (%d): channels=%u, width=%u, speed=%u\n", (int)result, (unsigned)format.Format.nChannels, (unsigned)format.Format.wBitsPerSample / 8, (unsigned)format.Format.nSamplesPerSec); SndSys_Shutdown (); return SIS_FAILURE; } if (DS_OK != IDirectSoundBuffer_GetCaps (pDSBuf, &dsbcaps)) { Con_Print("DS:GetCaps failed\n"); SndSys_Shutdown (); return SIS_FAILURE; } Con_Print("Using secondary sound buffer\n"); } else { if (DS_OK != IDirectSound_SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY)) { Con_Print("Set coop level failed\n"); SndSys_Shutdown (); return SIS_FAILURE; } if (DS_OK != IDirectSoundBuffer_GetCaps (pDSPBuf, &dsbcaps)) { Con_Print("DS:GetCaps failed\n"); return SIS_FAILURE; } pDSBuf = pDSPBuf; Con_Print("Using primary sound buffer\n"); } // Make sure mixer is active IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); Con_Printf(" %d channel(s)\n" " %d bits/sample\n" " %d samples/sec\n", requested->channels, requested->width * 8, requested->speed); gSndBufSize = dsbcaps.dwBufferBytes; // initialize the buffer reps = 0; while ((hresult = IDirectSoundBuffer_Lock(pDSBuf, 0, gSndBufSize, (LPVOID*)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK) { if (hresult != DSERR_BUFFERLOST) { Con_Print("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); SndSys_Shutdown (); return SIS_FAILURE; } if (++reps > 10000) { Con_Print("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); SndSys_Shutdown (); return SIS_FAILURE; } } memset(lpData, 0, dwSize); IDirectSoundBuffer_Unlock(pDSBuf, lpData, dwSize, NULL, 0); IDirectSoundBuffer_Stop(pDSBuf); IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); dwStartTime = 0; dsound_time = 0; snd_renderbuffer = Snd_CreateRingBuffer(requested, gSndBufSize / (requested->width * requested->channels), lpData); dsound_init = true; return SIS_SUCCESS; }
static ALuint DSoundProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; DSoundData *pData = (DSoundData*)pDevice->ExtraData; DSBCAPS DSBCaps; DWORD LastCursor = 0; DWORD PlayCursor; VOID *WritePtr1, *WritePtr2; DWORD WriteCnt1, WriteCnt2; DWORD FrameSize; DWORD FragSize; DWORD avail; HRESULT err; SetRTPriority(); memset(&DSBCaps, 0, sizeof(DSBCaps)); DSBCaps.dwSize = sizeof(DSBCaps); err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps); if(FAILED(err)) { AL_PRINT("Failed to get buffer caps: 0x%lx\n", err); aluHandleDisconnect(pDevice); return 1; } FrameSize = aluFrameSizeFromFormat(pDevice->Format); FragSize = pDevice->UpdateSize * FrameSize; IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL); while(!pData->killNow) { // Get current play and write cursors IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; if(avail < FragSize) { Sleep(1); continue; } avail -= avail%FragSize; // Lock output buffer WriteCnt1 = 0; WriteCnt2 = 0; err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); // If the buffer is lost, restore it, play and lock if(err == DSERR_BUFFERLOST) { err = IDirectSoundBuffer_Restore(pData->DSsbuffer); if(SUCCEEDED(err)) err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); if(SUCCEEDED(err)) err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); } // Successfully locked the output buffer if(SUCCEEDED(err)) { // If we have an active context, mix data directly into output buffer otherwise fill with silence aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize); aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize); // Unlock output buffer only when successfully locked IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else AL_PRINT("Buffer lock error: %#lx\n", err); // Update old write cursor location LastCursor += WriteCnt1+WriteCnt2; LastCursor %= DSBCaps.dwBufferBytes; } return 0; }
/* This function tries to create a primary audio buffer, and returns the number of audio chunks available in the created buffer. */ static int CreatePrimary(LPDIRECTSOUND sndObj, HWND focus, LPDIRECTSOUNDBUFFER *sndbuf, WAVEFORMATEX *wavefmt, Uint32 chunksize) { HRESULT result; DSBUFFERDESC format; DSBCAPS caps; int numchunks; /* Try to set primary mixing privileges */ result = IDirectSound_SetCooperativeLevel(sndObj, focus, DSSCL_WRITEPRIMARY); if ( result != DS_OK ) { #ifdef DEBUG_SOUND SetDSerror("DirectSound SetCooperativeLevel", result); #endif return(-1); } /* Try to create the primary buffer */ memset(&format, 0, sizeof(format)); format.dwSize = sizeof(format); format.dwFlags=(DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2); format.dwFlags |= DSBCAPS_STICKYFOCUS; #ifdef USE_POSITION_NOTIFY format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY; #endif result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL); if ( result != DS_OK ) { #ifdef DEBUG_SOUND SetDSerror("DirectSound CreateSoundBuffer", result); #endif return(-1); } /* Check the size of the fragment buffer */ memset(&caps, 0, sizeof(caps)); caps.dwSize = sizeof(caps); result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps); if ( result != DS_OK ) { #ifdef DEBUG_SOUND SetDSerror("DirectSound GetCaps", result); #endif IDirectSoundBuffer_Release(*sndbuf); return(-1); } if ( (chunksize > caps.dwBufferBytes) || ((caps.dwBufferBytes%chunksize) != 0) ) { /* The primary buffer size is not a multiple of 'chunksize' -- this hopefully doesn't happen when 'chunksize' is a power of 2. */ IDirectSoundBuffer_Release(*sndbuf); SDL_SetError( "Primary buffer size is: %d, cannot break it into chunks of %d bytes\n", caps.dwBufferBytes, chunksize); return(-1); } numchunks = (caps.dwBufferBytes/chunksize); /* Set the primary audio format */ result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt); if ( result != DS_OK ) { #ifdef DEBUG_SOUND SetDSerror("DirectSound SetFormat", result); #endif IDirectSoundBuffer_Release(*sndbuf); return(-1); } return(numchunks); }
SNDOBJ *SndObjCreate(IDirectSound *pDS, char *lpName, int sfx_flags , DWORD buf_flags, int sfx) { SNDOBJ *pSO = NULL; void * Buffer = NULL; int i; HRESULT hres; DSBCAPS dsbcaps; #if 0 // needed for locking sound buffer LPVOID lpvAudioPtr1; DWORD dwAudioBytes1; LPVOID lpvAudioPtr2; DWORD dwAudioBytes2; DWORD dwFlags = DSBLOCK_ENTIREBUFFER; #endif pSO = (SNDOBJ *)malloc(sizeof(SNDOBJ)); if ( !FreeHWBuffers ) buf_flags |= DSBCAPS_LOCSOFTWARE; if (pSO != NULL) { memset( pSO, 0, sizeof(SNDOBJ) ); pSO->Dup_Buffer[0] = NULL; pSO->CompoundBuffer = FALSE; pSO->looping_sfx_index[0] = -1; // if sound is already loaded into HW... if ( ( IS_COMPOUND( sfx_flags ) ) && CompoundSfxAllocated[sfx] ) { pSO->CompoundBuffer = TRUE; for (i = 0; i < MAX_DUP_BUFFERS; i++) pSO->CompoundBufferLookup[i] = -1; }else { if ( A3DCapable ) { pSO->Dup_Buffer[0] = DSLoad3DSoundBuffer(pDS, lpName, &pSO->Dup_3DBuffer[0], buf_flags ); }else { // create buffer. Will create in hw if available, since only 16 channels have been used for compound sfx if( buf_flags & DSBCAPS_CTRL3D ) { pSO->Dup_Buffer[0] = DSLoad3DSoundBuffer(pDS, lpName, &pSO->Dup_3DBuffer[0], buf_flags ); }else{ pSO->Dup_Buffer[0] = DSLoadSoundBuffer(pDS, lpName, buf_flags ); } } if( !pSO->Dup_Buffer[ 0 ] ) { Msg("Unable to create sound buffer for %s\n", lpName ); InvalidateBuffers( pSO ); return pSO; } // get caps of buffer memset( &dsbcaps, 0, sizeof( DSBCAPS ) ); dsbcaps.dwSize = sizeof( DSBCAPS ); IDirectSoundBuffer_GetCaps( pSO->Dup_Buffer[ 0 ], &dsbcaps ); if ( dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE ) { //DebugPrintf("creating %s in hardware\n", lpName ); }else { //DebugPrintf("creating %s in software\n", lpName ); #if 0 // lock buffer IDirectSoundBuffer_Lock( pSO->Dup_Buffer[ 0 ], 0, 0, &lpvAudioPtr1, &dwAudioBytes1, &lpvAudioPtr2, &dwAudioBytes2, dwFlags ); // make non-volatile MakeRegionPresent( ( BYTE * )lpvAudioPtr1, (UINT)dwAudioBytes1 ); // unlock buffer IDirectSoundBuffer_Unlock( pSO->Dup_Buffer[ 0 ], lpvAudioPtr1, 0, lpvAudioPtr2, 0 ); #endif } // if buffer in hw, should check free channels here, but Ensoniq driver always reports back 256 // so we will just have to try duplicating until failure for (i = 1; i < MAX_DUP_BUFFERS; i++) { pSO->looping_sfx_index[i] = -1; // duplicate 2D buffer... if ( !SoundBufferDuplicate( pDS, pSO->Dup_Buffer[0], &pSO->Dup_Buffer[i]) ) { DebugPrintf("unable to duplicate sound buffer\n"); // invalidate buffer & all duplicates InvalidateBuffers( pSO ); // was original buffer hw? if so, try to recreate in sw if ( dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE ) { DebugPrintf("trying to recreate in sw\n"); FreeHWBuffers = FALSE; // recreate all buffers up to & including this one in software if( buf_flags & DSBCAPS_CTRL3D ) { pSO->Dup_Buffer[ 0 ] = DSLoad3DSoundBuffer(pDS, lpName, &pSO->Dup_3DBuffer[ 0 ], buf_flags | DSBCAPS_LOCSOFTWARE ); }else{ pSO->Dup_Buffer[ 0 ] = DSLoadSoundBuffer(pDS, lpName, buf_flags | DSBCAPS_LOCSOFTWARE ); } if( !pSO->Dup_Buffer[ 0 ] ) { Msg("Unable to create sound buffer for %s\n", lpName ); InvalidateBuffers( pSO ); return pSO; } i = 0; continue; }else { // couldn't duplicate buffer in sw - just break out with buffer info still marked as invalid Msg("unable to duplicate buffers in sw\n"); break; } } // query for 3D interface if we are using 3D... if ( pSO->Dup_3DBuffer[0] ) { hres = IDirectSoundBuffer_QueryInterface(pSO->Dup_Buffer[i], &IID_IDirectSound3DBuffer, &pSO->Dup_3DBuffer[i]); } } } } return pSO; }
soundplay_t *SND_InitPlayback(int speed, int bits) { int ret; DSBCAPS caps; DSBUFFERDESC bufdesc; LPDIRECTSOUND ds; dsplay_t *hnd; WAVEFORMATEX format; if (!hInstDS) { hInstDS = LoadLibrary("dsound.dll"); if (hInstDS == NULL) { printf ("Couldn't load dsound.dll\n"); return NULL; } pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate"); if (!pDirectSoundCreate) { printf ("Couldn't get DS proc addr\n"); return NULL; } // pDirectSoundEnumerate = (void *)GetProcAddress(hInstDS,"DirectSoundEnumerateA"); } ds = NULL; pDirectSoundCreate(NULL, &ds, NULL); if (!ds) return NULL; hnd = malloc(sizeof(*hnd)); memset(hnd, 0, sizeof(*hnd)); hnd->funcs.update = DSOUND_UpdatePlayback; hnd->funcs.close = DSOUND_Shutdown; hnd->ds = ds; hnd->sampbytes = bits/8; if (FAILED(IDirectSound_SetCooperativeLevel (hnd->ds, GetDesktopWindow(), DSSCL_EXCLUSIVE))) printf("SetCooperativeLevel failed\n"); memset(&bufdesc, 0, sizeof(bufdesc)); bufdesc.dwSize = sizeof(bufdesc); // bufdesc.dwFlags |= DSBCAPS_GLOBALFOCUS; //so we hear it if quake is loaded bufdesc.dwFlags |= DSBCAPS_PRIMARYBUFFER; //so we can set speed bufdesc.dwFlags |= DSBCAPS_CTRLVOLUME; bufdesc.lpwfxFormat = NULL; bufdesc.dwBufferBytes = 0; format.wFormatTag = WAVE_FORMAT_PCM; format.cbSize = 0; format.nChannels = 1; format.wBitsPerSample = bits; format.nSamplesPerSec = speed; format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; ret = IDirectSound_CreateSoundBuffer(hnd->ds, &bufdesc, &hnd->dsbuf, NULL); if (!hnd->dsbuf) { printf("Couldn't create primary buffer\n"); DSOUND_Shutdown(&hnd->funcs); return NULL; } if (FAILED(IDirectSoundBuffer_SetFormat(hnd->dsbuf, &format))) printf("SetFormat failed\n"); //and now make a secondary buffer bufdesc.dwFlags = 0; bufdesc.dwFlags |= DSBCAPS_CTRLFREQUENCY; bufdesc.dwFlags |= DSBCAPS_LOCSOFTWARE; bufdesc.dwFlags |= DSBCAPS_GLOBALFOCUS; bufdesc.dwBufferBytes = speed * format.nChannels * hnd->sampbytes; bufdesc.lpwfxFormat = &format; ret = IDirectSound_CreateSoundBuffer(hnd->ds, &bufdesc, &hnd->dsbuf, NULL); if (!hnd->dsbuf) { printf("Couldn't create secondary buffer\n"); DSOUND_Shutdown(&hnd->funcs); return NULL; } memset(&caps, 0, sizeof(caps)); caps.dwSize = sizeof(caps); IDirectSoundBuffer_GetCaps(hnd->dsbuf, &caps); hnd->buffersize = caps.dwBufferBytes / hnd->sampbytes; //clear out the buffer { char *buffer; int buffersize=0; IDirectSoundBuffer_Play(hnd->dsbuf, 0, 0, DSBPLAY_LOOPING); ret = IDirectSoundBuffer_Lock(hnd->dsbuf, 0, hnd->buffersize*hnd->sampbytes, (void**)&buffer, &buffersize, NULL, NULL, 0); memset(buffer, 0, buffersize); IDirectSoundBuffer_Unlock(hnd->dsbuf, buffer, buffersize, NULL, 0); IDirectSoundBuffer_Stop(hnd->dsbuf); } //DSERR_INVALIDPARAM IDirectSoundBuffer_Play(hnd->dsbuf, 0, 0, DSBPLAY_LOOPING); IDirectSoundBuffer_GetCurrentPosition(hnd->dsbuf, &hnd->readpos, &hnd->writepos); hnd->writepos = hnd->readpos + speed / 2; //position our write position a quater of a second infront of the read position printf("%i %i\n", 100*hnd->readpos / hnd->buffersize, 100*hnd->writepos / hnd->buffersize); return &hnd->funcs; }