10 static ALenum alformat(AudioStreamBuffer *buf)
12 return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
15 AudioStream::AudioStream()
24 pthread_mutex_init(&mutex, 0);
27 AudioStream::~AudioStream()
32 bool AudioStream::open(const char *fname)
37 void AudioStream::close()
41 void AudioStream::set_volume(float vol)
43 if(vol < 0.0) vol = 0.0;
44 if(vol > 1.0) vol = 1.0;
48 pthread_mutex_lock(&mutex);
50 alSourcef(alsrc, AL_GAIN, vol);
52 pthread_mutex_unlock(&mutex);
55 float AudioStream::get_volume() const
59 void AudioStream::set_pitch(float pitch)
61 if(pitch < 0.0) pitch = 0.0;
62 if(pitch > 1.0) pitch = 1.0;
66 pthread_mutex_lock(&mutex);
68 alSourcef(alsrc, AL_PITCH, pitch);
70 pthread_mutex_unlock(&mutex);
73 float AudioStream::get_pitch() const
79 static void *thread_func(void *arg)
81 AudioStream *astr = (AudioStream*)arg;
86 void AudioStream::play(AUDIO_PLAYMODE mode)
88 loop = (mode == AUDIO_PLAYMODE_LOOP);
91 if(pthread_create(&play_thread, 0, thread_func, this) != 0) {
92 error_log("failed to create music playback thread\n");
96 void AudioStream::stop()
98 pthread_mutex_lock(&mutex);
103 printf("waiting for the music thread to stop\n");
104 pthread_mutex_unlock(&mutex);
105 pthread_join(play_thread, 0);
107 pthread_mutex_unlock(&mutex);
111 // gets an array of buffers and returns the index of the one matching id
112 static inline int find_buffer(unsigned int id, unsigned int *barr, int num)
114 for(int i=0; i<num; i++) {
123 static int queued_idx_list[AUDIO_NUM_BUFFERS];
124 static int queued_idx_head = 0;
125 static int queued_idx_tail = 0;
127 #define BUFQ_UNQUEUE() \
129 queued_idx_tail = (queued_idx_tail + 1) % AUDIO_NUM_BUFFERS; \
133 #define BUFQ_QUEUE(idx) \
135 queued_idx_head = (queued_idx_head + 1) % AUDIO_NUM_BUFFERS; \
136 queued_idx_list[queued_idx_head] = idx; \
140 void AudioStream::poll_loop()
142 long prev_msec = -1000;
143 unsigned int albuf[AUDIO_NUM_BUFFERS];
145 pthread_mutex_lock(&mutex);
146 alGenSources(1, &alsrc);
147 alSourcei(alsrc, AL_LOOPING, AL_FALSE);
148 alSourcef(alsrc, AL_GAIN, volume);
149 alSourcef(alsrc, AL_PITCH, pitch);
150 alGenBuffers(AUDIO_NUM_BUFFERS, albuf);
151 AudioStreamBuffer *buf = new AudioStreamBuffer;
153 assert(alGetError() == 0);
154 for(int i=0; i<AUDIO_NUM_BUFFERS; i++) {
155 if(more_samples(buf)) {
156 int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples
157 alBufferData(albuf[i], alformat(buf), buf->samples, bufsz, buf->sample_rate);
160 fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
163 alSourceQueueBuffers(alsrc, 1, albuf + i);
167 fprintf(stderr, "failed to start streaming audio buffers\n");
177 /* find out how many (if any) of the queued buffers are
178 * done, and free to be reused.
181 alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done);
182 for(int i=0; i<num_buf_done; i++) {
184 // unqueue a buffer...
186 alSourceUnqueueBuffers(alsrc, 1, &buf_id);
188 if((err = alGetError())) {
189 fprintf(stderr, "failed to unqueue used buffer (error: %x)\n", err);
195 // find out which one of our al buffers we just unqueued
196 int bidx = find_buffer(buf_id, albuf, AUDIO_NUM_BUFFERS);
201 alGetSourcei(alsrc, AL_LOOPING, &looping);
202 assert(looping == AL_FALSE);
203 /*if((unsigned int)cur_buf == buf_id) {
207 // if there are more data, fill it up and requeue it
208 if(more_samples(buf)) {
209 int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples
210 alBufferData(buf_id, alformat(buf), buf->samples, bufsz, buf->sample_rate);
211 if((err = alGetError())) {
212 fprintf(stderr, "failed to load sample data into OpenAL buffer (error: %x)\n", err);
215 alSourceQueueBuffers(alsrc, 1, &buf_id);
217 fprintf(stderr, "failed to start streaming audio buffers\n");
223 debug_log("audio stream looping...\n");
232 // make sure playback didn't stop
234 alGetSourcei(alsrc, AL_SOURCE_STATE, &state);
235 if(state != AL_PLAYING) {
240 pthread_mutex_unlock(&mutex);
241 long msec = get_time_msec();
242 long dt = msec - prev_msec;
245 if(dt < (long)poll_interval) {
246 sleep_msec(poll_interval - dt);
250 pthread_mutex_lock(&mutex);
254 // done with the data, wait for the source to stop playing before cleanup
256 while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) {
260 alDeleteBuffers(AUDIO_NUM_BUFFERS, albuf);
261 alDeleteSources(1, &alsrc);
263 pthread_mutex_unlock(&mutex);