Exemplo n.º 1
0
// TODO: Move the init into the thread, like WASAPI?
int DSoundAudioBackend::RunThread() {
	setCurrentThreadName("DSound");
	currentPos_ = 0;
	lastPos_ = 0;

	dsBuffer_->Play(0,0,DSBPLAY_LOOPING);

	while (!threadData_) {
		EnterCriticalSection(&soundCriticalSection);

		dsBuffer_->GetCurrentPosition((DWORD *)&currentPos_, 0);
		int numBytesToRender = RoundDown128(ModBufferSize(currentPos_ - lastPos_)); 

		if (numBytesToRender >= 256) {
			int numBytesRendered = 4 * (*callback_)(realtimeBuffer_, numBytesToRender >> 2, 16, 44100, 2);
			//We need to copy the full buffer, regardless of what the mixer claims to have filled
			//If we don't do this then the sound will loop if the sound stops and the mixer writes only zeroes
			numBytesRendered = numBytesToRender;
			WriteDataToBuffer(lastPos_, (char *) realtimeBuffer_, numBytesRendered);

			currentPos_ = ModBufferSize(lastPos_ + numBytesRendered);
			totalRenderedBytes_ += numBytesRendered;

			lastPos_ = currentPos_;
		}

		LeaveCriticalSection(&soundCriticalSection);
		WaitForSingleObject(soundSyncEvent_, MAXWAIT);
	}
Exemplo n.º 2
0
void LC3Sound::TimeProc(
	 UINT  IDEvent,			/* identifies timer event */
	 UINT  uReserved,		/* not used */
	 DWORD_PTR  dwUser,			/* application-defined instance data */
	 DWORD_PTR  dwReserved1,	/* not used */
	 DWORD_PTR  dwReserved2		/* not used */
)
{
	DWORD 		pos, posp;
	static volatile int timersema=0;

	/* use semaphore to prevent entering the mixing routines twice.. do we need this ? */

	if(++timersema==1)
	{
		lpSwSamp->GetCurrentPosition( &pos, &posp);
		
		{
			
			if( !DirectSave( soundData))
			{
				memset(soundData, 0x80, BUFSIZE);
			}
			
			WriteDataToBuffer( lpSwSamp, 0, (unsigned char*) soundData, BUFSIZE);
		}
		
	}
	timersema--;
}
Exemplo n.º 3
0
int DSoundAudioBackend::RunThread() {
	if (FAILED(DirectSoundCreate8(0, &ds_, 0))) {
		ds_ = NULL;
		threadData_ = 2;
		return 1;
	}

	ds_->SetCooperativeLevel(window_, DSSCL_PRIORITY);
	if (!CreateBuffer()) {
		ds_->Release();
		ds_ = NULL;
		threadData_ = 2;
		return 1;
	}

	soundSyncEvent_ = CreateEvent(0, false, false, 0);
	InitializeCriticalSection(&soundCriticalSection);

	DWORD num1;
	short *p1;

	dsBuffer_->Lock(0, bufferSize_, (void **)&p1, &num1, 0, 0, 0);

	memset(p1, 0, num1);
	dsBuffer_->Unlock(p1, num1, 0, 0);
	totalRenderedBytes_ = -bufferSize_;

	setCurrentThreadName("DSound");
	currentPos_ = 0;
	lastPos_ = 0;

	dsBuffer_->Play(0,0,DSBPLAY_LOOPING);

	while (!threadData_) {
		EnterCriticalSection(&soundCriticalSection);

		dsBuffer_->GetCurrentPosition((DWORD *)&currentPos_, 0);
		int numBytesToRender = RoundDown128(ModBufferSize(currentPos_ - lastPos_)); 

		if (numBytesToRender >= 256) {
			int numBytesRendered = 4 * (*callback_)(realtimeBuffer_, numBytesToRender >> 2, 16, 44100, 2);
			//We need to copy the full buffer, regardless of what the mixer claims to have filled
			//If we don't do this then the sound will loop if the sound stops and the mixer writes only zeroes
			numBytesRendered = numBytesToRender;
			WriteDataToBuffer(lastPos_, (char *) realtimeBuffer_, numBytesRendered);

			currentPos_ = ModBufferSize(lastPos_ + numBytesRendered);
			totalRenderedBytes_ += numBytesRendered;

			lastPos_ = currentPos_;
		}

		LeaveCriticalSection(&soundCriticalSection);
		WaitForSingleObject(soundSyncEvent_, MAXWAIT);
	}
Exemplo n.º 4
0
// The audio thread.
void DSound::SoundLoop()
{
	currentPos = 0;
	lastPos = 0;
	dsBuffer->Play(0, 0, DSBPLAY_LOOPING);

	while (!threadData)
	{
		// No blocking inside the csection
		dsBuffer->GetCurrentPosition((DWORD*)&currentPos, 0);
		int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
		if (numBytesToRender >= 256)
		{
			if (numBytesToRender > sizeof(realtimeBuffer))
				PanicAlert("soundThread: too big render call");
			m_mixer->Mix(realtimeBuffer, numBytesToRender / 4);
			WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);
			lastPos = ModBufferSize(lastPos + numBytesToRender);
		}
		soundSyncEvent.Wait();
	}
}
Exemplo n.º 5
0
//TODO: we should probably do something to prevent thread contention
static void CALLBACK TimeProc(
	 UINT  IDEvent,			/* identifies timer event */
	 UINT  uReserved,		/* not used */
	 DWORD_PTR  dwUser,			/* application-defined instance data */
	 DWORD_PTR  dwReserved1,	/* not used */
	 DWORD_PTR  dwReserved2		/* not used */
)
{
	DWORD 		pos, posp;
	static volatile int timersema=0;

	/* use semaphore to prevent entering the mixing routines twice.. do we need this ? */

	if(++timersema==1)
	{
		MADDriverRec	*WinMADDriver = (MADDriverRec*) dwUser;
		
		if(WinMADDriver->Reading == false)
		{
			switch(WinMADDriver->DriverSettings.outPutBits)
				{
					case 8:
						memset(WinMADDriver->currentBuf, 0x80, WinMADDriver->WIN95BUFFERSIZE);
						break;
					
					case 16:
						memset(WinMADDriver->currentBuf, 0, WinMADDriver->WIN95BUFFERSIZE);
						break;
				}
		}

		WinMADDriver->lpSwSamp->lpVtbl->GetCurrentPosition(WinMADDriver->lpSwSamp, &pos, &posp);
		
		if(pos > WinMADDriver->WIN95BUFFERSIZE/2 && WinMADDriver->OnOff == true)
		{
			WinMADDriver->OnOff = false;
			
			if (!DirectSave(WinMADDriver->currentBuf, NULL, WinMADDriver))
			{
				switch(WinMADDriver->DriverSettings.outPutBits)
				{
					case 8:
						memset(WinMADDriver->currentBuf, 0x80, WinMADDriver->WIN95BUFFERSIZE/2);
						break;
					
					case 16:
						memset(WinMADDriver->currentBuf, 0, WinMADDriver->WIN95BUFFERSIZE/2);
						break;
				}
			}
			
			if (!WriteDataToBuffer(WinMADDriver->lpSwSamp, 0, (unsigned char*) WinMADDriver->currentBuf, WinMADDriver->WIN95BUFFERSIZE/2))
			{
				//DEBUG 	debugger("ERR");
			}
		}
		else if (WinMADDriver->OnOff == false && (pos < WinMADDriver->WIN95BUFFERSIZE/2))
		{
			WinMADDriver->OnOff = true;
			
			if (!DirectSave(WinMADDriver->currentBuf + WinMADDriver->WIN95BUFFERSIZE/2, NULL, WinMADDriver))
			{
				switch(WinMADDriver->DriverSettings.outPutBits)
				{
					case 8:
						memset(WinMADDriver->currentBuf + WinMADDriver->WIN95BUFFERSIZE/2, 0x80, WinMADDriver->WIN95BUFFERSIZE/2);
						break;
					
					case 16:
						memset(WinMADDriver->currentBuf + WinMADDriver->WIN95BUFFERSIZE/2, 0, WinMADDriver->WIN95BUFFERSIZE/2);
						break;
				}
			}
			
			if (!WriteDataToBuffer(WinMADDriver->lpSwSamp, WinMADDriver->WIN95BUFFERSIZE/2, (unsigned char*) (WinMADDriver->currentBuf + WinMADDriver->WIN95BUFFERSIZE/2), WinMADDriver->WIN95BUFFERSIZE/2))
			{
				//DEBUG 	debugger("ERR");
			}
		}
		
		if (WinMADDriver->WIN95BUFFERSIZE - pos > 1700)	WinMADDriver->OscilloWavePtr = WinMADDriver->currentBuf + pos;
		else WinMADDriver->OscilloWavePtr = WinMADDriver->currentBuf;
	}
	timersema--;
}
Exemplo n.º 6
0
int CSound::LoadInternal(const char* szFileName, DSBUFFERDESC* pDsbdesc, void* pData, unsigned long dwDataSize){

	CSoundLoader* pLoader;
	char errmsg[512];
	if(CS_E_OK!=this->GetLoaderInterface(&pLoader, szFileName, pData, dwDataSize)){
		wsprintf(errmsg, "Sound::%sの読み取りインターフェイス取得に失敗.\nファイルが存在するかもしくは対応形式か確認して下さい.", szFileName);
		::MessageBox(NULL, errmsg, "", MB_ICONEXCLAMATION|MB_OK|MB_TOPMOST);
		//FatalAppExit(0, errmsg);
		return CS_E_NOTFOUND;
	}
	if(CSL_E_OK != pLoader->QueryLoadFile(szFileName, pData, dwDataSize)){
		wsprintf(errmsg, "Sound::%sの読み取りに失敗.", szFileName);
		::MessageBox(NULL, errmsg, "", MB_ICONEXCLAMATION|MB_OK|MB_TOPMOST);
		//FatalAppExit(0, errmsg);
		return CS_E_UNEXP;
	}

	//初期化
	this->AddRef();
	this->UnInitialize();

	m_Loader = pLoader;

	if(!m_pPrimaryBuffer){		//プライマリバッファを取得する
		if(CS_E_OK!=GetPrimaryBuffer(&m_pPrimaryBuffer, DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_PRIMARYBUFFER)) return CS_E_NULL_PRIMARY;
	}

	DSBUFFERDESC dsbdesc;
	zeroMem(&dsbdesc, sizeof(DSBUFFERDESC));
	dsbdesc.dwSize = sizeof(DSBUFFERDESC);

	//全体の長さとWFXの取得
	DWORD dwDataLength = m_Loader->GetDecodedLength();
	m_Loader->GetWaveFormatEx(&m_wfx);
	if(dwDataLength >= CS_LIMITLOADONMEMORY){//展開したときのサイズが1MB以上だったらストリーミング再生]
		//スレッド処理
		this->CloseStreamThread();
		m_hThreadMessageDispatchEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		m_hThread = CreateThread(NULL, 0, this->StreamThread, (void*)this, CREATE_SUSPENDED, &m_dwThreadId);		//スレッド生成
		// スレッド優先を変更
		SetThreadPriority( m_hThread, THREAD_PRIORITY_NORMAL ); 
		// スレッド開始
		ResumeThread( m_hThread );
		WaitForSingleObject(m_hThreadMessageDispatchEvent, INFINITE);// スレッドメッセージキューが作成されるのを待つ

		m_isStreamFile = TRUE;

		//セカンダリバッファ
		{
			SAFE_RELEASE(m_pSecondaryBuffer);
			dsbdesc.dwFlags =	DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY|
								DSBCAPS_GLOBALFOCUS|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME|
								DSBCAPS_CTRLFREQUENCY|DSBCAPS_LOCSOFTWARE;

			if(pDsbdesc){
				dsbdesc.dwFlags = pDsbdesc->dwFlags;
				dsbdesc.guid3DAlgorithm = dsbdesc.guid3DAlgorithm;
			}
			dsbdesc.lpwfxFormat = &m_wfx;
			DWORD dwSize = m_wfx.nAvgBytesPerSec * m_dwBufferLengthSec / m_dwNotificationNum;
			dwSize -= dwSize % m_wfx.nBlockAlign;
			dsbdesc.dwBufferBytes = dwSize * m_dwNotificationNum;
			if(!CreateBuffer(&m_pSecondaryBuffer, &dsbdesc, NULL))	return CS_E_NOCANDO;

			m_dwOneSplittedBufferSize = dwSize;//区切られたバッファの1つのサイズ(バッファ全体はこれ*m_dwNotificationNum
		}

		//通知インターフェイス
#if !ENABLE_SOUND_POLLING
		{
			SAFE_RELEASE(m_pSoundNotify);
			if(FAILED(m_pSecondaryBuffer->QueryInterface(IID_IDirectSoundNotify, (void**)&m_pSoundNotify))){
				return CS_E_NOCANDO;
			}

			SAFE_GLOBALFREE(m_pDsbnotify);
			if(!(m_pDsbnotify = (DSBPOSITIONNOTIFY*)GlobalAlloc(GPTR, m_dwNotificationNum * sizeof(DSBPOSITIONNOTIFY)))){
				return CS_E_UNEXP;
			}

			m_pNotifyHandle = CreateEvent(NULL, FALSE, FALSE, NULL);	//通知ハンドルの作成
			for(DWORD i=0; i<m_dwNotificationNum; i++){
				//OutputDebugStringFormatted("[%2lu]:%lu\n", i, (m_dwOneSplittedBufferSize*i) + 1);
				m_pDsbnotify[i].dwOffset     = (m_dwOneSplittedBufferSize*i) + 1;// バッファを分割する。通知ポイントは、バッファの区切れ目から1バイト先。こうすることで、スペックの低いマシンでも249ms以内に次のバッファ区間を埋めればよいことになる。
				m_pDsbnotify[i].hEventNotify = m_pNotifyHandle;
			}
			if(FAILED(m_pSoundNotify->SetNotificationPositions(m_dwNotificationNum, m_pDsbnotify))){
				SAFE_GLOBALFREE(m_pDsbnotify);
				SAFE_RELEASE(m_pSoundNotify);
				SAFE_CLOSEHANDLE(m_pNotifyHandle);
				return CS_E_NOCANDO;
			}
		}
#endif
	}else{
		m_isStreamFile = FALSE;

		void* pdata = NULL;
		if(CSL_E_OK != m_Loader->GetDecodedData(&pdata, 0, 0, FALSE)){
		}

		dsbdesc.dwFlags =	DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME|
							DSBCAPS_CTRLFREQUENCY|
							DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY|
							DSBCAPS_GLOBALFOCUS;
		if(pDsbdesc){
			dsbdesc.dwFlags = pDsbdesc->dwFlags;
			dsbdesc.guid3DAlgorithm = dsbdesc.guid3DAlgorithm;
		}
		dsbdesc.dwBufferBytes = dwDataLength;
		dsbdesc.lpwfxFormat = &m_wfx;

		SAFE_RELEASE(m_pSecondaryBuffer);
		if(!CreateBuffer(&m_pSecondaryBuffer, &dsbdesc, NULL)) return CS_E_NOCANDO;		//セカンダリバッファの作成
		if(!WriteDataToBuffer(&m_pSecondaryBuffer, pdata, 0, dwDataLength))	return CS_E_NOCANDO;		//データをバッファに書き込む
		
		SAFE_GLOBALFREE(pdata);
	}
	SAFE_RELEASE(m_pPrimaryBuffer);
	return CS_E_OK;
}