forked from dolphin-emu/dolphin
		
	git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7015 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			194 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			4.6 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 <functional>
 | |
| 
 | |
| #include "aldlist.h"
 | |
| #include "OpenALStream.h"
 | |
| 
 | |
| #if defined HAVE_OPENAL && HAVE_OPENAL
 | |
| 
 | |
| //
 | |
| // AyuanX: Spec says OpenAL1.1 is thread safe already
 | |
| //
 | |
| bool OpenALStream::Start()
 | |
| {
 | |
| 	ALDeviceList *pDeviceList = NULL;
 | |
| 	ALCcontext *pContext = NULL;
 | |
| 	ALCdevice *pDevice = NULL;
 | |
| 	bool bReturn = false;
 | |
| 
 | |
| 	soundSyncEvent.Init();
 | |
| 
 | |
| 	pDeviceList = new ALDeviceList();
 | |
| 	if ((pDeviceList) && (pDeviceList->GetNumDevices()))
 | |
| 	{
 | |
| 		char *defDevName = pDeviceList-> \
 | |
| 			GetDeviceName(pDeviceList->GetDefaultDevice());
 | |
| 		pDevice = alcOpenDevice(defDevName);
 | |
| 		if (pDevice)
 | |
| 		{
 | |
| 			pContext = alcCreateContext(pDevice, NULL);
 | |
| 			if (pContext)
 | |
| 			{
 | |
| 				alcMakeContextCurrent(pContext);
 | |
| 				thread = std::thread(std::mem_fun(&OpenALStream::SoundLoop), this);
 | |
| 				bReturn = true;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				alcCloseDevice(pDevice);
 | |
| 				PanicAlertT("OpenAL: can't create context "
 | |
| 					"for device %s", defDevName);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			PanicAlertT("OpenAL: can't open device %s", defDevName);
 | |
| 		}
 | |
| 		delete pDeviceList;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		PanicAlertT("OpenAL: can't find sound devices");
 | |
| 	}
 | |
| 
 | |
| 	return bReturn;
 | |
| }
 | |
| 
 | |
| void OpenALStream::Stop()
 | |
| {
 | |
| 	threadData = 1;
 | |
| 	// kick the thread if it's waiting
 | |
| 	soundSyncEvent.Set();
 | |
| 
 | |
| 	thread.join();
 | |
| 
 | |
| 	alSourceStop(uiSource);
 | |
| 	alSourcei(uiSource, AL_BUFFER, 0);
 | |
| 
 | |
| 	// Clean up buffers and sources
 | |
| 	alDeleteSources(1, &uiSource);
 | |
| 	uiSource = 0;
 | |
| 	alDeleteBuffers(OAL_NUM_BUFFERS, uiBuffers);
 | |
| 
 | |
| 	ALCcontext *pContext = alcGetCurrentContext();
 | |
| 	ALCdevice *pDevice = alcGetContextsDevice(pContext);
 | |
| 
 | |
| 	alcMakeContextCurrent(NULL);
 | |
| 	alcDestroyContext(pContext);
 | |
| 	alcCloseDevice(pDevice);
 | |
| 
 | |
| 	soundSyncEvent.Shutdown();
 | |
| }
 | |
| 
 | |
| void OpenALStream::SetVolume(int volume)
 | |
| {
 | |
| 	fVolume = (float)volume / 100.0f;
 | |
| 
 | |
| 	if (uiSource)
 | |
| 		alSourcef(uiSource, AL_GAIN, fVolume); 
 | |
| }
 | |
| 
 | |
| void OpenALStream::Update()
 | |
| {
 | |
| 	soundSyncEvent.Set();
 | |
| }
 | |
| 
 | |
| void OpenALStream::Clear(bool mute)
 | |
| {
 | |
| 	m_muted = mute;
 | |
| 
 | |
| 	if(m_muted)
 | |
| 	{
 | |
| 		alSourceStop(uiSource);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		alSourcePlay(uiSource);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void OpenALStream::SoundLoop()
 | |
| {
 | |
| 	ALenum err;
 | |
| 	u32 ulFrequency = m_mixer->GetSampleRate();
 | |
| 
 | |
| 	memset(uiBuffers, 0, OAL_NUM_BUFFERS * sizeof(ALuint));
 | |
| 	uiSource = 0;
 | |
| 
 | |
| 	// Generate some AL Buffers for streaming
 | |
| 	alGenBuffers(OAL_NUM_BUFFERS, (ALuint *)uiBuffers);
 | |
| 	// Generate a Source to playback the Buffers
 | |
| 	alGenSources(1, &uiSource);
 | |
| 
 | |
| 	// Short Silence
 | |
| 	memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * 4);
 | |
| 	for (int i = 0; i < OAL_NUM_BUFFERS; i++)
 | |
| 		alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_MAX_SAMPLES, ulFrequency);
 | |
| 	alSourceQueueBuffers(uiSource, OAL_NUM_BUFFERS, uiBuffers);
 | |
| 	alSourcePlay(uiSource);
 | |
| 	
 | |
| 	// Set the default sound volume as saved in the config file.
 | |
| 	alSourcef(uiSource, AL_GAIN, fVolume); 
 | |
| 
 | |
| 	err = alGetError();
 | |
| 	// TODO: Error handling
 | |
| 
 | |
| 	ALint iBuffersFilled = 0;
 | |
| 	ALint iBuffersProcessed = 0;
 | |
| 	ALuint uiBufferTemp[OAL_NUM_BUFFERS] = {0};
 | |
| 
 | |
| 	while (!threadData) 
 | |
| 	{
 | |
| 		if (iBuffersProcessed == iBuffersFilled)
 | |
| 		{
 | |
| 			alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed);
 | |
| 			iBuffersFilled = 0;
 | |
| 		}
 | |
| 
 | |
| 		unsigned int numSamples = m_mixer->GetNumSamples();
 | |
| 
 | |
| 		if (iBuffersProcessed && (numSamples >= OAL_THRESHOLD))
 | |
| 		{
 | |
| 			numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples;
 | |
| 			// Remove the Buffer from the Queue.  (uiBuffer contains the Buffer ID for the unqueued Buffer)
 | |
| 			if (iBuffersFilled == 0)
 | |
| 				alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp);
 | |
| 
 | |
| 			m_mixer->Mix(realtimeBuffer, numSamples);
 | |
| 			alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, realtimeBuffer, numSamples * 4, ulFrequency);
 | |
| 			alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]);
 | |
| 			iBuffersFilled++;
 | |
| 
 | |
| 			if (iBuffersFilled == OAL_NUM_BUFFERS)
 | |
| 				alSourcePlay(uiSource);
 | |
| 		}
 | |
| 		else if (numSamples >= OAL_THRESHOLD)
 | |
| 		{
 | |
| 			ALint state = 0;
 | |
| 			alGetSourcei(uiSource, AL_SOURCE_STATE, &state);
 | |
| 			if (state == AL_STOPPED)
 | |
| 				alSourcePlay(uiSource);
 | |
| 		}
 | |
| 		soundSyncEvent.Wait();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #endif //HAVE_OPENAL
 | |
| 
 |