/* * Check if there is space in playing buffer. */ static unsigned dsound_play_empty_size(struct dsound_stream *dsound_strm) { HRESULT hr; long size_available; DWORD writePos, readPos; hr = IDirectSoundBuffer_GetCurrentPosition(dsound_strm->ds.play.lpDsBuffer, &readPos, &writePos); if FAILED(hr) return PJ_FALSE; if (readPos < dsound_strm->dwBytePos) size_available = readPos + dsound_strm->dwDsBufferSize - dsound_strm->dwBytePos; else size_available = readPos - dsound_strm->dwBytePos; return size_available; }
/* SNDDMA_GetDMAPos return the current sample position (in mono samples read) inside the recirculating dma buffer, so the mixing code will know how many sample are required to fill it up. */ int SNDDMA_GetDMAPos (void) { MMTIME mmtime; int s = 0; DWORD dwWrite; if (dsound_init) { mmtime.wType = TIME_SAMPLES; IDirectSoundBuffer_GetCurrentPosition (pDSBuf, &mmtime.u.sample, &dwWrite); s = mmtime.u.sample - mmstarttime.u.sample; } else if (wav_init) { s = snd_sent * WAV_BUFFER_SIZE; } s >>= sample16; s &= (shm->samples - 1); return s; }
/* * 再生位置通知のハンドラ */ static VOID OnNotifyPlayPos(int nBuffer) { DWORD dwPlayPos; HRESULT hRet; // 再生終了領域を再生し終わった場合 if(nPosCurArea[nBuffer] == nPosEndArea[nBuffer]) { /* 再生を停止する */ IDirectSoundBuffer_Stop(pDSBuffer[nBuffer]); IDirectSoundBuffer_SetCurrentPosition(pDSBuffer[nBuffer], 0); /* ストリームを停止状態にする */ pStream[nBuffer] = NULL; return; // 再生終了 } // 再生位置を取得する hRet = IDirectSoundBuffer_GetCurrentPosition(pDSBuffer[nBuffer], &dwPlayPos, NULL); if(hRet != DS_OK) return; // 再生位置の取得に失敗した /* * 更新する領域上を再生中である場合 * - 初回の通知のときに発生する * - または、遅延がバッファN周分のとき発生する * - バッファを更新しないで次の通知を待つ * - 遅延の場合は同じ音が繰り返し再生される(壊れたCDのように) */ if(dwPlayPos >= (DWORD)nPosCurArea[nBuffer] * AREA_BYTES && dwPlayPos < ((DWORD)nPosCurArea[nBuffer] + 1) * AREA_BYTES) return; /* 更新しない */ // バッファを更新する WriteNext(nBuffer); }
static int dx_bufferspace(void) { DWORD play_cursor; int free_samples, buffer_samples; IDirectSoundBuffer_GetCurrentPosition(buffer, &play_cursor, NULL); /* We should properly distinguish between buffer empty and buffer fill * case. However, it's absolutely essential that the state where play and * write cursors overlap is read as buffer being filled with data. */ if (play_cursor < buffer_offset) { free_samples = buffer_size - (buffer_offset - play_cursor); } else { free_samples = play_cursor - buffer_offset; } SDEBUG(("play=%d, ourwrite=%d, free=%d", play_cursor, buffer_offset, free_samples)); free_samples /= (is16bit ? 2 : 1) * num_of_channels; /* test for underrun condition. It generally looks like we suddenly we have * a filled buffer instead of nearly empty one, because the play cursor * stepped over the write cursor. We generally have sound core calling * bufferspace() with every write, so we can rely on frequent calls here. */ buffer_samples = buffer_size / (is16bit ? 2 : 1) / num_of_channels; if (free_samples < fragment_size && earlier_bufferspace > buffer_samples - fragment_size) { /* don't trigger again */ earlier_bufferspace = 0; /* report underrun */ return buffer_samples; } earlier_bufferspace = free_samples; return free_samples; }
float pest_get_pos(){ unsigned __int64 time = 0; int play_pos; if(!playing) return 0; EnterCriticalSection(&critical); IDirectSoundBuffer_GetCurrentPosition( secondary, &play_pos, NULL ); time += bytes_written; if( last_known <= play_pos ){ time += play_pos - last_known; }else{ time += (BUFFER_LEN*4)-(last_known-play_pos); } LeaveCriticalSection(&critical); /* { char temp[256]; sprintf( temp, "returning time: %f", (float)((time/4)-(44100))*(1.f/44100.f)+pest_time_offset ); OutputDebugString( temp ); } */ return (float)((time/4)-(44100))*(1.f/44100.f)+pest_time_offset; }
static void DSoundRender_UpdatePositions(DSoundRenderImpl *This, DWORD *seqwritepos, DWORD *minwritepos) { WAVEFORMATEX *wfx = (WAVEFORMATEX*)This->renderer.pInputPin->pin.mtCurrent.pbFormat; BYTE *buf1, *buf2; DWORD size1, size2, playpos, writepos, old_writepos, old_playpos, adv; BOOL writepos_set = This->writepos < This->buf_size; /* Update position and zero */ old_writepos = This->writepos; old_playpos = This->last_playpos; if (old_writepos <= old_playpos) old_writepos += This->buf_size; IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, &playpos, &writepos); if (old_playpos > playpos) { adv = This->buf_size + playpos - old_playpos; This->play_time += time_from_pos(This, This->buf_size); } else adv = playpos - old_playpos; This->last_playpos = playpos; if (adv) { TRACE("Moving from %u to %u: clearing %u bytes\n", old_playpos, playpos, adv); IDirectSoundBuffer_Lock(This->dsbuffer, old_playpos, adv, (void**)&buf1, &size1, (void**)&buf2, &size2, 0); memset(buf1, wfx->wBitsPerSample == 8 ? 128 : 0, size1); memset(buf2, wfx->wBitsPerSample == 8 ? 128 : 0, size2); IDirectSoundBuffer_Unlock(This->dsbuffer, buf1, size1, buf2, size2); } *minwritepos = writepos; if (!writepos_set || old_writepos < writepos) { if (writepos_set) { This->writepos = This->buf_size; FIXME("Underrun of data occurred!\n"); } *seqwritepos = writepos; } else *seqwritepos = This->writepos; }
static uint32_t RawCanWrite(void) { DWORD CurWritePos,CurPlayPos=0; CheckDStatus(); CurWritePos=0; if(IDirectSoundBuffer_GetCurrentPosition(ppbufw,&CurPlayPos,&CurWritePos)==DS_OK) { // FCEU_DispMessage("%8d",(CurWritePos-CurPlayPos)); } CurWritePos=(CurPlayPos+BufHowMuch)%DSBufferSize; /* If the current write pos is >= half the buffer size less than the to write pos, assume DirectSound has wrapped around. */ if(((int32_t)ToWritePos-(int32_t)CurWritePos) >= (DSBufferSize/2)) { CurWritePos+=DSBufferSize; //FCEU_printf("Fixit: %d,%d,%d\n",ToWritePos,CurWritePos,CurWritePos-DSBufferSize); } if(ToWritePos<CurWritePos) { int32_t howmuch=(int32_t)CurWritePos-(int32_t)ToWritePos; if(howmuch > BufHowMuch) /* Oopsie. Severe buffer overflow... */ { //FCEU_printf("Ack"); ToWritePos=CurWritePos%DSBufferSize; } return(CurWritePos-ToWritePos); } else return(0); }
static HRESULT TimeGet( aout_stream_sys_t *sys, vlc_tick_t *delay ) { DWORD read, status; HRESULT hr; ssize_t size; hr = IDirectSoundBuffer_GetStatus( sys->p_dsbuffer, &status ); if( hr != DS_OK ) return hr; if( !(status & DSBSTATUS_PLAYING) ) return DSERR_INVALIDCALL ; hr = IDirectSoundBuffer_GetCurrentPosition( sys->p_dsbuffer, &read, NULL ); if( hr != DS_OK ) return hr; size = (ssize_t)read - sys->i_last_read; /* GetCurrentPosition cannot be trusted if the return doesn't change * Just return an error */ if( size == 0 ) return DSERR_GENERIC ; else if( size < 0 ) size += DS_BUF_SIZE; sys->i_data -= size; sys->i_last_read = read; if( sys->i_data < 0 ) /* underrun */ Flush(sys); *delay = vlc_tick_from_samples( sys->i_data / sys->i_bytes_per_sample, sys->i_rate ); return DS_OK; }
HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty ) { HRESULT hr; DWORD playCursor; DWORD writeCursor; long numBytesEmpty; long playWriteGap; // Query to see how much room is in buffer. // Note: Even though writeCursor is not used, it must be passed to prevent DirectSound from dieing // under WinNT. The Microsoft documentation says we can pass NULL but apparently not. // Thanks to Max Rheiner for the fix. hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor ); if( hr != DS_OK ) { return hr; } AddTraceMessage("playCursor", playCursor); AddTraceMessage("dsw_WriteOffset", dsw->dsw_WriteOffset); // Determine size of gap between playIndex and WriteIndex that we cannot write into. playWriteGap = writeCursor - playCursor; if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */ /* Attempt to detect playCursor wrap-around and correct it. */ if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) ) { /* How much time has elapsed since last check. */ LARGE_INTEGER currentTime; LARGE_INTEGER elapsedTime; long bytesPlayed; long bytesExpected; long buffersWrapped; QueryPerformanceCounter( ¤tTime ); elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart; dsw->dsw_LastPlayTime = currentTime; /* How many bytes does DirectSound say have been played. */ bytesPlayed = playCursor - dsw->dsw_LastPlayCursor; if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap dsw->dsw_LastPlayCursor = playCursor; /* Calculate how many bytes we would have expected to been played by now. */ bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart); buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize; if( buffersWrapped > 0 ) { AddTraceMessage("playCursor wrapped! bytesPlayed", bytesPlayed ); AddTraceMessage("playCursor wrapped! bytesExpected", bytesExpected ); playCursor += (buffersWrapped * dsw->dsw_OutputSize); bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize); } /* Maintain frame output cursor. */ dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerFrame); } numBytesEmpty = playCursor - dsw->dsw_WriteOffset; if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset /* Have we underflowed? */ if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) ) { if( dsw->dsw_OutputRunning ) { dsw->dsw_OutputUnderflows += 1; AddTraceMessage("underflow detected! numBytesEmpty", numBytesEmpty ); } dsw->dsw_WriteOffset = writeCursor; numBytesEmpty = dsw->dsw_OutputSize - playWriteGap; } *bytesEmpty = numBytesEmpty; return hr; }
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; }
void m1sdr_TimeCheck(void) { int nPlaySeg=0, nFollowingSeg=0; DWORD nPlay=0, nWrite=0; int nRet=0; if (!lpDS) return; // We should do nothing until nPlay has left nDSoundNextSeg IDirectSoundBuffer_GetCurrentPosition(lpSecB, &nPlay, &nWrite); nPlaySeg=nPlay/(nDSoundSegLen<<2); if (nPlaySeg>nDSoundSegCount-1) nPlaySeg=nDSoundSegCount-1; if (nPlaySeg<0) nPlaySeg=0; // important to ensure nPlaySeg clipped for below if (nDSoundNextSeg == nPlaySeg) { Sleep(200); // Don't need to do anything for a bit goto End; } // work out which seg we will fill next nFollowingSeg = nDSoundNextSeg; WRAP_INC(nFollowingSeg) while (nDSoundNextSeg != nPlaySeg) { void *pData=NULL,*pData2=NULL; DWORD cbLen=0,cbLen2=0; // fill nNextSeg // Lock the relevant seg of the loop buffer nRet = IDirectSoundBuffer_Lock(lpSecB, nDSoundNextSeg*(nDSoundSegLen<<2), nDSoundSegLen<<2, &pData, &cbLen, &pData2, &cbLen2, 0); if (nRet>=0 && pData!=NULL) { // Locked the seg okay - write the sound we calculated last time memcpy(pData, samples, nDSoundSegLen<<2); } // Unlock (2nd 0 is because we wrote nothing to second part) if (nRet>=0) IDirectSoundBuffer_Unlock(lpSecB, pData, cbLen, pData2, 0); // generate more samples if ((m1sdr_Callback) && (!oss_pause)) { //printf("callback: %ld samples\n", samples); m1sdr_Callback(nDSoundSegLen, samples); } else { memset(samples, 0, nDSoundSegLen*4); } waveLogFrame((unsigned char *)samples, nDSoundSegLen<<2); nDSoundNextSeg = nFollowingSeg; WRAP_INC(nFollowingSeg) } End: return; }
static HRESULT WINAPI PrimaryBufferImpl_Lock( LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID *lplpaudioptr1,LPDWORD audiobytes1,LPVOID *lplpaudioptr2,LPDWORD audiobytes2,DWORD flags ) { HRESULT hres; IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface); DirectSoundDevice *device = This->device; TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", iface, writecursor, writebytes, lplpaudioptr1, audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount() ); if (!audiobytes1) return DSERR_INVALIDPARAM; if (device->priolevel != DSSCL_WRITEPRIMARY) { WARN("failed priority check!\n"); return DSERR_PRIOLEVELNEEDED; } /* when this flag is set, writecursor is meaningless and must be calculated */ if (flags & DSBLOCK_FROMWRITECURSOR) { /* GetCurrentPosition does too much magic to duplicate here */ hres = IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writecursor); if (hres != DS_OK) { WARN("IDirectSoundBuffer_GetCurrentPosition failed\n"); return hres; } } /* when this flag is set, writebytes is meaningless and must be set */ if (flags & DSBLOCK_ENTIREBUFFER) writebytes = device->buflen; if (writecursor >= device->buflen) { WARN("Invalid parameter, writecursor: %u >= buflen: %u\n", writecursor, device->buflen); return DSERR_INVALIDPARAM; } if (writebytes > device->buflen) { WARN("Invalid parameter, writebytes: %u > buflen: %u\n", writebytes, device->buflen); return DSERR_INVALIDPARAM; } if (writecursor+writebytes <= device->buflen) { *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor; *audiobytes1 = writebytes; if (lplpaudioptr2) *(LPBYTE*)lplpaudioptr2 = NULL; if (audiobytes2) *audiobytes2 = 0; TRACE("->%d.0\n",writebytes); } else { *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor; *audiobytes1 = device->buflen-writecursor; if (lplpaudioptr2) *(LPBYTE*)lplpaudioptr2 = device->buffer; if (audiobytes2) *audiobytes2 = writebytes-(device->buflen-writecursor); TRACE("->%d.%d\n",*audiobytes1,audiobytes2?*audiobytes2:0); } return DS_OK; }
static INLINE void get_positions(dsound_t *ds, DWORD *read_ptr, DWORD *write_ptr) { IDirectSoundBuffer_GetCurrentPosition(ds->dsb, read_ptr, write_ptr); }
static int dsound_run_out (HWVoiceOut *hw, int live) { int err; HRESULT hr; DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; int len, hwshift; DWORD blen1, blen2; DWORD len1, len2; DWORD decr; DWORD wpos, ppos, old_pos; LPVOID p1, p2; int bufsize; dsound *s = ds->s; DSoundConf *conf = &s->conf; if (!dsb) { dolog ("Attempt to run empty with playback buffer\n"); return 0; } hwshift = hw->info.shift; bufsize = hw->samples << hwshift; hr = IDirectSoundBuffer_GetCurrentPosition ( dsb, &ppos, ds->first_time ? &wpos : NULL ); if (FAILED (hr)) { dsound_logerr (hr, "Could not get playback buffer position\n"); return 0; } len = live << hwshift; if (ds->first_time) { if (conf->latency_millis) { DWORD cur_blat; cur_blat = audio_ring_dist (wpos, ppos, bufsize); ds->first_time = 0; old_pos = wpos; old_pos += millis_to_bytes (&hw->info, conf->latency_millis) - cur_blat; old_pos %= bufsize; old_pos &= ~hw->info.align; } else { old_pos = wpos; } #ifdef DEBUG_DSOUND ds->played = 0; ds->mixed = 0; #endif } else { if (ds->old_pos == ppos) { #ifdef DEBUG_DSOUND dolog ("old_pos == ppos\n"); #endif return 0; } #ifdef DEBUG_DSOUND ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize); #endif old_pos = ds->old_pos; } if ((old_pos < ppos) && ((old_pos + len) > ppos)) { len = ppos - old_pos; } else { if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) { len = bufsize - old_pos + ppos; } } if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) { dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n", len, bufsize, old_pos, ppos); return 0; } len &= ~hw->info.align; if (!len) { return 0; } #ifdef DEBUG_DSOUND ds->old_ppos = ppos; #endif err = dsound_lock_out ( dsb, &hw->info, old_pos, len, &p1, &p2, &blen1, &blen2, 0, s ); if (err) { return 0; } len1 = blen1 >> hwshift; len2 = blen2 >> hwshift; decr = len1 + len2; if (p1 && len1) { dsound_write_sample (hw, p1, len1); } if (p2 && len2) { dsound_write_sample (hw, p2, len2); } dsound_unlock_out (dsb, p1, p2, blen1, blen2); ds->old_pos = (old_pos + (decr << hwshift)) % bufsize; #ifdef DEBUG_DSOUND ds->mixed += decr << hwshift; dolog ("played %lu mixed %lu diff %ld sec %f\n", ds->played, ds->mixed, ds->mixed - ds->played, abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second); #endif return decr; }
DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter) { fluid_dsound_audio_driver_t* dev = (fluid_dsound_audio_driver_t*) lpParameter; short *buf1, *buf2; DWORD bytes1, bytes2; DWORD cur_position, frames, play_position, write_position, bytes; HRESULT res; cur_position = 0; /* boost the priority of the audio thread */ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); IDirectSoundBuffer_Play(dev->sec_buffer, 0, 0, DSBPLAY_LOOPING); while (dev->cont) { IDirectSoundBuffer_GetCurrentPosition(dev->sec_buffer, &play_position, &write_position); if (cur_position <= play_position) { bytes = play_position - cur_position; } else if ((play_position < cur_position) && (write_position <= cur_position)) { bytes = dev->queue_byte_size + play_position - cur_position; } else { bytes = 0; } if (bytes >= dev->buffer_byte_size) { /* Lock */ res = IDirectSoundBuffer_Lock(dev->sec_buffer, cur_position, bytes, (void*) &buf1, &bytes1, (void*) &buf2, &bytes2, 0); if ((res != DS_OK) || (buf1 == NULL)) { FLUID_LOG(FLUID_PANIC, "Failed to lock the audio buffer. System lockup might follow. Exiting."); ExitProcess(0); } /* fill the first part of the buffer */ if (bytes1 > 0) { frames = bytes1 / dev->frame_size; dev->write(dev->synth, frames, buf1, 0, 2, buf1, 1, 2); cur_position += frames * dev->frame_size; } /* fill the second part of the buffer */ if ((buf2 != NULL) && (bytes2 > 0)) { frames = bytes2 / dev->frame_size; dev->write(dev->synth, frames, buf2, 0, 2, buf2, 1, 2); cur_position += frames * dev->frame_size; } /* Unlock */ IDirectSoundBuffer_Unlock(dev->sec_buffer, buf1, bytes1, buf2, bytes2); if (cur_position >= dev->queue_byte_size) { cur_position -= dev->queue_byte_size; } } else { Sleep(1); } } ExitThread(0); return 0; /* never reached */ }
static HRESULT test_block_align(LPGUID lpGuid) { HRESULT rc; LPDIRECTSOUND dso=NULL; LPDIRECTSOUNDBUFFER secondary=NULL; DSBUFFERDESC bufdesc; DSBCAPS dsbcaps; WAVEFORMATEX wfx; DWORD pos, pos2; int ref; /* Create the DirectSound object */ rc=pDirectSoundCreate(lpGuid,&dso,NULL); ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, "DirectSoundCreate() failed: %08x\n",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: %08x\n", 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: %08x\n", rc); if (rc==DS_OK && wfx.nBlockAlign > 1) { ok(dsbcaps.dwBufferBytes==(wfx.nAvgBytesPerSec + wfx.nBlockAlign), "Buffer size not a multiple of nBlockAlign: requested %d, " "got %d, should be %d\n", bufdesc.dwBufferBytes, dsbcaps.dwBufferBytes, wfx.nAvgBytesPerSec + wfx.nBlockAlign); rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 0); ok(rc == DS_OK, "Could not set position to 0: %08x\n", rc); rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos, NULL); ok(rc == DS_OK, "Could not get position: %08x\n", rc); rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 1); ok(rc == DS_OK, "Could not set position to 1: %08x\n", rc); rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos2, NULL); ok(rc == DS_OK, "Could not get new position: %08x\n", rc); ok(pos == pos2, "Positions not the same! Old position: %d, new position: %d\n", pos, pos2); } 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 guint gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length) { GstDirectSoundSink *dsoundsink; DWORD dwStatus; HRESULT hRes; LPVOID pLockedBuffer1 = NULL, pLockedBuffer2 = NULL; DWORD dwSizeBuffer1, dwSizeBuffer2; DWORD dwCurrentPlayCursor; dsoundsink = GST_DIRECTSOUND_SINK (asink); /* Fix endianness */ if (dsoundsink->buffer_format == GST_IEC958) _swab (data, data, length); GST_DSOUND_LOCK (dsoundsink); /* get current buffer status */ hRes = IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus); /* get current play cursor position */ hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary, &dwCurrentPlayCursor, NULL); if (SUCCEEDED (hRes) && (dwStatus & DSBSTATUS_PLAYING)) { DWORD dwFreeBufferSize; calculate_freesize: /* calculate the free size of the circular buffer */ if (dwCurrentPlayCursor < dsoundsink->current_circular_offset) dwFreeBufferSize = dsoundsink->buffer_size - (dsoundsink->current_circular_offset - dwCurrentPlayCursor); else dwFreeBufferSize = dwCurrentPlayCursor - dsoundsink->current_circular_offset; if (length >= dwFreeBufferSize) { Sleep (100); hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary, &dwCurrentPlayCursor, NULL); hRes = IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus); if (SUCCEEDED (hRes) && (dwStatus & DSBSTATUS_PLAYING)) goto calculate_freesize; else { dsoundsink->first_buffer_after_reset = FALSE; GST_DSOUND_UNLOCK (dsoundsink); return 0; } } } if (dwStatus & DSBSTATUS_BUFFERLOST) { hRes = IDirectSoundBuffer_Restore (dsoundsink->pDSBSecondary); /*need a loop waiting the buffer is restored?? */ dsoundsink->current_circular_offset = 0; } hRes = IDirectSoundBuffer_Lock (dsoundsink->pDSBSecondary, dsoundsink->current_circular_offset, length, &pLockedBuffer1, &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L); if (SUCCEEDED (hRes)) { // Write to pointers without reordering. memcpy (pLockedBuffer1, data, dwSizeBuffer1); if (pLockedBuffer2 != NULL) memcpy (pLockedBuffer2, (LPBYTE) data + dwSizeBuffer1, dwSizeBuffer2); // Update where the buffer will lock (for next time) dsoundsink->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2; dsoundsink->current_circular_offset %= dsoundsink->buffer_size; /* Circular buffer */ hRes = IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer1, dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2); } /* if the buffer was not in playing state yet, call play on the buffer except if this buffer is the fist after a reset (base class call reset and write a buffer when setting the sink to pause) */ if (!(dwStatus & DSBSTATUS_PLAYING) && dsoundsink->first_buffer_after_reset == FALSE) { hRes = IDirectSoundBuffer_Play (dsoundsink->pDSBSecondary, 0, 0, DSBPLAY_LOOPING); } dsoundsink->first_buffer_after_reset = FALSE; GST_DSOUND_UNLOCK (dsoundsink); return length; }
DWORD WINAPI pest_thread_proc( LPVOID jalla ){ short *buffer1; short *buffer2; int play_pos; DWORD len1; DWORD len2; ready_to_quit = FALSE; if(done) return 0; done = FALSE; SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); IDirectSoundBuffer_Lock( secondary, 0, BUFFER_LEN*4, (void**)&buffer1, &len1, (void**)&buffer2, &len2, DSBLOCK_ENTIREBUFFER); bytes_written = fill_buffer( buffer1, len1 ); if(buffer2) bytes_written+= fill_buffer( buffer2, len2 ); EnterCriticalSection(&critical); last_known = (int)(bytes_written%(BUFFER_LEN*4)); LeaveCriticalSection(&critical); IDirectSoundBuffer_Unlock(secondary,(void*)buffer1,len1,(void*)buffer2,len2); IDirectSoundBuffer_SetCurrentPosition(secondary, 0); IDirectSoundBuffer_Play(secondary, 0, 0, DSBPLAY_LOOPING); playing = TRUE; Sleep(100); while( !done ) { short buffer[BUFFER_LEN*2]; int to_write; DWORD written; IDirectSoundBuffer_GetCurrentPosition( secondary, &play_pos, NULL ); if( last_known < play_pos ){ to_write = play_pos - last_known; OutputDebugString( "Last known smaller than play pos" ); }else{ to_write = (BUFFER_LEN*4)-(last_known-play_pos); } while( IDirectSoundBuffer_Lock( secondary, last_known, to_write, (void**)&buffer1, &len1, (void**)&buffer2, &len2, 0)!=DS_OK){ OutputDebugString("Trying to restore"); IDirectSoundBuffer_Restore( secondary ); IDirectSoundBuffer_Play( secondary, 0, 0, DSBPLAY_LOOPING); } written = fill_buffer( (short*)buffer, len1+len2 ); memcpy(buffer1,buffer,len1); if(written>len1) memcpy(buffer2,(char*)buffer+len1,written-len1); IDirectSoundBuffer_Unlock( secondary, (void*)buffer1, len1, (void*)buffer2, len2 ); EnterCriticalSection(&critical); bytes_written += written; last_known = (int)(bytes_written%(BUFFER_LEN*4)); LeaveCriticalSection(&critical); Sleep(100); } playing=FALSE; ready_to_quit=TRUE; DeleteCriticalSection(&critical); return 0; }
static int ds_rsd_open(void* data, wav_header_t *w) { ds_t* ds = data; if (DirectSoundCreate(NULL, &ds->ds, NULL) != DS_OK) return -1; if (IDirectSound_SetCooperativeLevel(ds->ds, GetDesktopWindow(), DSSCL_NORMAL) != DS_OK) return -1; int bits = 16; ds->fmt = w->rsd_format; ds->conv = converter_fmt_to_s16ne(w->rsd_format); ds->rings = 16; ds->latency = DEFAULT_CHUNK_SIZE * 2; WAVEFORMATEX wfx = { .wFormatTag = WAVE_FORMAT_PCM, .nChannels = w->numChannels, .nSamplesPerSec = w->sampleRate, .wBitsPerSample = bits, .nBlockAlign = w->numChannels * bits / 8, .nAvgBytesPerSec = w->sampleRate * w->numChannels * bits / 8, }; DSBUFFERDESC bufdesc = { .dwSize = sizeof(DSBUFFERDESC), .dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS, .dwBufferBytes = ds->rings * ds->latency, .lpwfxFormat = &wfx, }; if (IDirectSound_CreateSoundBuffer(ds->ds, &bufdesc, &ds->dsb, 0) != DS_OK) return -1; IDirectSoundBuffer_SetCurrentPosition(ds->dsb, 0); clear_buffers(ds); IDirectSoundBuffer_Play(ds->dsb, 0, 0, DSBPLAY_LOOPING); return 0; } static size_t ds_rsd_write(void *data, const void* inbuf, size_t size) { ds_t *ds = data; size_t osize = size; uint8_t convbuf[2 * size]; const uint8_t *buffer_ptr = inbuf; if (ds->conv != RSD_NULL) { if (rsnd_format_to_bytes(ds->fmt) == 1) osize = 2 * size; else if (rsnd_format_to_bytes(ds->fmt) == 4) osize = size / 2; memcpy(convbuf, inbuf, size); audio_converter(convbuf, ds->fmt, ds->conv, size); buffer_ptr = convbuf; } // With this approach we are prone to underruns which would "ring", // but the RSound API does not really encourage letting stuff underrun anyways. ds->writering = (ds->writering + 1) % ds->rings; for (;;) { DWORD pos; IDirectSoundBuffer_GetCurrentPosition(ds->dsb, &pos, 0); unsigned activering = pos / ds->latency; if (activering != ds->writering) break; Sleep(1); } void *output1, *output2; DWORD size1, size2; HRESULT res; if ((res = IDirectSoundBuffer_Lock(ds->dsb, ds->writering * ds->latency, osize, &output1, &size1, &output2, &size2, 0)) != DS_OK) { if (res != DSERR_BUFFERLOST) return 0; if (IDirectSoundBuffer_Restore(ds->dsb) != DS_OK) return 0; if (IDirectSoundBuffer_Lock(ds->dsb, ds->writering * ds->latency, osize, &output1, &size1, &output2, &size2, 0) != DS_OK) return 0; } memcpy(output1, buffer_ptr, size1); memcpy(output2, buffer_ptr + size1, size2); IDirectSoundBuffer_Unlock(ds->dsb, output1, size1, output2, size2); return size; } static int ds_rsd_latency(void* data) { ds_t *ds = data; DWORD pos; IDirectSoundBuffer_GetCurrentPosition(ds->dsb, &pos, 0); DWORD next_writepos = ((ds->writering + 1) % ds->rings) * ds->latency; if (next_writepos <= pos) next_writepos += ds->rings * ds->latency; int delta = next_writepos - pos; if (rsnd_format_to_bytes(ds->fmt) == 1) delta /= 2; else if (rsnd_format_to_bytes(ds->fmt) == 4) delta *= 2; return delta; }
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; }
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; }
HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer ) { DWORD dwDataLen; DWORD playCursor; HRESULT result; LPDIRECTSOUNDBUFFER pPrimaryBuffer; HWND hWnd; HRESULT hr; WAVEFORMATEX wfFormat; DSBUFFERDESC primaryDesc; DSBUFFERDESC secondaryDesc; unsigned char* pDSBuffData; LARGE_INTEGER counterFrequency; dsw->dsw_OutputSize = bytesPerBuffer; dsw->dsw_OutputRunning = FALSE; dsw->dsw_OutputUnderflows = 0; dsw->dsw_FramesWritten = 0; dsw->dsw_BytesPerFrame = nChannels * sizeof(short); // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the // applications's window. Also if that window is closed before the Buffer is closed // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.) // So we will use GetDesktopWindow() which was suggested by Miller Puckette. // hWnd = GetForegroundWindow(); hWnd = GetDesktopWindow(); // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz. // Exclusize also prevents unexpected sounds from other apps during a performance. if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound, hWnd, DSSCL_EXCLUSIVE)) != DS_OK) { return hr; } // ----------------------------------------------------------------------- // Create primary buffer and set format just so we can specify our custom format. // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz. // Setup the primary buffer description ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC)); primaryDesc.dwSize = sizeof(DSBUFFERDESC); primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth primaryDesc.dwBufferBytes = 0; primaryDesc.lpwfxFormat = NULL; // Create the buffer if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound, &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result; // Define the buffer format wfFormat.wFormatTag = WAVE_FORMAT_PCM; wfFormat.nChannels = nChannels; wfFormat.nSamplesPerSec = nFrameRate; wfFormat.wBitsPerSample = 8 * sizeof(short); wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8; wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; wfFormat.cbSize = 0; /* No extended format info. */ // Set the primary buffer's format if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result; // ---------------------------------------------------------------------- // Setup the secondary buffer description ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC)); secondaryDesc.dwSize = sizeof(DSBUFFERDESC); secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; secondaryDesc.dwBufferBytes = bytesPerBuffer; secondaryDesc.lpwfxFormat = &wfFormat; // Create the secondary buffer if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound, &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result; // Lock the DS buffer if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData, &dwDataLen, NULL, 0, 0)) != DS_OK) return result; // Zero the DS buffer ZeroMemory(pDSBuffData, dwDataLen); // Unlock the DS buffer if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result; if( QueryPerformanceFrequency( &counterFrequency ) ) { int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short)); dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate; AddTraceMessage("dsw_CounterTicksPerBuffer = %d\n", dsw->dsw_CounterTicksPerBuffer.LowPart ); } else { dsw->dsw_CounterTicksPerBuffer.QuadPart = 0; } // Let DSound set the starting write position because if we set it to zero, it looks like the // buffer is full to begin with. This causes a long pause before sound starts when using large buffers. hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset ); if( hr != DS_OK ) { return hr; } dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerFrame; /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */ return DS_OK; }
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; }
/* SNDDMA_InitDirect Direct-Sound support */ sndinitstat SNDDMA_InitDirect (void) { DSBUFFERDESC dsbuf; DSBCAPS dsbcaps; DWORD dwSize, dwWrite; DSCAPS dscaps; WAVEFORMATEX format, pformat; HRESULT hresult; int reps; memset ((void *) &sn, 0, sizeof (sn)); shm = &sn; shm->channels = 2; shm->samplebits = 16; shm->speed = 11025; memset (&format, 0, sizeof (format)); format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = shm->channels; format.wBitsPerSample = shm->samplebits; format.nSamplesPerSec = shm->speed; format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; format.cbSize = 0; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; if (!hInstDS) { hInstDS = LoadLibrary ("dsound.dll"); if (hInstDS == NULL) { Con_Printf ("Couldn't load dsound.dll\n"); return SIS_FAILURE; } pDirectSoundCreate = (void *) GetProcAddress (hInstDS, "DirectSoundCreate"); if (!pDirectSoundCreate) { Con_Printf ("Couldn't get DS proc addr\n"); return SIS_FAILURE; } } while ((hresult = iDirectSoundCreate (NULL, &pDS, NULL)) != DS_OK) { if (hresult != DSERR_ALLOCATED) { Con_Printf ("DirectSound create failed\n"); return SIS_FAILURE; } Con_Printf ("DirectSoundCreate failure\n" " hardware already in use\n"); return SIS_NOTAVAIL; } dscaps.dwSize = sizeof (dscaps); if (DS_OK != IDirectSound_GetCaps (pDS, &dscaps)) { Con_Printf ("Couldn't get DS caps\n"); } if (dscaps.dwFlags & DSCAPS_EMULDRIVER) { Con_Printf ("No DirectSound driver installed\n"); FreeSound (); return SIS_FAILURE; } if (DS_OK != IDirectSound_SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE)) { Con_Printf ("Set coop level failed\n"); FreeSound (); 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; if (!COM_CheckParm ("-snoforceformat")) { if (DS_OK == IDirectSound_CreateSoundBuffer (pDS, &dsbuf, &pDSPBuf, NULL)) { pformat = format; if (DS_OK != IDirectSoundBuffer_SetFormat (pDSPBuf, &pformat)) { } else primary_format_set = true; } } if (!primary_format_set || !COM_CheckParm ("-primarysound")) { // 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; dsbuf.lpwfxFormat = &format; memset (&dsbcaps, 0, sizeof (dsbcaps)); dsbcaps.dwSize = sizeof (dsbcaps); if (DS_OK != IDirectSound_CreateSoundBuffer (pDS, &dsbuf, &pDSBuf, NULL)) { Con_Printf ("DS:CreateSoundBuffer Failed"); FreeSound (); return SIS_FAILURE; } shm->channels = format.nChannels; shm->samplebits = format.wBitsPerSample; shm->speed = format.nSamplesPerSec; if (DS_OK != IDirectSound_GetCaps (pDSBuf, &dsbcaps)) { Con_Printf ("DS:GetCaps failed\n"); FreeSound (); return SIS_FAILURE; } } else { if (DS_OK != IDirectSound_SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY)) { Con_Printf ("Set coop level failed\n"); FreeSound (); return SIS_FAILURE; } if (DS_OK != IDirectSound_GetCaps (pDSPBuf, &dsbcaps)) { Con_Printf ("DS:GetCaps failed\n"); return SIS_FAILURE; } pDSBuf = pDSPBuf; } // Make sure mixer is active IDirectSoundBuffer_Play (pDSBuf, 0, 0, DSBPLAY_LOOPING); 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_Printf ("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); FreeSound (); return SIS_FAILURE; } if (++reps > 10000) { Con_Printf ("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); FreeSound (); return SIS_FAILURE; } } memset (lpData, 0, dwSize); // lpData[4] = lpData[5] = 0x7f; // force a pop for debugging IDirectSoundBuffer_Unlock (pDSBuf, lpData, dwSize, NULL, 0); /* we don't want anyone to access the buffer directly w/o locking it first. */ lpData = NULL; IDirectSoundBuffer_Stop (pDSBuf); IDirectSoundBuffer_GetCurrentPosition (pDSBuf, &mmstarttime.u.sample, &dwWrite); IDirectSoundBuffer_Play (pDSBuf, 0, 0, DSBPLAY_LOOPING); shm->soundalive = true; shm->splitbuffer = false; shm->samples = gSndBufSize / (shm->samplebits / 8); shm->samplepos = 0; shm->submission_chunk = 1; shm->buffer = (unsigned char *) lpData; sample16 = (shm->samplebits / 8) - 1; dsound_init = true; return SIS_SUCCESS; }
static DWORD WINAPI bufferLoop(void *param) { HANDLE handles[2] = { g_dsound.tickev, g_dsound.exitev }; while (WaitForMultipleObjects(2, handles, FALSE, BUFFERLEN/3000) != WAIT_OBJECT_0 + 1) // while not exit { EnterCriticalSection(&g_dsound.crsec); void *buf1, *buf2; DWORD len1, len2; // fetch current buffer pos DWORD curpos; int nwrite = 0; for (;;) { HRESULT hr = IDirectSoundBuffer_GetCurrentPosition(g_dsound.sbuf, &curpos, NULL); if (hr == S_OK) { // find out how many bytes to write curpos &= ~31u; if (curpos == g_dsound.lastpos) goto done; // still the same nwrite = curpos - g_dsound.lastpos; if (nwrite < 0) { nwrite += BUFFERLEN; printf("positivizing nwrite\n"); } printf("nwrite = %i\n", nwrite); hr = IDirectSoundBuffer_Lock(g_dsound.sbuf, g_dsound.lastpos, nwrite, &buf1, &len1, &buf2, &len2, 0); } if (hr == S_OK) break; else if (hr == DSERR_BUFFERLOST) { printf("buffer lost!\n"); IDirectSoundBuffer_Restore(g_dsound.sbuf); } else { printf("something else went wrong\n"); goto done; } } // we got the lock printf("got lock\n"); g_dsound.lastpos = curpos; g_dsound.bufcnt += nwrite; // render to mix buffer g_dsound.callback(g_dsound.mixbuffer, nwrite / 2); // float->int, clamp //if (buf1) // clamp(buf1, g_dsound.mixbuffer, len1/2); //if (buf2) // clamp(buf2, g_dsound.mixbuffer + len1/2, len2/2); if (buf1) { printf("buf1: %d\n", len1); memcpy(buf1, g_dsound.mixbuffer, len1); } if (buf2) { printf("buf2: %d\n", len2); memcpy(buf2, g_dsound.mixbuffer + len1/2, len2); } HRESULT hr = IDirectSoundBuffer_Unlock(g_dsound.sbuf, buf1, len1, buf2, len2); if (!hr) { printf("unlock result: %i\n", hr); } done: LeaveCriticalSection(&g_dsound.crsec); } return 0; }
static ALuint DSoundProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; DSoundData *pData = (DSoundData*)pDevice->ExtraData; DWORD LastCursor = 0; DWORD PlayCursor; VOID *WritePtr1, *WritePtr2; DWORD WriteCnt1, WriteCnt2; DWORD BufferSize; DWORD avail; HRESULT err; BufferSize = pDevice->UpdateSize * DS_FRAGS * aluBytesFromFormat(pDevice->Format) * aluChannelsFromFormat(pDevice->Format); while(!pData->killNow) { // Get current play and write cursors IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); avail = (PlayCursor-LastCursor+BufferSize) % BufferSize; if(avail == 0) { Sleep(1); continue; } // 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 SuspendContext(NULL); aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format); aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format); ProcessContext(NULL); // 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 %= BufferSize; } return 0; }
static void DirectSound_update_audio(void) { HRESULT hr; int next_voice_pos; VOID *area1,*area2; DWORD len_area1,len_area2; if (dsb == NULL || new_sound_data == FALSE) return; profiler_mark(PROFILER_MIXER); next_voice_pos = voice_pos + stream_cache_len*sizeof(INT16)*stereo_factor; if (next_voice_pos >= buffer_length) next_voice_pos -= buffer_length; if (Display_Throttled()) /* sync with audio only when speed throttling is not turned off */ { profiler_mark(PROFILER_IDLE); for (;;) { LONG curpos; LONG writepos; IDirectSoundBuffer_GetCurrentPosition(dsb,&curpos,&writepos); if (voice_pos < next_voice_pos) { if (curpos < voice_pos || curpos >= next_voice_pos) break; } else { if (curpos < voice_pos && curpos >= next_voice_pos) break; } } profiler_mark(PROFILER_END); } hr = IDirectSoundBuffer_Lock(dsb, voice_pos, stream_cache_len * sizeof(INT16) * stereo_factor, &area1, &len_area1, &area2, &len_area2, 0); if (FAILED(hr)) { ErrorMsg("Unable to lock secondary sound buffer: %s",DirectXDecodeError(hr)); } else { memcpy(area1, stream_cache_data, len_area1); memcpy(area2, ((byte *)stream_cache_data) + len_area1, len_area2); hr = IDirectSoundBuffer_Unlock(dsb,area1,len_area1,area2,len_area2); if (FAILED(hr)) ErrorMsg("Unable to unlock secondary sound buffer: %s",DirectXDecodeError(hr)); } voice_pos = next_voice_pos; profiler_mark(PROFILER_END); new_sound_data = FALSE; }