dungeon_crawler

changeset 55:4c427e28ca00

music playback bugfixing
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 19 Sep 2012 08:19:10 +0300
parents 995191474cc0
children f9b8bbebc9b3
files prototype/src/audio/ovstream.cc prototype/src/audio/ovstream.h prototype/src/audio/stream.cc prototype/src/audio/stream.h prototype/src/main.cc
diffstat 5 files changed, 134 insertions(+), 14 deletions(-) [+]
line diff
     1.1 --- a/prototype/src/audio/ovstream.cc	Wed Sep 19 05:22:43 2012 +0300
     1.2 +++ b/prototype/src/audio/ovstream.cc	Wed Sep 19 08:19:10 2012 +0300
     1.3 @@ -1,16 +1,80 @@
     1.4 +#include <stdio.h>
     1.5 +#include <assert.h>
     1.6  #include "ovstream.h"
     1.7  
     1.8  OggVorbisStream::OggVorbisStream()
     1.9  {
    1.10 -	ov_clear(&vf);
    1.11 +	vfopen = false;
    1.12  }
    1.13  
    1.14  OggVorbisStream::~OggVorbisStream()
    1.15  {
    1.16 -	ov_clear(&vf);
    1.17 +	close();
    1.18  }
    1.19  
    1.20 -bool OggVorbisStream::more_samples()
    1.21 +bool OggVorbisStream::open(const char *fname)
    1.22  {
    1.23 -	return false;
    1.24 +	close();
    1.25 +
    1.26 +	std::lock_guard<std::mutex> lock(vflock);
    1.27 +
    1.28 +	printf("opening ogg/vorbis stream: %s\n", fname ? fname : "<not found>");
    1.29 +
    1.30 +	if(!fname || ov_fopen(fname, &vf) != 0) {
    1.31 +		fprintf(stderr, "failed to open ogg/vorbis stream: %s\n", fname ? fname : "<not found>");
    1.32 +		return false;
    1.33 +	}
    1.34 +	vfopen = true;
    1.35 +	return true;
    1.36  }
    1.37 +
    1.38 +void OggVorbisStream::close()
    1.39 +{
    1.40 +	std::lock_guard<std::mutex> lock(vflock);
    1.41 +
    1.42 +	if(vfopen) {
    1.43 +		ov_clear(&vf);
    1.44 +		vfopen = false;
    1.45 +	}
    1.46 +}
    1.47 +
    1.48 +void OggVorbisStream::rewind()
    1.49 +{
    1.50 +	std::lock_guard<std::mutex> lock(vflock);
    1.51 +
    1.52 +	if(vfopen) {
    1.53 +		ov_raw_seek(&vf, 0);
    1.54 +	}
    1.55 +}
    1.56 +
    1.57 +bool OggVorbisStream::more_samples(AudioStreamBuffer *buf)
    1.58 +{
    1.59 +	std::lock_guard<std::mutex> lock(vflock);
    1.60 +
    1.61 +	vorbis_info *vinfo = ov_info(&vf, -1);
    1.62 +	buf->channels = vinfo->channels;
    1.63 +	buf->sample_rate = vinfo->rate;
    1.64 +
    1.65 +	assert(buf->channels == 2);
    1.66 +	assert(buf->sample_rate == 44100);
    1.67 +
    1.68 +	long bufsz = AUDIO_BUFFER_BYTES;
    1.69 +	long total_read = 0;
    1.70 +	while(total_read < bufsz) {
    1.71 +		int bitstream;
    1.72 +		long rd = ov_read(&vf, buf->samples + total_read, bufsz, 0, 2, 1, &bitstream);
    1.73 +		if(!rd) {
    1.74 +			bufsz = total_read;
    1.75 +		} else {
    1.76 +			total_read += rd;
    1.77 +		}
    1.78 +	}
    1.79 +
    1.80 +	if(!total_read) {
    1.81 +		buf->num_samples = 0;
    1.82 +		return false;
    1.83 +	}
    1.84 +
    1.85 +	buf->num_samples = bufsz / vinfo->channels / 2;
    1.86 +	return true;
    1.87 +}
     2.1 --- a/prototype/src/audio/ovstream.h	Wed Sep 19 05:22:43 2012 +0300
     2.2 +++ b/prototype/src/audio/ovstream.h	Wed Sep 19 08:19:10 2012 +0300
     2.3 @@ -7,8 +7,11 @@
     2.4  class OggVorbisStream : public AudioStream {
     2.5  private:
     2.6  	OggVorbis_File vf;
     2.7 +	bool vfopen;
     2.8  
     2.9 -	virtual bool more_samples();
    2.10 +	std::mutex vflock;
    2.11 +
    2.12 +	virtual bool more_samples(AudioStreamBuffer *buf);
    2.13  
    2.14  public:
    2.15  	OggVorbisStream();
    2.16 @@ -16,6 +19,8 @@
    2.17  
    2.18  	bool open(const char *fname);
    2.19  	void close();
    2.20 +
    2.21 +	virtual void rewind();
    2.22  };
    2.23  
    2.24  #endif	// OVSTREAM_H_
     3.1 --- a/prototype/src/audio/stream.cc	Wed Sep 19 05:22:43 2012 +0300
     3.2 +++ b/prototype/src/audio/stream.cc	Wed Sep 19 08:19:10 2012 +0300
     3.3 @@ -15,15 +15,17 @@
     3.4  	stop();
     3.5  }
     3.6  
     3.7 -void AudioStream::play(bool loop)
     3.8 +void AudioStream::play(enum PlayMode mode)
     3.9  {
    3.10 -	this->loop = loop;
    3.11 +	loop = (mode == PlayMode::loop);
    3.12  	done = false;
    3.13  	play_thread = std::thread(&AudioStream::poll_loop, this);
    3.14  }
    3.15  
    3.16  void AudioStream::stop()
    3.17  {
    3.18 +	std::lock_guard<std::mutex> lock(mutex);
    3.19 +
    3.20  	if(alsrc) {
    3.21  		done = true;
    3.22  		alSourceStop(alsrc);
    3.23 @@ -40,21 +42,38 @@
    3.24  void AudioStream::poll_loop()
    3.25  {
    3.26  	static const int num_buffers = 3;
    3.27 -	AudioStreamBuffer buf;
    3.28  	unsigned int albuf[num_buffers];
    3.29  
    3.30 +	mutex.lock();
    3.31 +
    3.32  	alGenSources(1, &alsrc);
    3.33  	alGenBuffers(num_buffers, albuf);
    3.34  
    3.35 +	AudioStreamBuffer *buf = new AudioStreamBuffer;
    3.36 +
    3.37  	for(int i=0; i<num_buffers; i++) {
    3.38 -		if(more_samples(&buf)) {
    3.39 +		if(more_samples(buf)) {
    3.40 +			int bufsz = buf->num_samples * buf->channels * 2;	// 2 is for 16bit samples
    3.41 +			printf("buffer data: %d samples, %d rate, %d channels\n", buf->num_samples, buf->sample_rate, buf->channels);
    3.42 +			alBufferData(albuf[i], alformat(buf), buf->samples, bufsz, buf->sample_rate);
    3.43 +			if(alGetError()) {
    3.44 +				fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
    3.45 +			}
    3.46 +
    3.47  			alSourceQueueBuffers(alsrc, 1, albuf + i);
    3.48 +			if(alGetError()) {
    3.49 +				fprintf(stderr, "failed to start streaming audio buffers\n");
    3.50 +			}
    3.51  		} else {
    3.52  			break;
    3.53  		}
    3.54  	}
    3.55 +	// start playback
    3.56 +	alSourcePlay(alsrc);
    3.57 +	mutex.unlock();
    3.58  
    3.59  	while(!done) {
    3.60 +		mutex.lock();
    3.61  		/* find out how many (if any) of the queued buffers are
    3.62  		 * done, and free to be reused.
    3.63  		 */
    3.64 @@ -66,12 +85,18 @@
    3.65  			alSourceUnqueueBuffers(alsrc, 1, &buf_id);
    3.66  
    3.67  			// if there are more data, fill it up and requeue it
    3.68 -			if(more_samples(&buf)) {
    3.69 -				int bufsz = buf.num_samples * buf.channels * 2;	// 2 is for 16bit samples
    3.70 -				alBufferData(buf_id, alformat(&buf), buf.samples, bufsz, buf.sample_rate);
    3.71 +			if(more_samples(buf)) {
    3.72 +				int bufsz = buf->num_samples * buf->channels * 2;	// 2 is for 16bit samples
    3.73 +				printf("buffer data: %d samples, %d rate, %d channels\n", buf->num_samples, buf->sample_rate, buf->channels);
    3.74 +				alBufferData(buf_id, alformat(buf), buf->samples, bufsz, buf->sample_rate);
    3.75  				if(alGetError()) {
    3.76  					fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
    3.77  				}
    3.78 +
    3.79 +				alSourceQueueBuffers(alsrc, 1, albuf + i);
    3.80 +				if(alGetError()) {
    3.81 +					fprintf(stderr, "failed to start streaming audio buffers\n");
    3.82 +				}
    3.83  			} else {
    3.84  				// no more data...
    3.85  				if(loop) {
    3.86 @@ -91,10 +116,14 @@
    3.87  			}
    3.88  		}
    3.89  
    3.90 +		mutex.unlock();
    3.91 +
    3.92  		std::chrono::milliseconds dur{poll_interval};
    3.93  		std::this_thread::sleep_for(dur);
    3.94  	}
    3.95  
    3.96 +	mutex.lock();
    3.97 +
    3.98  	// done with the data, wait for the source to stop playing before cleanup
    3.99  	int state;
   3.100  	while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) {
   3.101 @@ -104,4 +133,6 @@
   3.102  	alDeleteBuffers(num_buffers, albuf);
   3.103  	alDeleteSources(1, &alsrc);
   3.104  	alsrc = 0;
   3.105 +
   3.106 +	mutex.unlock();
   3.107  }
     4.1 --- a/prototype/src/audio/stream.h	Wed Sep 19 05:22:43 2012 +0300
     4.2 +++ b/prototype/src/audio/stream.h	Wed Sep 19 08:19:10 2012 +0300
     4.3 @@ -2,17 +2,26 @@
     4.4  #define AUDIO_STREAM_H_
     4.5  
     4.6  #include <thread>
     4.7 +#include <mutex>
     4.8 +
     4.9 +#define AUDIO_BUFFER_MSEC		1000
    4.10 +#define AUDIO_BUFFER_SAMPLES	(AUDIO_BUFFER_MSEC * 44100 / 1000)
    4.11 +#define AUDIO_BUFFER_BYTES		(AUDIO_BUFFER_SAMPLES * 2 * 2)
    4.12  
    4.13  struct AudioStreamBuffer {
    4.14 -	void *samples;
    4.15 +	char samples[AUDIO_BUFFER_BYTES];
    4.16  	int num_samples;
    4.17  	int channels;
    4.18  	int sample_rate;
    4.19  };
    4.20  
    4.21 +enum class PlayMode { once, loop };
    4.22 +
    4.23  class AudioStream {
    4.24  private:
    4.25  	std::thread play_thread;
    4.26 +	std::mutex mutex;
    4.27 +
    4.28  	bool done, loop;
    4.29  	unsigned int poll_interval;
    4.30  	unsigned int alsrc;
    4.31 @@ -25,7 +34,7 @@
    4.32  	AudioStream();
    4.33  	virtual ~AudioStream();
    4.34  
    4.35 -	void play(bool loop = false);
    4.36 +	void play(enum PlayMode mode);
    4.37  	void stop();
    4.38  
    4.39  	virtual void rewind() = 0;
     5.1 --- a/prototype/src/main.cc	Wed Sep 19 05:22:43 2012 +0300
     5.2 +++ b/prototype/src/main.cc	Wed Sep 19 08:19:10 2012 +0300
     5.3 @@ -16,6 +16,7 @@
     5.4  #include "timer.h"
     5.5  #include "audio/audio.h"
     5.6  #include "audio/source.h"
     5.7 +#include "audio/ovstream.h"
     5.8  
     5.9  bool init(int xsz, int ysz);
    5.10  void cleanup();
    5.11 @@ -45,6 +46,7 @@
    5.12  static bool show_con;
    5.13  
    5.14  static AudioSource *move_sound;
    5.15 +static OggVorbisStream *music;
    5.16  
    5.17  int main(int argc, char **argv)
    5.18  {
    5.19 @@ -104,6 +106,14 @@
    5.20  	if(cfg.sound) {
    5.21  		move_sound = new AudioSource;
    5.22  		move_sound->set_volume(0.4);
    5.23 +
    5.24 +		music = new OggVorbisStream;
    5.25 +		if(music->open(datafile_path("bgtrack.ogg"))) {
    5.26 +			music->play(PlayMode::loop);
    5.27 +		} else {
    5.28 +			delete music;
    5.29 +			music = 0;
    5.30 +		}
    5.31  	}
    5.32  
    5.33  	rend = new DeferredRenderer();
    5.34 @@ -151,6 +161,7 @@
    5.35  	cleanup_cmdcon();
    5.36  
    5.37  	if(cfg.sound) {
    5.38 +		delete music;
    5.39  		delete move_sound;
    5.40  		destroy_audio();
    5.41  	}