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 }