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