dungeon_crawler

view prototype/src/audio/stream.cc @ 56:f9b8bbebc9b3

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