forked from dolphin-emu/dolphin
		
	git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6838 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			212 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (C) 2003 Dolphin Project.
 | 
						|
 | 
						|
// This program is free software: you can redistribute it and/or modify
 | 
						|
// it under the terms of the GNU General Public License as published by
 | 
						|
// the Free Software Foundation, version 2.0.
 | 
						|
 | 
						|
// This program is distributed in the hope that it will be useful,
 | 
						|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
// GNU General Public License 2.0 for more details.
 | 
						|
 | 
						|
// A copy of the GPL 2.0 should have been included with the program.
 | 
						|
// If not, see http://www.gnu.org/licenses/
 | 
						|
 | 
						|
// Official SVN repository and contact information can be found at
 | 
						|
// http://code.google.com/p/dolphin-emu/
 | 
						|
 | 
						|
#include "AudioCommon.h"
 | 
						|
#include "XAudio2Stream.h"
 | 
						|
 | 
						|
struct StreamingVoiceContext : public IXAudio2VoiceCallback
 | 
						|
{
 | 
						|
	IXAudio2SourceVoice* pSourceVoice;
 | 
						|
	CMixer *m_mixer;
 | 
						|
	Common::EventEx *soundSyncEvent;
 | 
						|
	short *xaBuffer;
 | 
						|
 | 
						|
	StreamingVoiceContext(IXAudio2 *pXAudio2, CMixer *pMixer, Common::EventEx *pSyncEvent)
 | 
						|
	{
 | 
						|
 | 
						|
		m_mixer = pMixer;
 | 
						|
		soundSyncEvent = pSyncEvent;
 | 
						|
 | 
						|
		WAVEFORMATEXTENSIBLE wfx;
 | 
						|
 | 
						|
		memset(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
 | 
						|
		wfx.Format.wFormatTag		= WAVE_FORMAT_EXTENSIBLE;
 | 
						|
		wfx.Format.nSamplesPerSec	= m_mixer->GetSampleRate();
 | 
						|
		wfx.Format.nChannels		= 2;
 | 
						|
		wfx.Format.wBitsPerSample	= 16;
 | 
						|
		wfx.Format.nBlockAlign		= wfx.Format.nChannels*wfx.Format.wBitsPerSample/8;
 | 
						|
		wfx.Format.nAvgBytesPerSec	= wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
 | 
						|
		wfx.Format.cbSize			= sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 | 
						|
		wfx.Samples.wValidBitsPerSample = 16;
 | 
						|
		wfx.dwChannelMask			= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
 | 
						|
		wfx.SubFormat				= KSDATAFORMAT_SUBTYPE_PCM;
 | 
						|
 | 
						|
		// create source voice
 | 
						|
		HRESULT hr;
 | 
						|
		if(FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, XAUDIO2_VOICE_NOSRC, 1.0f, this)))
 | 
						|
			PanicAlertT("XAudio2 CreateSourceVoice failed: %#X", hr); 
 | 
						|
 | 
						|
		pSourceVoice->FlushSourceBuffers();
 | 
						|
		pSourceVoice->Start();
 | 
						|
 | 
						|
		xaBuffer = new s16[NUM_BUFFERS * BUFFER_SIZE];
 | 
						|
		memset(xaBuffer, 0, NUM_BUFFERS * BUFFER_SIZE_BYTES);
 | 
						|
 | 
						|
		//start buffers with silence
 | 
						|
		for(int i=0; i < NUM_BUFFERS; i++)
 | 
						|
		{
 | 
						|
			XAUDIO2_BUFFER buf = {0};
 | 
						|
			buf.AudioBytes = BUFFER_SIZE_BYTES;
 | 
						|
			buf.pAudioData = (BYTE *) &xaBuffer[i * BUFFER_SIZE];
 | 
						|
			buf.pContext   = (void *) buf.pAudioData;
 | 
						|
			
 | 
						|
			pSourceVoice->SubmitSourceBuffer(&buf);
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	
 | 
						|
    ~StreamingVoiceContext()
 | 
						|
    {
 | 
						|
        IXAudio2SourceVoice* temp = pSourceVoice;
 | 
						|
        pSourceVoice = NULL;
 | 
						|
        temp->FlushSourceBuffers();
 | 
						|
        temp->DestroyVoice();
 | 
						|
        safe_delete_array(xaBuffer);
 | 
						|
    }
 | 
						|
	
 | 
						|
	void StreamingVoiceContext::Stop() {
 | 
						|
		if (pSourceVoice)
 | 
						|
			pSourceVoice->Stop();
 | 
						|
	}
 | 
						|
 | 
						|
	void StreamingVoiceContext::Play() {
 | 
						|
		if (pSourceVoice)
 | 
						|
			pSourceVoice->Start();
 | 
						|
	}
 | 
						|
	
 | 
						|
	STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) {}
 | 
						|
	STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) {}
 | 
						|
	STDMETHOD_(void, OnVoiceProcessingPassEnd) () {}
 | 
						|
	STDMETHOD_(void, OnBufferStart) (void*) {}
 | 
						|
	STDMETHOD_(void, OnLoopEnd) (void*) {}   
 | 
						|
	STDMETHOD_(void, OnStreamEnd) () {}
 | 
						|
    STDMETHOD_(void, OnBufferEnd) (void* context)
 | 
						|
    {	//
 | 
						|
		//  buffer end callback; gets SAMPLES_PER_BUFFER samples for a new buffer
 | 
						|
		//
 | 
						|
		if( !pSourceVoice || !context) return;
 | 
						|
	
 | 
						|
		//soundSyncEvent->Init();
 | 
						|
		//soundSyncEvent->Wait(); //sync
 | 
						|
		//soundSyncEvent->Spin(); //or tight sync
 | 
						|
		
 | 
						|
		//if (!pSourceVoice) return;
 | 
						|
 | 
						|
		m_mixer->Mix((short *)context, SAMPLES_PER_BUFFER);
 | 
						|
 | 
						|
 | 
						|
		XAUDIO2_BUFFER buf = {0};
 | 
						|
		buf.AudioBytes  = BUFFER_SIZE_BYTES;
 | 
						|
		buf.pAudioData  = (byte*)context;
 | 
						|
		buf.pContext    = context;
 | 
						|
 | 
						|
		pSourceVoice->SubmitSourceBuffer(&buf);
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
StreamingVoiceContext* pVoiceContext = 0;
 | 
						|
 | 
						|
bool XAudio2::Start()
 | 
						|
{
 | 
						|
	//soundSyncEvent.Init();
 | 
						|
	
 | 
						|
    // XAudio2 init
 | 
						|
    CoInitializeEx(NULL, COINIT_MULTITHREADED);
 | 
						|
	HRESULT hr;
 | 
						|
    if(FAILED(hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_ANY_PROCESSOR))) //callback dosent seem to run on a speecific cpu anyways
 | 
						|
    {
 | 
						|
        PanicAlertT("XAudio2 init failed: %#X", hr);
 | 
						|
        CoUninitialize();
 | 
						|
		return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // XAudio2 master voice
 | 
						|
	// XAUDIO2_DEFAULT_CHANNELS instead of 2 for expansion?
 | 
						|
    if(FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice, 2, m_mixer->GetSampleRate())))
 | 
						|
    {
 | 
						|
        PanicAlertT("XAudio2 master voice creation failed: %#X", hr);
 | 
						|
        safe_release(pXAudio2);
 | 
						|
        CoUninitialize();
 | 
						|
		return false;
 | 
						|
    }
 | 
						|
 | 
						|
	// Volume
 | 
						|
	if (pMasteringVoice)
 | 
						|
		pMasteringVoice->SetVolume(m_volume);
 | 
						|
 | 
						|
	if (pXAudio2)
 | 
						|
		pVoiceContext = new StreamingVoiceContext(pXAudio2, m_mixer, &soundSyncEvent);
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
void XAudio2::SetVolume(int volume)
 | 
						|
{
 | 
						|
	//linear 1- .01
 | 
						|
	m_volume = (float)volume / 100.f;
 | 
						|
 | 
						|
	if (pMasteringVoice)
 | 
						|
		pMasteringVoice->SetVolume(m_volume);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//XAUDIO2_PERFORMANCE_DATA perfData;
 | 
						|
//int xi = 0;
 | 
						|
void XAudio2::Update()
 | 
						|
{
 | 
						|
	//soundSyncEvent.Set();
 | 
						|
 | 
						|
	//xi++;
 | 
						|
	//if (xi == 100000) {
 | 
						|
	//	xi = 0;
 | 
						|
	//	pXAudio2->GetPerformanceData(&perfData);
 | 
						|
	//	NOTICE_LOG(DSPHLE, "XAudio2 latency (samples): %i",perfData.CurrentLatencyInSamples);
 | 
						|
	//	NOTICE_LOG(DSPHLE, "XAudio2    total glitches: %i",perfData.GlitchesSinceEngineStarted);
 | 
						|
	//}
 | 
						|
}
 | 
						|
 | 
						|
void XAudio2::Clear(bool mute)
 | 
						|
{
 | 
						|
	m_muted = mute;
 | 
						|
 | 
						|
	if (pVoiceContext)
 | 
						|
	{
 | 
						|
		if (m_muted)
 | 
						|
			pVoiceContext->Stop();
 | 
						|
		else
 | 
						|
			pVoiceContext->Play();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void XAudio2::Stop()
 | 
						|
{
 | 
						|
	//soundSyncEvent.Set();
 | 
						|
 | 
						|
    safe_delete(pVoiceContext);
 | 
						|
    pVoiceContext = NULL;
 | 
						|
 | 
						|
	if(pMasteringVoice)
 | 
						|
		pMasteringVoice->DestroyVoice();
 | 
						|
	
 | 
						|
    safe_release(pXAudio2);
 | 
						|
	pMasteringVoice = NULL;
 | 
						|
    CoUninitialize();
 | 
						|
	//soundSyncEvent.Shutdown();
 | 
						|
}
 |