# HG changeset patch # User John Tsiombikas # Date 1348031950 -10800 # Node ID 4c427e28ca0085c0c01d7c217241ef1576eb82fa # Parent 995191474cc0395fd7bb5cb0b8eaaf9048c1c28f music playback bugfixing diff -r 995191474cc0 -r 4c427e28ca00 prototype/src/audio/ovstream.cc --- a/prototype/src/audio/ovstream.cc Wed Sep 19 05:22:43 2012 +0300 +++ b/prototype/src/audio/ovstream.cc Wed Sep 19 08:19:10 2012 +0300 @@ -1,16 +1,80 @@ +#include +#include #include "ovstream.h" OggVorbisStream::OggVorbisStream() { - ov_clear(&vf); + vfopen = false; } OggVorbisStream::~OggVorbisStream() { - ov_clear(&vf); + close(); } -bool OggVorbisStream::more_samples() +bool OggVorbisStream::open(const char *fname) { - return false; + close(); + + std::lock_guard lock(vflock); + + printf("opening ogg/vorbis stream: %s\n", fname ? fname : ""); + + if(!fname || ov_fopen(fname, &vf) != 0) { + fprintf(stderr, "failed to open ogg/vorbis stream: %s\n", fname ? fname : ""); + return false; + } + vfopen = true; + return true; } + +void OggVorbisStream::close() +{ + std::lock_guard lock(vflock); + + if(vfopen) { + ov_clear(&vf); + vfopen = false; + } +} + +void OggVorbisStream::rewind() +{ + std::lock_guard lock(vflock); + + if(vfopen) { + ov_raw_seek(&vf, 0); + } +} + +bool OggVorbisStream::more_samples(AudioStreamBuffer *buf) +{ + std::lock_guard lock(vflock); + + vorbis_info *vinfo = ov_info(&vf, -1); + buf->channels = vinfo->channels; + buf->sample_rate = vinfo->rate; + + assert(buf->channels == 2); + assert(buf->sample_rate == 44100); + + long bufsz = AUDIO_BUFFER_BYTES; + long total_read = 0; + while(total_read < bufsz) { + int bitstream; + long rd = ov_read(&vf, buf->samples + total_read, bufsz, 0, 2, 1, &bitstream); + if(!rd) { + bufsz = total_read; + } else { + total_read += rd; + } + } + + if(!total_read) { + buf->num_samples = 0; + return false; + } + + buf->num_samples = bufsz / vinfo->channels / 2; + return true; +} diff -r 995191474cc0 -r 4c427e28ca00 prototype/src/audio/ovstream.h --- a/prototype/src/audio/ovstream.h Wed Sep 19 05:22:43 2012 +0300 +++ b/prototype/src/audio/ovstream.h Wed Sep 19 08:19:10 2012 +0300 @@ -7,8 +7,11 @@ class OggVorbisStream : public AudioStream { private: OggVorbis_File vf; + bool vfopen; - virtual bool more_samples(); + std::mutex vflock; + + virtual bool more_samples(AudioStreamBuffer *buf); public: OggVorbisStream(); @@ -16,6 +19,8 @@ bool open(const char *fname); void close(); + + virtual void rewind(); }; #endif // OVSTREAM_H_ diff -r 995191474cc0 -r 4c427e28ca00 prototype/src/audio/stream.cc --- a/prototype/src/audio/stream.cc Wed Sep 19 05:22:43 2012 +0300 +++ b/prototype/src/audio/stream.cc Wed Sep 19 08:19:10 2012 +0300 @@ -15,15 +15,17 @@ stop(); } -void AudioStream::play(bool loop) +void AudioStream::play(enum PlayMode mode) { - this->loop = loop; + loop = (mode == PlayMode::loop); done = false; play_thread = std::thread(&AudioStream::poll_loop, this); } void AudioStream::stop() { + std::lock_guard lock(mutex); + if(alsrc) { done = true; alSourceStop(alsrc); @@ -40,21 +42,38 @@ void AudioStream::poll_loop() { static const int num_buffers = 3; - AudioStreamBuffer buf; unsigned int albuf[num_buffers]; + mutex.lock(); + alGenSources(1, &alsrc); alGenBuffers(num_buffers, albuf); + AudioStreamBuffer *buf = new AudioStreamBuffer; + for(int i=0; inum_samples * buf->channels * 2; // 2 is for 16bit samples + printf("buffer data: %d samples, %d rate, %d channels\n", buf->num_samples, buf->sample_rate, buf->channels); + alBufferData(albuf[i], alformat(buf), buf->samples, bufsz, buf->sample_rate); + if(alGetError()) { + fprintf(stderr, "failed to load sample data into OpenAL buffer\n"); + } + alSourceQueueBuffers(alsrc, 1, albuf + i); + if(alGetError()) { + fprintf(stderr, "failed to start streaming audio buffers\n"); + } } else { break; } } + // start playback + alSourcePlay(alsrc); + mutex.unlock(); while(!done) { + mutex.lock(); /* find out how many (if any) of the queued buffers are * done, and free to be reused. */ @@ -66,12 +85,18 @@ alSourceUnqueueBuffers(alsrc, 1, &buf_id); // if there are more data, fill it up and requeue it - if(more_samples(&buf)) { - int bufsz = buf.num_samples * buf.channels * 2; // 2 is for 16bit samples - alBufferData(buf_id, alformat(&buf), buf.samples, bufsz, buf.sample_rate); + if(more_samples(buf)) { + int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples + printf("buffer data: %d samples, %d rate, %d channels\n", buf->num_samples, buf->sample_rate, buf->channels); + alBufferData(buf_id, alformat(buf), buf->samples, bufsz, buf->sample_rate); if(alGetError()) { fprintf(stderr, "failed to load sample data into OpenAL buffer\n"); } + + alSourceQueueBuffers(alsrc, 1, albuf + i); + if(alGetError()) { + fprintf(stderr, "failed to start streaming audio buffers\n"); + } } else { // no more data... if(loop) { @@ -91,10 +116,14 @@ } } + mutex.unlock(); + std::chrono::milliseconds dur{poll_interval}; std::this_thread::sleep_for(dur); } + mutex.lock(); + // done with the data, wait for the source to stop playing before cleanup int state; while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) { @@ -104,4 +133,6 @@ alDeleteBuffers(num_buffers, albuf); alDeleteSources(1, &alsrc); alsrc = 0; + + mutex.unlock(); } diff -r 995191474cc0 -r 4c427e28ca00 prototype/src/audio/stream.h --- a/prototype/src/audio/stream.h Wed Sep 19 05:22:43 2012 +0300 +++ b/prototype/src/audio/stream.h Wed Sep 19 08:19:10 2012 +0300 @@ -2,17 +2,26 @@ #define AUDIO_STREAM_H_ #include +#include + +#define AUDIO_BUFFER_MSEC 1000 +#define AUDIO_BUFFER_SAMPLES (AUDIO_BUFFER_MSEC * 44100 / 1000) +#define AUDIO_BUFFER_BYTES (AUDIO_BUFFER_SAMPLES * 2 * 2) struct AudioStreamBuffer { - void *samples; + char samples[AUDIO_BUFFER_BYTES]; int num_samples; int channels; int sample_rate; }; +enum class PlayMode { once, loop }; + class AudioStream { private: std::thread play_thread; + std::mutex mutex; + bool done, loop; unsigned int poll_interval; unsigned int alsrc; @@ -25,7 +34,7 @@ AudioStream(); virtual ~AudioStream(); - void play(bool loop = false); + void play(enum PlayMode mode); void stop(); virtual void rewind() = 0; diff -r 995191474cc0 -r 4c427e28ca00 prototype/src/main.cc --- a/prototype/src/main.cc Wed Sep 19 05:22:43 2012 +0300 +++ b/prototype/src/main.cc Wed Sep 19 08:19:10 2012 +0300 @@ -16,6 +16,7 @@ #include "timer.h" #include "audio/audio.h" #include "audio/source.h" +#include "audio/ovstream.h" bool init(int xsz, int ysz); void cleanup(); @@ -45,6 +46,7 @@ static bool show_con; static AudioSource *move_sound; +static OggVorbisStream *music; int main(int argc, char **argv) { @@ -104,6 +106,14 @@ if(cfg.sound) { move_sound = new AudioSource; move_sound->set_volume(0.4); + + music = new OggVorbisStream; + if(music->open(datafile_path("bgtrack.ogg"))) { + music->play(PlayMode::loop); + } else { + delete music; + music = 0; + } } rend = new DeferredRenderer(); @@ -151,6 +161,7 @@ cleanup_cmdcon(); if(cfg.sound) { + delete music; delete move_sound; destroy_audio(); }