X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fsound.cc;h=bcd86670c302d4e6ff17d3bc0133eb73043cd9d9;hp=f3060540eba005087560423b4dcdb0d167a524c6;hb=HEAD;hpb=e9a16d767785b1a903a4466ff26265a5f7dae9e5 diff --git a/src/moof/sound.cc b/src/moof/sound.cc index f306054..bcd8667 100644 --- a/src/moof/sound.cc +++ b/src/moof/sound.cc @@ -1,13 +1,11 @@ -/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * -* vi:ts=4 sw=4 tw=75 -* * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * -**************************************************************************/ +*****************************************************************************/ #include #include @@ -20,24 +18,26 @@ #include #include -#include "log.hh" +#include "debug.hh" #include "sound.hh" #include "resource.hh" +#include "runloop.hh" +#include "thread.hh" #include "timer.hh" #ifndef BUF_SIZE -#define BUF_SIZE (4096) +#define BUF_SIZE 8192 #endif -#define NUM_SAMPLE_BITS (16) +#define NUM_SAMPLE_BITS 16 namespace moof { -/*] Sound backend - *************************************************************************/ +thread stream_thread_; + class sound_backend { @@ -52,27 +52,25 @@ public: if (!al_device || !al_context) { const char* error = alcGetString(al_device, - alcGetError(al_device)); + alcGetError(al_device)); log_error("audio subsystem initialization failure", error); } else { alcMakeContextCurrent(al_context); - log_info << "opened sound device `" - << alcGetString(al_device, - ALC_DEFAULT_DEVICE_SPECIFIER) - << "'" << std::endl; + log_info << "opened sound device `" << + alcGetString(al_device, ALC_DEFAULT_DEVICE_SPECIFIER) << + "'" << std::endl; } } } - sound_backend(const sound_backend& backend) { ++retain_count; } - sound_backend& operator=(const sound_backend& backend) + sound_backend& operator = (const sound_backend& backend) { ++retain_count; return *this; @@ -88,13 +86,12 @@ public: } } - - static int retain_count; + static int retain_count; static ALCdevice* al_device; static ALCcontext* al_context; }; -int sound_backend::retain_count = 0; +int sound_backend::retain_count = 0; ALCdevice* sound_backend::al_device; ALCcontext* sound_backend::al_context; @@ -104,10 +101,6 @@ typedef resource_handle sound_handle; MOOF_REGISTER_RESOURCE(sound_resource, ogg, sounds); - -/*] Sound resource - *************************************************************************/ - class sound_resource : public boost::noncopyable { public: @@ -117,9 +110,8 @@ public: sample_(0) { if (ov_fopen((char*)path.c_str(), &file_) < 0) - { - throw std::runtime_error("problem reading audio: " + path); - } + throw std::runtime_error("problem reading audio: " + + path); } ~sound_resource() @@ -128,7 +120,6 @@ public: if (buffer_) alDeleteBuffers(1, &buffer_); } - ALuint read_all() const { if (buffer_) return buffer_; @@ -147,9 +138,8 @@ public: while (size < sizeof(data)) { int section; - int result = ov_read(&file_, - data + size, sizeof(data) - size, - 0, 2, 1, §ion); + int result = ov_read(&file_, data + size, + sizeof(data) - size, 0, 2, 1, §ion); if (0 < result) { @@ -162,7 +152,7 @@ public: ALuint buffer; alGenBuffers(1, &buffer); alBufferData(buffer, get_audio_format(info), - data, size, info->rate); + data, size, info->rate); buffer_ = buffer; return buffer; @@ -173,7 +163,6 @@ public: break; } } - return AL_NONE; } @@ -181,13 +170,12 @@ public: { if ((sample == sample_ && ov_pcm_seek_lap(&file_, sample) != 0) || (sample != sample_ && ov_pcm_seek(&file_, sample) != 0)) - { return false; - } - char data[BUF_SIZE]; + char data[BUF_SIZE]; int section; - int result = ov_read(&file_, data, sizeof(data), 0, 2, 1, §ion); + int result = ov_read(&file_, data, sizeof(data), + 0, 2, 1, §ion); if (0 < result) { @@ -197,8 +185,10 @@ public: sample_ = sample = ov_pcm_tell(&file_); return true; } - else if (result < 0) log_warning("vorbis playback error"); - + else if (result < 0) + { + log_warning("vorbis playback error"); + } return false; } @@ -206,62 +196,61 @@ public: { ov_crosslap(&other->file_, &file_); - char data[BUF_SIZE]; + char data[BUF_SIZE]; int section; - int result = ov_read(&file_, data, sizeof(data), 0, 2, 1, §ion); + int result = ov_read(&file_, data, sizeof(data), + 0, 2, 1, §ion); if (0 < result) { vorbis_info* info = ov_info(&file_, section); alBufferData(buffer, get_audio_format(info), - data, result, info->rate); + data, result, info->rate); sample_ = sample = ov_pcm_tell(&file_); return true; } - else if (result < 0) log_warning("vorbis playback error"); - + else if (result < 0) + { + log_warning("vorbis playback error"); + } return false; } - - // determines the correct number of fixed-size buffers needed to hold a - // given number of seconds of PCM audio. + // determines the correct number of fixed-size buffers needed to hold + // a given number of seconds of PCM audio. int num_buffers(scalar seconds) const { vorbis_info* info = ov_info(&file_, -1); int count = scalar(info->rate) * // sample rate - scalar(info->channels) * // channels - scalar(NUM_SAMPLE_BITS) * // sample size - seconds * // time - SCALAR(0.125) / // bits to bytes - scalar(BUF_SIZE); // individual buffer size + scalar(info->channels) * // channels + scalar(NUM_SAMPLE_BITS) * // sample size + seconds * // time + SCALAR(0.125) / // bits to bytes + scalar(BUF_SIZE); // individual buffer size return count; } - static ALenum get_audio_format(const vorbis_info* info) { - if (info->channels == 1) return AL_FORMAT_MONO16; - else if (info->channels == 2) return AL_FORMAT_STEREO16; + if (info->channels == 1) + return AL_FORMAT_MONO16; + else if (info->channels == 2) + return AL_FORMAT_STEREO16; log_error("unsupported number of channels:", info->channels); return 0; } - private: mutable OggVorbis_File file_; - mutable ALuint buffer_; - mutable uint64_t sample_; + mutable ALuint buffer_; + mutable uint64_t sample_; - sound_backend backend_; + sound_backend backend_; }; -/*] Sound class - *************************************************************************/ - class sound::impl { public: @@ -313,7 +302,10 @@ public: alSourceUnqueueBuffers(source_, queued, buffers); alDeleteBuffers(queued, buffers); } - else alSourcei(source_, AL_BUFFER, AL_NONE); + else + { + alSourcei(source_, AL_BUFFER, AL_NONE); + } } void play() @@ -324,33 +316,31 @@ public: alGetSourcei(source_, AL_SOURCE_STATE, &state); switch (state) { - case AL_INITIAL: - case AL_STOPPED: - - if (is_streaming_) - { - start_update_timer(); - num_buffers_ = queue_.front()->num_buffers(buffer_size_); - fill_stream(); - is_playing_ = true; - alSourcei(source_, AL_LOOPING, false); - } - else - { - ALuint buffer = queue_.front()->read_all(); - alSourcei(source_, AL_BUFFER, buffer); - alSourcei(source_, AL_LOOPING, is_looping_); - } - break; + case AL_INITIAL: + case AL_STOPPED: + if (is_streaming_) + { + start_update_timer(); + num_buffers_ = queue_.front()->num_buffers(buffer_size_); + fill_stream(); + is_playing_ = true; + alSourcei(source_, AL_LOOPING, false); + } + else + { + ALuint buffer = queue_.front()->read_all(); + alSourcei(source_, AL_BUFFER, buffer); + alSourcei(source_, AL_LOOPING, is_looping_); + } + break; - case AL_PAUSED: - - if (is_streaming_) - { - start_update_timer(); - is_playing_ = true; - } - break; + case AL_PAUSED: + if (is_streaming_) + { + start_update_timer(); + is_playing_ = true; + } + break; } alSourcePlay(source_); @@ -358,8 +348,19 @@ public: void start_update_timer() { - stream_timer_.init(boost::bind(&impl::stream_update, this, _1, _2), + stream_timer_.init(boost::bind(&impl::stream_update, + this, _1, _2), SCALAR(0.1), timer::repeat); + + thread::main_runloop().add_timer(stream_timer_); + + //thread thread; + //thread.runloop().add_timer(stream_timer_); + //if (!stream_thread_.is_valid()) + //stream_thread_ = thread::detach(stream_timer_); + // FIXME: proper locking needs to be done; this is causing crashes + // on shutdown when sound resources are destroyed yet the stream + // thread is neither shutdown or notified. } void fill_stream() @@ -373,7 +374,7 @@ public: alGetSourcei(source_, AL_BUFFERS_QUEUED, &queued); alGetSourcei(source_, AL_BUFFERS_PROCESSED, &processed); - int target_diff = num_buffers_ - queued + processed; + int target_diff = num_buffers_ - queued + processed; ALuint bufs[processed]; alSourceUnqueueBuffers(source_, processed, bufs); @@ -383,7 +384,10 @@ public: if (0 < target_diff) { - if (queue_buffer(buf)) --target_diff; + if (queue_buffer(buf)) + { + --target_diff; + } else { alDeleteBuffers(processed - i - 1, &bufs[i+1]); @@ -393,7 +397,7 @@ public: else alDeleteBuffers(1, &buf); } - if (stream_timer_.is_valid() && 0 < target_diff) + if (stream_timer_.mode() != timer::invalid && 0 < target_diff) { for (int i = 0; i < target_diff; ++i) { @@ -415,6 +419,7 @@ public: } } + // TODO: this function is ugly bool queue_buffer(ALuint buffer) { if (buffer == AL_NONE) alGenBuffers(1, &buffer); @@ -458,7 +463,10 @@ public: queue_.push_back(sound); looped_once = true; } - else break; + else + { + break; + } } } @@ -468,7 +476,6 @@ public: return false; } - void stop() { alSourceStop(source_); @@ -487,7 +494,6 @@ public: stream_timer_.invalidate(); } - void sample(const std::string& name) { stop(); @@ -505,17 +511,15 @@ public: is_streaming_ = true; } - bool is_playing() const { ALenum state; alGetSourcei(source_, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) return true; - else return is_playing_; + else return is_playing_; } - void loop(bool looping) { is_looping_ = looping; @@ -523,35 +527,29 @@ public: ALenum type; alGetSourcei(source_, AL_SOURCE_TYPE, &type); if (type != AL_STREAMING) - { alSourcei(source_, AL_LOOPING, is_looping_); - } } - void stream_update(timer& timer, scalar t) { - //log_error("blaaaaaaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhhhhhrrrrrg"); + log_debug("blaaaaaaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhhhhhrrrrrg"); fill_stream(); - // TODO: might be nice to also allow using threads for streaming - // rather than a timer, probably as a compile-time option } + ALuint source_; - ALuint source_; - - bool is_playing_; - bool is_looping_; - bool is_streaming_; + bool is_playing_; + bool is_looping_; + bool is_streaming_; std::deque queue_; - uint64_t sample_; - int num_buffers_; - scalar buffer_size_; + uint64_t sample_; + int num_buffers_; + scalar buffer_size_; - timer stream_timer_; + timer stream_timer_; - sound_backend backend_; + sound_backend backend_; }; @@ -563,7 +561,6 @@ sound::sound(const std::string& path) : // pass through impl_(new sound::impl(path)) {} - void sound::sample(const std::string& path) { // pass through @@ -576,7 +573,6 @@ void sound::queue(const std::string& path) impl_->queue(path); } - void sound::play() { // pass through @@ -612,7 +608,6 @@ void sound::buffer_size(scalar seconds) impl_->buffer_size_ = seconds; } - void sound::position(const vector3& position) { float vec[3] = {position[0], position[1], position[2]}; @@ -641,7 +636,6 @@ void sound::loop(bool looping) impl_->loop(looping); } - void sound::listener_position(const vector3& position) { float vec[] = {position[0], position[1], position[2]}; @@ -655,7 +649,7 @@ void sound::listener_velocity(const vector3& velocity) } void sound::listener_orientation(const vector3& forward, - const vector3& up) + const vector3& up) { float vec[6]; vec[0] = float(forward[0]);