nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "openal.h" nuclear@0: #include "stream.h" nuclear@0: #include "timer.h" nuclear@0: nuclear@0: static ALenum alformat(AudioStreamBuffer *buf) nuclear@0: { nuclear@0: return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; nuclear@0: } nuclear@0: nuclear@0: AudioStream::AudioStream() nuclear@0: { nuclear@0: alsrc = 0; nuclear@0: poll_interval = 25; nuclear@0: done = true; nuclear@0: loop = false; nuclear@0: volume = 1.0; nuclear@0: pitch = 1.0; nuclear@0: nuclear@0: pthread_mutex_init(&mutex, 0); nuclear@0: } nuclear@0: nuclear@0: AudioStream::~AudioStream() nuclear@0: { nuclear@0: stop(); nuclear@0: } nuclear@0: nuclear@0: bool AudioStream::open(const char *fname) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: void AudioStream::close() nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: void AudioStream::set_volume(float vol) nuclear@0: { nuclear@0: if(vol < 0.0) vol = 0.0; nuclear@0: if(vol > 1.0) vol = 1.0; nuclear@0: nuclear@0: volume = vol; nuclear@0: nuclear@0: pthread_mutex_lock(&mutex); nuclear@0: if(alsrc) { nuclear@0: alSourcef(alsrc, AL_GAIN, vol); nuclear@0: } nuclear@0: pthread_mutex_unlock(&mutex); nuclear@0: } nuclear@0: nuclear@0: float AudioStream::get_volume() const nuclear@0: { nuclear@0: return volume; nuclear@0: } nuclear@0: void AudioStream::set_pitch(float pitch) nuclear@0: { nuclear@0: if(pitch < 0.0) pitch = 0.0; nuclear@0: if(pitch > 1.0) pitch = 1.0; nuclear@0: nuclear@0: this->pitch = pitch; nuclear@0: nuclear@0: pthread_mutex_lock(&mutex); nuclear@0: if(alsrc) { nuclear@0: alSourcef(alsrc, AL_PITCH, pitch); nuclear@0: } nuclear@0: pthread_mutex_unlock(&mutex); nuclear@0: } nuclear@0: nuclear@0: float AudioStream::get_pitch() const nuclear@0: { nuclear@0: return pitch; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: static void *thread_func(void *arg) nuclear@0: { nuclear@0: AudioStream *astr = (AudioStream*)arg; nuclear@0: astr->poll_loop(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void AudioStream::play(AUDIO_PLAYMODE mode) nuclear@0: { nuclear@0: loop = (mode == AUDIO_PLAYMODE_LOOP); nuclear@0: done = false; nuclear@0: nuclear@0: if(pthread_create(&play_thread, 0, thread_func, this) != 0) { nuclear@0: fprintf(stderr, "failed to create music playback thread\n"); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void AudioStream::stop() nuclear@0: { nuclear@0: pthread_mutex_lock(&mutex); nuclear@0: nuclear@0: if(alsrc) { nuclear@0: done = true; nuclear@0: //alSourceStop(alsrc); nuclear@0: printf("waiting for the music thread to stop\n"); nuclear@0: pthread_mutex_unlock(&mutex); nuclear@0: pthread_join(play_thread, 0); nuclear@0: } else { nuclear@0: pthread_mutex_unlock(&mutex); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // gets an array of buffers and returns the index of the one matching id nuclear@0: static inline int find_buffer(unsigned int id, unsigned int *barr, int num) nuclear@0: { nuclear@0: for(int i=0; inum_samples * buf->channels * 2; // 2 is for 16bit samples nuclear@0: alBufferData(albuf[i], alformat(buf), buf->samples, bufsz, buf->sample_rate); nuclear@0: nuclear@0: if(alGetError()) { nuclear@0: fprintf(stderr, "failed to load sample data into OpenAL buffer\n"); nuclear@0: } nuclear@0: nuclear@0: alSourceQueueBuffers(alsrc, 1, albuf + i); nuclear@0: BUFQ_QUEUE(i); nuclear@0: nuclear@0: if(alGetError()) { nuclear@0: fprintf(stderr, "failed to start streaming audio buffers\n"); nuclear@0: } nuclear@0: } else { nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // start playback nuclear@0: alSourcePlay(alsrc); nuclear@0: while(!done) { nuclear@0: /* find out how many (if any) of the queued buffers are nuclear@0: * done, and free to be reused. nuclear@0: */ nuclear@0: int num_buf_done; nuclear@0: alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done); nuclear@0: for(int i=0; inum_samples * buf->channels * 2; // 2 is for 16bit samples nuclear@0: alBufferData(buf_id, alformat(buf), buf->samples, bufsz, buf->sample_rate); nuclear@0: if((err = alGetError())) { nuclear@0: fprintf(stderr, "failed to load sample data into OpenAL buffer (error: %x)\n", err); nuclear@0: } nuclear@0: nuclear@0: alSourceQueueBuffers(alsrc, 1, &buf_id); nuclear@0: if(alGetError()) { nuclear@0: fprintf(stderr, "failed to start streaming audio buffers\n"); nuclear@0: } nuclear@0: BUFQ_QUEUE(bidx); nuclear@0: } else { nuclear@0: // no more data... nuclear@0: if(loop) { nuclear@0: printf("audio stream looping...\n"); nuclear@0: rewind(); nuclear@0: } else { nuclear@0: done = true; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(num_buf_done) { nuclear@0: // make sure playback didn't stop nuclear@0: int state; nuclear@0: alGetSourcei(alsrc, AL_SOURCE_STATE, &state); nuclear@0: if(state != AL_PLAYING) { nuclear@0: alSourcePlay(alsrc); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: pthread_mutex_unlock(&mutex); nuclear@0: long msec = get_time_msec(); nuclear@0: long dt = msec - prev_msec; nuclear@0: prev_msec = msec; nuclear@0: nuclear@0: if(dt < (long)poll_interval) { nuclear@0: sleep_msec(poll_interval - dt); nuclear@0: } else { nuclear@0: sched_yield(); nuclear@0: } nuclear@0: pthread_mutex_lock(&mutex); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // done with the data, wait for the source to stop playing before cleanup nuclear@0: int state; nuclear@0: while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) { nuclear@0: sched_yield(); nuclear@0: } nuclear@0: nuclear@0: alDeleteBuffers(AUDIO_NUM_BUFFERS, albuf); nuclear@0: alDeleteSources(1, &alsrc); nuclear@0: alsrc = 0; nuclear@0: pthread_mutex_unlock(&mutex); nuclear@0: nuclear@0: delete buf; nuclear@0: }