Add sync audio for emscripten
This commit is contained in:
		
							parent
							
								
									ee39e65061
								
							
						
					
					
						commit
						9b531afb0c
					
				
					 9 changed files with 149 additions and 73 deletions
				
			
		
							
								
								
									
										139
									
								
								src/alstream.cpp
									
										
									
									
									
								
							
							
						
						
									
										139
									
								
								src/alstream.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -302,8 +302,12 @@ void ALStream::startStream(float offset)
 | 
			
		|||
	startOffset = offset;
 | 
			
		||||
	procFrames = offset * source->sampleRate();
 | 
			
		||||
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
	streamData();
 | 
			
		||||
#else
 | 
			
		||||
	thread = createSDLThread
 | 
			
		||||
		<ALStream, &ALStream::streamData>(this, threadName);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ALStream::pauseStream()
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +366,6 @@ void ALStream::streamData()
 | 
			
		|||
{
 | 
			
		||||
	/* Fill up queue */
 | 
			
		||||
	bool firstBuffer = true;
 | 
			
		||||
	ALDataSource::Status status;
 | 
			
		||||
 | 
			
		||||
	if (threadTermReq)
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -406,74 +409,82 @@ void ALStream::streamData()
 | 
			
		|||
 | 
			
		||||
	/* Wait for buffers to be consumed, then
 | 
			
		||||
	 * refill and queue them up again */
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		shState->rtData().syncPoint.passSecondarySync();
 | 
			
		||||
 | 
			
		||||
		ALint procBufs = AL::Source::getProcBufferCount(alSrc);
 | 
			
		||||
 | 
			
		||||
		while (procBufs--)
 | 
			
		||||
		{
 | 
			
		||||
			if (threadTermReq)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			AL::Buffer::ID buf = AL::Source::unqueueBuffer(alSrc);
 | 
			
		||||
 | 
			
		||||
			/* If something went wrong, try again later */
 | 
			
		||||
			if (buf == AL::Buffer::ID(0))
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (buf == lastBuf)
 | 
			
		||||
			{
 | 
			
		||||
				/* Reset the processed sample count so
 | 
			
		||||
				 * querying the playback offset returns 0.0 again */
 | 
			
		||||
				procFrames = source->loopStartFrames();
 | 
			
		||||
				lastBuf = AL::Buffer::ID(0);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				/* Add the frame count contained in this
 | 
			
		||||
				 * buffer to the total count */
 | 
			
		||||
				ALint bits = AL::Buffer::getBits(buf);
 | 
			
		||||
				ALint size = AL::Buffer::getSize(buf);
 | 
			
		||||
				ALint chan = AL::Buffer::getChannels(buf);
 | 
			
		||||
 | 
			
		||||
				if (bits != 0 && chan != 0)
 | 
			
		||||
					procFrames += ((size / (bits / 8)) / chan);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (sourceExhausted)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			status = source->fillBuffer(buf);
 | 
			
		||||
 | 
			
		||||
			if (status == ALDataSource::Error)
 | 
			
		||||
			{
 | 
			
		||||
				sourceExhausted.set();
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			AL::Source::queueBuffer(alSrc, buf);
 | 
			
		||||
 | 
			
		||||
			/* In case of buffer underrun,
 | 
			
		||||
			 * start playing again */
 | 
			
		||||
			if (AL::Source::getState(alSrc) == AL_STOPPED)
 | 
			
		||||
				AL::Source::play(alSrc);
 | 
			
		||||
 | 
			
		||||
			/* If this was the last buffer before the data
 | 
			
		||||
			 * source loop wrapped around again, mark it as
 | 
			
		||||
			 * such so we can catch it and reset the processed
 | 
			
		||||
			 * sample count once it gets unqueued */
 | 
			
		||||
			if (status == ALDataSource::WrapAround)
 | 
			
		||||
				lastBuf = buf;
 | 
			
		||||
 | 
			
		||||
			if (status == ALDataSource::EndOfStream)
 | 
			
		||||
				sourceExhausted.set();
 | 
			
		||||
		}
 | 
			
		||||
		streamDevice();
 | 
			
		||||
 | 
			
		||||
		if (threadTermReq)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		SDL_Delay(AUDIO_SLEEP);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ALStream::update() {
 | 
			
		||||
	if (threadTermReq)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	shState->rtData().syncPoint.passSecondarySync();
 | 
			
		||||
 | 
			
		||||
	ALint procBufs = AL::Source::getProcBufferCount(alSrc);
 | 
			
		||||
 | 
			
		||||
	while (procBufs--)
 | 
			
		||||
	{
 | 
			
		||||
		if (threadTermReq)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		AL::Buffer::ID buf = AL::Source::unqueueBuffer(alSrc);
 | 
			
		||||
 | 
			
		||||
		/* If something went wrong, try again later */
 | 
			
		||||
		if (buf == AL::Buffer::ID(0))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (buf == lastBuf)
 | 
			
		||||
		{
 | 
			
		||||
			/* Reset the processed sample count so
 | 
			
		||||
			 * querying the playback offset returns 0.0 again */
 | 
			
		||||
			procFrames = source->loopStartFrames();
 | 
			
		||||
			lastBuf = AL::Buffer::ID(0);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/* Add the frame count contained in this
 | 
			
		||||
			 * buffer to the total count */
 | 
			
		||||
			ALint bits = AL::Buffer::getBits(buf);
 | 
			
		||||
			ALint size = AL::Buffer::getSize(buf);
 | 
			
		||||
			ALint chan = AL::Buffer::getChannels(buf);
 | 
			
		||||
 | 
			
		||||
			if (bits != 0 && chan != 0)
 | 
			
		||||
				procFrames += ((size / (bits / 8)) / chan);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (sourceExhausted)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		status = source->fillBuffer(buf);
 | 
			
		||||
 | 
			
		||||
		if (status == ALDataSource::Error)
 | 
			
		||||
		{
 | 
			
		||||
			sourceExhausted.set();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		AL::Source::queueBuffer(alSrc, buf);
 | 
			
		||||
 | 
			
		||||
		/* In case of buffer underrun,
 | 
			
		||||
		 * start playing again */
 | 
			
		||||
		if (AL::Source::getState(alSrc) == AL_STOPPED)
 | 
			
		||||
			AL::Source::play(alSrc);
 | 
			
		||||
 | 
			
		||||
		/* If this was the last buffer before the data
 | 
			
		||||
		 * source loop wrapped around again, mark it as
 | 
			
		||||
		 * such so we can catch it and reset the processed
 | 
			
		||||
		 * sample count once it gets unqueued */
 | 
			
		||||
		if (status == ALDataSource::WrapAround)
 | 
			
		||||
			lastBuf = buf;
 | 
			
		||||
 | 
			
		||||
		if (status == ALDataSource::EndOfStream)
 | 
			
		||||
			sourceExhausted.set();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,13 +23,12 @@
 | 
			
		|||
#define ALSTREAM_H
 | 
			
		||||
 | 
			
		||||
#include "al-util.h"
 | 
			
		||||
#include "aldatasource.h"
 | 
			
		||||
#include "sdl-util.h"
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <SDL_rwops.h>
 | 
			
		||||
 | 
			
		||||
struct ALDataSource;
 | 
			
		||||
 | 
			
		||||
#define STREAM_BUFS 3
 | 
			
		||||
 | 
			
		||||
/* State-machine like audio playback stream.
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +103,8 @@ struct ALStream
 | 
			
		|||
	float queryOffset();
 | 
			
		||||
	bool queryNativePitch();
 | 
			
		||||
 | 
			
		||||
	void update();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void closeSource();
 | 
			
		||||
	void openSource(const std::string &filename);
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +118,8 @@ private:
 | 
			
		|||
 | 
			
		||||
	/* thread func */
 | 
			
		||||
	void streamData();
 | 
			
		||||
 | 
			
		||||
	ALDataSource::Status status;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // ALSTREAM_H
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,22 +71,27 @@ struct AudioPrivate
 | 
			
		|||
	      syncPoint(rtData.syncPoint)
 | 
			
		||||
	{
 | 
			
		||||
		meWatch.state = MeNotPlaying;
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
		meWatch.thread = createSDLThread
 | 
			
		||||
			<AudioPrivate, &AudioPrivate::meWatchFun>(this, "audio_mewatch");
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~AudioPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		meWatch.termReq.set();
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
		SDL_WaitThread(meWatch.thread, 0);
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void meWatchFun()
 | 
			
		||||
	{
 | 
			
		||||
		const float fadeOutStep = 1.f / (200  / AUDIO_SLEEP);
 | 
			
		||||
		const float fadeInStep  = 1.f / (1000 / AUDIO_SLEEP);
 | 
			
		||||
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
		while (true)
 | 
			
		||||
#endif
 | 
			
		||||
		{
 | 
			
		||||
			syncPoint.passSecondarySync();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -231,8 +236,9 @@ struct AudioPrivate
 | 
			
		|||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
			SDL_Delay(AUDIO_SLEEP);
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -247,6 +253,7 @@ void Audio::bgmPlay(const char *filename,
 | 
			
		|||
                    int pitch,
 | 
			
		||||
                    float pos)
 | 
			
		||||
{
 | 
			
		||||
	printf("PLAYING BGM %s\n", filename);
 | 
			
		||||
	p->bgm.play(filename, volume, pitch, pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -333,4 +340,14 @@ void Audio::reset()
 | 
			
		|||
	p->se.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::update()
 | 
			
		||||
{
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
	p->bgm.update();
 | 
			
		||||
	p->bgm.update();
 | 
			
		||||
	p->me.update();
 | 
			
		||||
	p->meWatchFun();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Audio::~Audio() { delete p; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,6 +69,8 @@ public:
 | 
			
		|||
 | 
			
		||||
	void reset();
 | 
			
		||||
 | 
			
		||||
	void update();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Audio(RGSSThreadData &rtData);
 | 
			
		||||
	~Audio();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,12 +203,14 @@ void AudioStream::fadeOut(int duration)
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
	if (fade.thread)
 | 
			
		||||
	{
 | 
			
		||||
		fade.reqFini.set();
 | 
			
		||||
		SDL_WaitThread(fade.thread, 0);
 | 
			
		||||
		fade.thread = 0;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	fade.active.set();
 | 
			
		||||
	fade.msStep = 1.0f / duration;
 | 
			
		||||
| 
						 | 
				
			
			@ -216,8 +218,10 @@ void AudioStream::fadeOut(int duration)
 | 
			
		|||
	fade.reqTerm.clear();
 | 
			
		||||
	fade.startTicks = SDL_GetTicks();
 | 
			
		||||
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
	fade.thread = createSDLThread
 | 
			
		||||
		<AudioStream, &AudioStream::fadeOutThread>(this, fade.threadName);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	unlockStream();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -280,24 +284,38 @@ void AudioStream::finiFadeOutInt()
 | 
			
		|||
 | 
			
		||||
void AudioStream::startFadeIn()
 | 
			
		||||
{
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
	/* Previous fadein should always be terminated in play() */
 | 
			
		||||
	assert(!fadeIn.thread);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	fadeIn.rqFini.clear();
 | 
			
		||||
	fadeIn.rqTerm.clear();
 | 
			
		||||
	fadeIn.startTicks = SDL_GetTicks();
 | 
			
		||||
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
	fadeInThread();
 | 
			
		||||
#else
 | 
			
		||||
	fadeIn.thread = createSDLThread
 | 
			
		||||
		<AudioStream, &AudioStream::fadeInThread>(this, fadeIn.threadName);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioStream::fadeOutThread()
 | 
			
		||||
{
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
	while (true)
 | 
			
		||||
#else
 | 
			
		||||
	if (fade.active)
 | 
			
		||||
#endif
 | 
			
		||||
	{
 | 
			
		||||
		/* Just immediately terminate on request */
 | 
			
		||||
		if (fade.reqTerm)
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
			return;
 | 
			
		||||
#else
 | 
			
		||||
			break;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		lockStream();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -315,18 +333,26 @@ void AudioStream::fadeOutThread()
 | 
			
		|||
 | 
			
		||||
			setVolume(FadeOut, 1.0f);
 | 
			
		||||
			unlockStream();
 | 
			
		||||
 | 
			
		||||
#ifdef __EMSCRIPTEN__
 | 
			
		||||
			fade.active.clear();
 | 
			
		||||
			return;
 | 
			
		||||
#else
 | 
			
		||||
			break;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		setVolume(FadeOut, resVol);
 | 
			
		||||
 | 
			
		||||
		unlockStream();
 | 
			
		||||
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
		SDL_Delay(AUDIO_SLEEP);
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifndef __EMSCRIPTEN__
 | 
			
		||||
	fade.active.clear();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioStream::fadeInThread()
 | 
			
		||||
| 
						 | 
				
			
			@ -363,3 +389,9 @@ void AudioStream::fadeInThread()
 | 
			
		|||
		SDL_Delay(AUDIO_SLEEP);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AudioStream::update()
 | 
			
		||||
{
 | 
			
		||||
	fadeOutThread();
 | 
			
		||||
	stream.update();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -140,6 +140,8 @@ struct AudioStream
 | 
			
		|||
 | 
			
		||||
	float playingOffset();
 | 
			
		||||
 | 
			
		||||
	void update();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	float volumes[VolumeTypeCount];
 | 
			
		||||
	void updateVolume();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ struct SDLSoundSource : ALDataSource
 | 
			
		|||
		if (!sample)
 | 
			
		||||
		{
 | 
			
		||||
			SDL_RWclose(&ops);
 | 
			
		||||
			printf("ERROR SDL_sound: %s", Sound_GetError());
 | 
			
		||||
			throw Exception(Exception::SDLError, "SDL_sound: %s", Sound_GetError());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue