dungeon_crawler

changeset 54:995191474cc0

writting the stream audio player
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 19 Sep 2012 05:22:43 +0300
parents 1ea56011c1ff
children 4c427e28ca00
files prototype/src/audio/stream.cc prototype/src/audio/stream.h
diffstat 2 files changed, 112 insertions(+), 3 deletions(-) [+]
line diff
     1.1 --- a/prototype/src/audio/stream.cc	Wed Sep 19 01:08:41 2012 +0300
     1.2 +++ b/prototype/src/audio/stream.cc	Wed Sep 19 05:22:43 2012 +0300
     1.3 @@ -1,13 +1,107 @@
     1.4 +#include <stdio.h>
     1.5  #include "stream.h"
     1.6 +#include "openal.h"
     1.7 +
     1.8 +AudioStream::AudioStream()
     1.9 +{
    1.10 +	alsrc = 0;
    1.11 +	poll_interval = 250;
    1.12 +	done = true;
    1.13 +	loop = false;
    1.14 +}
    1.15  
    1.16  AudioStream::~AudioStream()
    1.17  {
    1.18 +	stop();
    1.19  }
    1.20  
    1.21 -void AudioStream::play()
    1.22 +void AudioStream::play(bool loop)
    1.23  {
    1.24 +	this->loop = loop;
    1.25 +	done = false;
    1.26 +	play_thread = std::thread(&AudioStream::poll_loop, this);
    1.27  }
    1.28  
    1.29  void AudioStream::stop()
    1.30  {
    1.31 +	if(alsrc) {
    1.32 +		done = true;
    1.33 +		alSourceStop(alsrc);
    1.34 +		play_thread.join();
    1.35 +	}
    1.36  }
    1.37 +
    1.38 +static ALenum alformat(AudioStreamBuffer *buf)
    1.39 +{
    1.40 +	return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
    1.41 +}
    1.42 +
    1.43 +// thread function
    1.44 +void AudioStream::poll_loop()
    1.45 +{
    1.46 +	static const int num_buffers = 3;
    1.47 +	AudioStreamBuffer buf;
    1.48 +	unsigned int albuf[num_buffers];
    1.49 +
    1.50 +	alGenSources(1, &alsrc);
    1.51 +	alGenBuffers(num_buffers, albuf);
    1.52 +
    1.53 +	for(int i=0; i<num_buffers; i++) {
    1.54 +		if(more_samples(&buf)) {
    1.55 +			alSourceQueueBuffers(alsrc, 1, albuf + i);
    1.56 +		} else {
    1.57 +			break;
    1.58 +		}
    1.59 +	}
    1.60 +
    1.61 +	while(!done) {
    1.62 +		/* find out how many (if any) of the queued buffers are
    1.63 +		 * done, and free to be reused.
    1.64 +		 */
    1.65 +		int num_buf_done;
    1.66 +		alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done);
    1.67 +		for(int i=0; i<num_buf_done; i++) {
    1.68 +			// unqueue a buffer...
    1.69 +			unsigned int buf_id;
    1.70 +			alSourceUnqueueBuffers(alsrc, 1, &buf_id);
    1.71 +
    1.72 +			// if there are more data, fill it up and requeue it
    1.73 +			if(more_samples(&buf)) {
    1.74 +				int bufsz = buf.num_samples * buf.channels * 2;	// 2 is for 16bit samples
    1.75 +				alBufferData(buf_id, alformat(&buf), buf.samples, bufsz, buf.sample_rate);
    1.76 +				if(alGetError()) {
    1.77 +					fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
    1.78 +				}
    1.79 +			} else {
    1.80 +				// no more data...
    1.81 +				if(loop) {
    1.82 +					rewind();
    1.83 +				} else {
    1.84 +					done = true;
    1.85 +				}
    1.86 +			}
    1.87 +		}
    1.88 +
    1.89 +		if(num_buf_done) {
    1.90 +			// make sure playback didn't stop
    1.91 +			int state;
    1.92 +			alGetSourcei(alsrc, AL_SOURCE_STATE, &state);
    1.93 +			if(state != AL_PLAYING) {
    1.94 +				alSourcePlay(alsrc);
    1.95 +			}
    1.96 +		}
    1.97 +
    1.98 +		std::chrono::milliseconds dur{poll_interval};
    1.99 +		std::this_thread::sleep_for(dur);
   1.100 +	}
   1.101 +
   1.102 +	// done with the data, wait for the source to stop playing before cleanup
   1.103 +	int state;
   1.104 +	while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) {
   1.105 +		std::this_thread::yield();
   1.106 +	}
   1.107 +
   1.108 +	alDeleteBuffers(num_buffers, albuf);
   1.109 +	alDeleteSources(1, &alsrc);
   1.110 +	alsrc = 0;
   1.111 +}
     2.1 --- a/prototype/src/audio/stream.h	Wed Sep 19 01:08:41 2012 +0300
     2.2 +++ b/prototype/src/audio/stream.h	Wed Sep 19 05:22:43 2012 +0300
     2.3 @@ -3,17 +3,32 @@
     2.4  
     2.5  #include <thread>
     2.6  
     2.7 +struct AudioStreamBuffer {
     2.8 +	void *samples;
     2.9 +	int num_samples;
    2.10 +	int channels;
    2.11 +	int sample_rate;
    2.12 +};
    2.13 +
    2.14  class AudioStream {
    2.15  private:
    2.16  	std::thread play_thread;
    2.17 +	bool done, loop;
    2.18 +	unsigned int poll_interval;
    2.19 +	unsigned int alsrc;
    2.20  
    2.21 -	virtual bool more_samples() = 0;
    2.22 +	virtual bool more_samples(AudioStreamBuffer *buf) = 0;
    2.23 +
    2.24 +	void poll_loop();
    2.25  
    2.26  public:
    2.27 +	AudioStream();
    2.28  	virtual ~AudioStream();
    2.29  
    2.30 -	void play();
    2.31 +	void play(bool loop = false);
    2.32  	void stop();
    2.33 +
    2.34 +	virtual void rewind() = 0;
    2.35  };
    2.36  
    2.37  #endif	// AUDIO_STREAM_H_