dungeon_crawler

annotate prototype/src/audio/stream.cc @ 69:45172d087ebe

fixed some windows compatibility crap fixed a terrible stack overrun in psys (TODO: remember to fix in libpsys too)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 07 Oct 2012 03:42:44 +0200
parents f9b8bbebc9b3
children
rev   line source
nuclear@54 1 #include <stdio.h>
nuclear@56 2 #include <assert.h>
nuclear@53 3 #include "stream.h"
nuclear@54 4 #include "openal.h"
nuclear@54 5
nuclear@54 6 AudioStream::AudioStream()
nuclear@54 7 {
nuclear@54 8 alsrc = 0;
nuclear@54 9 poll_interval = 250;
nuclear@54 10 done = true;
nuclear@54 11 loop = false;
nuclear@56 12 volume = 1.0;
nuclear@54 13 }
nuclear@53 14
nuclear@53 15 AudioStream::~AudioStream()
nuclear@53 16 {
nuclear@54 17 stop();
nuclear@53 18 }
nuclear@53 19
nuclear@56 20 void AudioStream::set_volume(float vol)
nuclear@56 21 {
nuclear@56 22 volume = vol;
nuclear@56 23
nuclear@56 24 std::lock_guard<std::mutex> lock(mutex);
nuclear@56 25 if(alsrc) {
nuclear@56 26 alSourcef(alsrc, AL_GAIN, vol);
nuclear@56 27 }
nuclear@56 28 }
nuclear@56 29
nuclear@56 30 float AudioStream::get_volume() const
nuclear@56 31 {
nuclear@56 32 return volume;
nuclear@56 33 }
nuclear@56 34
nuclear@69 35 void AudioStream::play(PlayMode mode)
nuclear@53 36 {
nuclear@55 37 loop = (mode == PlayMode::loop);
nuclear@54 38 done = false;
nuclear@54 39 play_thread = std::thread(&AudioStream::poll_loop, this);
nuclear@53 40 }
nuclear@53 41
nuclear@53 42 void AudioStream::stop()
nuclear@53 43 {
nuclear@56 44 mutex.lock();
nuclear@54 45 if(alsrc) {
nuclear@54 46 done = true;
nuclear@54 47 alSourceStop(alsrc);
nuclear@56 48 printf("waiting for the music thread to stop\n");
nuclear@56 49 mutex.unlock();
nuclear@54 50 play_thread.join();
nuclear@56 51 } else {
nuclear@56 52 mutex.unlock();
nuclear@54 53 }
nuclear@53 54 }
nuclear@54 55
nuclear@54 56 static ALenum alformat(AudioStreamBuffer *buf)
nuclear@54 57 {
nuclear@54 58 return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
nuclear@54 59 }
nuclear@54 60
nuclear@54 61 // thread function
nuclear@54 62 void AudioStream::poll_loop()
nuclear@54 63 {
nuclear@54 64 static const int num_buffers = 3;
nuclear@54 65 unsigned int albuf[num_buffers];
nuclear@54 66
nuclear@55 67 mutex.lock();
nuclear@55 68
nuclear@54 69 alGenSources(1, &alsrc);
nuclear@56 70 alSourcei(alsrc, AL_LOOPING, AL_FALSE);
nuclear@56 71 alSourcef(alsrc, AL_GAIN, volume);
nuclear@56 72
nuclear@54 73 alGenBuffers(num_buffers, albuf);
nuclear@54 74
nuclear@55 75 AudioStreamBuffer *buf = new AudioStreamBuffer;
nuclear@55 76
nuclear@54 77 for(int i=0; i<num_buffers; i++) {
nuclear@55 78 if(more_samples(buf)) {
nuclear@55 79 int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples
nuclear@55 80 alBufferData(albuf[i], alformat(buf), buf->samples, bufsz, buf->sample_rate);
nuclear@55 81 if(alGetError()) {
nuclear@55 82 fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
nuclear@55 83 }
nuclear@55 84
nuclear@54 85 alSourceQueueBuffers(alsrc, 1, albuf + i);
nuclear@55 86 if(alGetError()) {
nuclear@55 87 fprintf(stderr, "failed to start streaming audio buffers\n");
nuclear@55 88 }
nuclear@54 89 } else {
nuclear@54 90 break;
nuclear@54 91 }
nuclear@54 92 }
nuclear@55 93 // start playback
nuclear@55 94 alSourcePlay(alsrc);
nuclear@54 95
nuclear@54 96 while(!done) {
nuclear@54 97 /* find out how many (if any) of the queued buffers are
nuclear@54 98 * done, and free to be reused.
nuclear@54 99 */
nuclear@54 100 int num_buf_done;
nuclear@54 101 alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done);
nuclear@54 102 for(int i=0; i<num_buf_done; i++) {
nuclear@56 103 int err;
nuclear@54 104 // unqueue a buffer...
nuclear@54 105 unsigned int buf_id;
nuclear@54 106 alSourceUnqueueBuffers(alsrc, 1, &buf_id);
nuclear@56 107 if((err = alGetError())) {
nuclear@56 108 fprintf(stderr, "failed to unqueue used buffer (error: %x)\n", err);
nuclear@56 109 num_buf_done = i;
nuclear@56 110 break;
nuclear@56 111 }
nuclear@56 112
nuclear@56 113 int looping;
nuclear@56 114 alGetSourcei(alsrc, AL_LOOPING, &looping);
nuclear@56 115 assert(looping == AL_FALSE);
nuclear@56 116
nuclear@56 117 int cur_buf;
nuclear@56 118 alGetSourcei(alsrc, AL_BUFFER, &cur_buf);
nuclear@56 119 if((unsigned int)cur_buf == buf_id) {
nuclear@56 120 continue;
nuclear@56 121 }
nuclear@54 122
nuclear@54 123 // if there are more data, fill it up and requeue it
nuclear@55 124 if(more_samples(buf)) {
nuclear@55 125 int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples
nuclear@55 126 alBufferData(buf_id, alformat(buf), buf->samples, bufsz, buf->sample_rate);
nuclear@56 127 if((err = alGetError())) {
nuclear@56 128 fprintf(stderr, "failed to load sample data into OpenAL buffer (error: %x)\n", err);
nuclear@54 129 }
nuclear@55 130
nuclear@56 131 alSourceQueueBuffers(alsrc, 1, &buf_id);
nuclear@55 132 if(alGetError()) {
nuclear@55 133 fprintf(stderr, "failed to start streaming audio buffers\n");
nuclear@55 134 }
nuclear@54 135 } else {
nuclear@54 136 // no more data...
nuclear@54 137 if(loop) {
nuclear@54 138 rewind();
nuclear@54 139 } else {
nuclear@54 140 done = true;
nuclear@54 141 }
nuclear@54 142 }
nuclear@54 143 }
nuclear@54 144
nuclear@54 145 if(num_buf_done) {
nuclear@54 146 // make sure playback didn't stop
nuclear@54 147 int state;
nuclear@54 148 alGetSourcei(alsrc, AL_SOURCE_STATE, &state);
nuclear@54 149 if(state != AL_PLAYING) {
nuclear@54 150 alSourcePlay(alsrc);
nuclear@54 151 }
nuclear@54 152 }
nuclear@54 153
nuclear@55 154 mutex.unlock();
nuclear@55 155
nuclear@69 156 std::chrono::milliseconds dur(poll_interval);
nuclear@54 157 std::this_thread::sleep_for(dur);
nuclear@56 158
nuclear@56 159 mutex.lock();
nuclear@54 160 }
nuclear@54 161
nuclear@54 162 // done with the data, wait for the source to stop playing before cleanup
nuclear@54 163 int state;
nuclear@54 164 while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) {
nuclear@54 165 std::this_thread::yield();
nuclear@54 166 }
nuclear@54 167
nuclear@54 168 alDeleteBuffers(num_buffers, albuf);
nuclear@54 169 alDeleteSources(1, &alsrc);
nuclear@54 170 alsrc = 0;
nuclear@55 171
nuclear@55 172 mutex.unlock();
nuclear@54 173 }