void DXAudioInput::run() { LPDIRECTSOUNDCAPTURE8 pDSCapture; LPDIRECTSOUNDCAPTUREBUFFER pDSCaptureBuffer; LPDIRECTSOUNDNOTIFY8 pDSNotify; DWORD dwBufferSize; bool bOk; DWORD dwReadyBytes = 0; DWORD dwLastReadPos = 0; DWORD dwReadPosition; DWORD dwCapturePosition; LPVOID aptr1, aptr2; DWORD nbytes1, nbytes2; HRESULT hr; WAVEFORMATEX wfx; DSCBUFFERDESC dscbd; pDSCapture = NULL; pDSCaptureBuffer = NULL; pDSNotify = NULL; bOk = false; bool failed = false; float safety = 2.0f; bool didsleep = false; bool firstsleep = false; Timer t; ZeroMemory(&wfx, sizeof(wfx)); wfx.wFormatTag = WAVE_FORMAT_PCM; ZeroMemory(&dscbd, sizeof(dscbd)); dscbd.dwSize = sizeof(dscbd); dscbd.dwBufferBytes = dwBufferSize = iFrameSize * sizeof(short) * NBUFFBLOCKS; dscbd.lpwfxFormat = &wfx; wfx.nChannels = 1; wfx.nSamplesPerSec = iSampleRate; wfx.nBlockAlign = 2; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.wBitsPerSample = 16; // Create IDirectSoundCapture using the preferred capture device if (! g.s.qbaDXInput.isEmpty()) { LPGUID lpguid = reinterpret_cast<LPGUID>(g.s.qbaDXInput.data()); if (FAILED(hr = DirectSoundCaptureCreate8(lpguid, &pDSCapture, NULL))) { failed = true; } } if (! pDSCapture && FAILED(hr = DirectSoundCaptureCreate8(&DSDEVID_DefaultVoiceCapture, &pDSCapture, NULL))) qWarning("DXAudioInput: DirectSoundCaptureCreate failed: hr=0x%08lx", hr); else if (FAILED(hr = pDSCapture->CreateCaptureBuffer(&dscbd, &pDSCaptureBuffer, NULL))) qWarning("DXAudioInput: CreateCaptureBuffer failed: hr=0x%08lx", hr); else if (FAILED(hr = pDSCaptureBuffer->QueryInterface(IID_IDirectSoundNotify, reinterpret_cast<void **>(&pDSNotify)))) qWarning("DXAudioInput: QueryInterface (Notify) failed: hr=0x%08lx", hr); else bOk = true; if (failed) g.mw->msgBox(tr("Opening chosen DirectSound Input failed. Default device will be used.")); qWarning("DXAudioInput: Initialized"); if (! bOk) goto cleanup; if (FAILED(hr = pDSCaptureBuffer->Start(DSCBSTART_LOOPING))) { qWarning("DXAudioInput: Start failed: hr=0x%08lx", hr); } else { while (bRunning) { firstsleep = true; didsleep = false; do { if (FAILED(hr = pDSCaptureBuffer->GetCurrentPosition(&dwCapturePosition, &dwReadPosition))) { qWarning("DXAudioInput: GetCurrentPosition failed: hr=0x%08lx", hr); bRunning = false; break; } if (dwReadPosition < dwLastReadPos) dwReadyBytes = (dwBufferSize - dwLastReadPos) + dwReadPosition; else dwReadyBytes = dwReadPosition - dwLastReadPos; if (static_cast<int>(dwReadyBytes) < sizeof(short) * iFrameSize) { double msecleft = 20.0 - (dwReadyBytes * 20.0) / (sizeof(short) * iFrameSize); if (didsleep) safety *= 1.1f; else if (firstsleep) safety *= 0.998f; int msec = static_cast<int>(msecleft + (firstsleep ? safety : 0.0)); msleep(msec); didsleep = true; firstsleep = false; } } while (static_cast<int>(dwReadyBytes) < sizeof(short) * iFrameSize); // Desynchonized? if (dwReadyBytes > (dwBufferSize / 2)) { qWarning("DXAudioInput: Lost synchronization"); dwLastReadPos = dwReadPosition; } else if (bRunning) { if (FAILED(hr = pDSCaptureBuffer->Lock(dwLastReadPos, sizeof(short) * iFrameSize, &aptr1, &nbytes1, &aptr2, &nbytes2, 0))) { qWarning("DXAudioInput: Lock from %ld (%d bytes) failed: hr=0x%08lx",dwLastReadPos, sizeof(short) * iFrameSize, hr); bRunning = false; break; } if (aptr1 && nbytes1) CopyMemory(psMic, aptr1, nbytes1); if (aptr2 && nbytes2) CopyMemory(psMic+nbytes1/2, aptr2, nbytes2); if (FAILED(hr = pDSCaptureBuffer->Unlock(aptr1, nbytes1, aptr2, nbytes2))) { qWarning("DXAudioInput: Unlock failed: hr=0x%08lx", hr); bRunning = false; break; } dwLastReadPos = (dwLastReadPos + sizeof(short) * iFrameSize) % dwBufferSize; encodeAudioFrame(); } } if (! FAILED(hr)) pDSCaptureBuffer->Stop(); } if (FAILED(hr)) { g.mw->msgBox(tr("Lost DirectSound input device.")); } cleanup: if (! bOk) { g.mw->msgBox(tr("Opening chosen DirectSound Input device failed. No microphone capture will be done.")); } if (pDSNotify) pDSNotify->Release(); if (pDSCaptureBuffer) pDSCaptureBuffer->Release(); if (pDSCapture) pDSCapture->Release(); }
uae_u8 sampler_getsample (int channel) { #if 0 int cur_pos; static int cap_pos; static float diffsample; #endif static double doffset_offset; HRESULT hr; DWORD t; void *p1, *p2; DWORD len1, len2; evt cycles; int sample, samplecnt; double doffset; int offset; if (!currprefs.sampler_stereo) channel = 0; if (!inited) { DWORD pos; if (!capture_init ()) { capture_free (); return 0; } inited = 1; oldcycles = get_cycles (); oldoffset = -1; doffset_offset = 0; hr = lpDSB2r->GetCurrentPosition (&t, &pos); if (FAILED (hr)) { sampler_free (); return 0; } if (t >= pos) safediff = t - pos; else safediff = recordbufferframes * SAMPLESIZE - pos + t; write_log (_T("SAMPLER: safediff %d %d\n"), safediff, safediff + sampleframes * SAMPLESIZE); safediff += 4 * sampleframes * SAMPLESIZE; #if 0 diffsample = 0; safepos = -recordbufferframes / 10 * SAMPLESIZE; hr = lpDSB2r->GetCurrentPosition (&t, &pos); cap_pos = pos; cap_pos += safepos; if (cap_pos < 0) cap_pos += recordbufferframes * SAMPLESIZE; if (cap_pos >= recordbufferframes * SAMPLESIZE) cap_pos -= recordbufferframes * SAMPLESIZE; if (FAILED (hr)) { sampler_free (); return 0; } #endif } if (clockspersample < 1) return 0; uae_s16 *sbuf = (uae_s16*)samplebuffer; vsynccnt = 0; sample = 0; samplecnt = 0; cycles = (int)get_cycles () - (int)oldcycles; doffset = doffset_offset + cycles / clockspersample; offset = (int)doffset; if (oldoffset < 0 || offset >= sampleframes || offset < 0) { if (offset >= sampleframes) { doffset -= offset; doffset_offset = doffset; } if (oldoffset >= 0 && offset >= sampleframes) { while (oldoffset < sampleframes) { sample += sbuf[oldoffset * SAMPLESIZE / 2 + channel]; oldoffset++; samplecnt++; } } hr = lpDSB2r->GetCurrentPosition (&t, NULL); int pos = t; pos -= safediff; if (pos < 0) pos += recordbufferframes * SAMPLESIZE; hr = lpDSB2r->Lock (pos, sampleframes * SAMPLESIZE, &p1, &len1, &p2, &len2, 0); if (FAILED (hr)) { write_log (_T("SAMPLER: Lock() failed %x\n"), hr); return 0; } memcpy (samplebuffer, p1, len1); if (p2) memcpy (samplebuffer + len1, p2, len2); lpDSB2r->Unlock (p1, len1, p2, len2); #if 0 cap_pos = t; cap_pos += sampleframes * SAMPLESIZE; if (cap_pos < 0) cap_pos += RECORDBUFFER * SAMPLESIZE; if (cap_pos >= RECORDBUFFER * SAMPLESIZE) cap_pos -= RECORDBUFFER * SAMPLESIZE; hr = lpDSB2r->GetCurrentPosition (&t, &pos); cur_pos = pos; if (FAILED (hr)) return 0; cur_pos += safepos; if (cur_pos < 0) cur_pos += RECORDBUFFER * SAMPLESIZE; if (cur_pos >= RECORDBUFFER * SAMPLESIZE) cur_pos -= RECORDBUFFER * SAMPLESIZE; int diff; if (cur_pos >= cap_pos) diff = cur_pos - cap_pos; else diff = RECORDBUFFER * SAMPLESIZE - cap_pos + cur_pos; if (diff > RECORDBUFFER * SAMPLESIZE / 2) diff -= RECORDBUFFER * SAMPLESIZE; diff /= SAMPLESIZE; int diff2 = 100 * diff / (RECORDBUFFER / 2); diffsample = -pow (diff2 < 0 ? -diff2 : diff2, 3.1); if (diff2 < 0) diffsample = -diffsample; write_log (_T("%d\n"), diff); write_log (_T("CAP=%05d CUR=%05d (%-05d) OFF=%05d %f\n"), cap_pos / SAMPLESIZE, cur_pos / SAMPLESIZE, (cap_pos - cur_pos) / SAMPLESIZE, offset, doffset_offset); #endif if (offset < 0) offset = 0; if (offset >= sampleframes) offset -= sampleframes; oldoffset = 0; oldcycles = get_cycles (); } while (oldoffset <= offset) { sample += sbuf[oldoffset * SAMPLESIZE / 2 + channel]; samplecnt++; oldoffset++; } oldoffset = offset; if (samplecnt > 0) sample /= samplecnt; #if 1 /* yes, not 256, without this max recording volume would still be too quiet on my sound cards */ sample /= 128; if (sample < -128) sample = 0; else if (sample > 127) sample = 127; return (uae_u8)(sample - 128); #else return (Uae_u8)((sample / 256) - 128); #endif }
int VoiceRecord_DSound::GetRecordedData(short *pOut, int nSamplesInt) { if(!m_pCaptureBuffer) { assert(false); return 0; } DWORD dwStatus; HRESULT hr = m_pCaptureBuffer->GetStatus(&dwStatus); if(FAILED(hr) || !(dwStatus & DSCBSTATUS_CAPTURING)) return 0; Idle(); // Update wrapping.. DWORD nSamplesWanted = (DWORD)nSamplesInt; DWORD dwCapturePos, dwReadPos; hr = m_pCaptureBuffer->GetCurrentPosition(&dwCapturePos, &dwReadPos); if(FAILED(hr)) return 0; dwCapturePos += m_WrapOffset; dwReadPos += m_WrapOffset; // Read the range (dwReadPos-nSamplesWanted, dwReadPos), but don't re-read data we've already read. DWORD readStart; if(dwReadPos > nSamplesWanted) readStart = dwReadPos - nSamplesWanted; else readStart = 0; if(readStart < m_LastReadPos) readStart = m_LastReadPos; // Lock the buffer. LPVOID pData[2]; DWORD dataLen[2]; hr = m_pCaptureBuffer->Lock( readStart % NumCaptureBufferBytes(), // Offset. dwReadPos - readStart, // Number of bytes to lock. &pData[0], // Buffer 1. &dataLen[0], // Buffer 1 length. &pData[1], // Buffer 2. &dataLen[1], // Buffer 2 length. 0 // Flags. ); if(FAILED(hr)) return 0; // Hopefully we didn't get too much data back! if((dataLen[0]+dataLen[1]) > nSamplesWanted) { assert(false); m_pCaptureBuffer->Unlock(pData[0], dataLen[0], pData[1], dataLen[1]); return 0; } // Copy the data to the output. memcpy(pOut, pData[0], dataLen[0]); memcpy(&pOut[dataLen[0]/2], pData[1], dataLen[1]); m_pCaptureBuffer->Unlock(pData[0], dataLen[0], pData[1], dataLen[1]); // Update the shiz. m_LastReadPos = dwReadPos; return (dataLen[0] + dataLen[1]) >> 1; }
int audioStreamer_ds::Read(char *buf, int len) // returns 0 if blocked, < 0 if error, > 0 if data { if (!m_inbuf) return -1; if (!m_has_started) { m_inbuf->Start(DSCBSTART_LOOPING); m_has_started=1; } int cappos; m_inbuf->GetCurrentPosition(NULL,(DWORD *)&cappos); if (cappos < m_last_pos) m_i_dw++; m_last_pos=cappos; if ((m_i_dw - m_i_lw) * m_totalbufsize + cappos - m_bufpos >= (unsigned int)m_totalbufsize/2) // detect overrun, set to cappos { m_i_lw=m_i_dw; m_bufpos=0; while (m_bufpos < cappos-m_bufsize) m_bufpos += m_bufsize; if (m_bufpos >= m_totalbufsize) { m_i_lw++; m_bufpos -= m_totalbufsize; } // audiostream_onover(); } for (;;) { if (m_i_lw < m_i_dw || m_bufpos + m_bufsize < cappos) break; Sleep(DS_SLEEP); m_inbuf->GetCurrentPosition(NULL,(DWORD*)&cappos); if (cappos < m_last_pos) m_i_dw++; m_last_pos=cappos; } //audiostream_instance->g_sound_in_overruns = (m_i_lw < m_i_dw ? (m_totalbufsize+cappos) : cappos ) -m_bufpos; void *v1=0, *v2=0; DWORD lv1=0, lv2=0; if (m_inbuf->Lock(m_bufpos,len,&v1,&lv1,&v2,&lv2,FALSE) == DS_OK) { int l1=min((int)lv1,len); memcpy(buf,v1,l1); if (l1 < len && v2 && lv2) memcpy(buf+l1,v2,min((int)lv2,len-l1)); m_inbuf->Unlock(v1,lv1,v2,lv2); m_bufpos += len; if (m_bufpos >= m_totalbufsize) { m_i_lw++; m_bufpos -= m_totalbufsize; } } else { return -1; } return len; }