X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FSound.cc;fp=src%2FMoof%2FSound.cc;h=0000000000000000000000000000000000000000;hp=ffa270e9e9876768669cd7ca3bdf850d46b5b09c;hb=831f04d4bc19a390415ac0bbac4331c7a65509bc;hpb=299af4f2047e767e5d79501c26444473bda64c64 diff --git a/src/Moof/Sound.cc b/src/Moof/Sound.cc deleted file mode 100644 index ffa270e..0000000 --- a/src/Moof/Sound.cc +++ /dev/null @@ -1,601 +0,0 @@ - -/*] Copyright (c) 2009-2010, 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 -#include -#include - -#include - -#include -#include -#include -#include - -#include "Error.hh" -#include "Manager.hh" -#include "Log.hh" -#include "Sound.hh" -#include "Timer.hh" - -#define BUFFER_SIZE (64 * 1024) -//#define BUFFER_SIZE (5*2048) - -namespace Mf { - - -class Sound::Impl -{ -public: - - static ALenum getAudioFormat(const vorbis_info* audioInfo) - { - if (audioInfo->channels == 1) return AL_FORMAT_MONO16; - else return AL_FORMAT_STEREO16; - } - - - class Buffer; - typedef boost::shared_ptr BufferP; - - class Buffer : public Manager - { - public: - - Buffer() : - mBuffer(-1) - { - mOggStream.datasource = 0; - } - - ~Buffer() - { - if (mOggStream.datasource) - { - ov_clear(&mOggStream); - } - if (int(mBuffer) != -1) alDeleteBuffers(1, &mBuffer); - } - - - void init(const std::string& name) - { - if (mOggStream.datasource) - { - ov_clear(&mOggStream); - mOggStream.datasource = 0; - } - - std::string path(name); - if (!Sound::getPath(path)) - { - Error(Error::RESOURCE_NOT_FOUND, path).raise(); - } - - if (ov_fopen((char*)path.c_str(), &mOggStream) < 0) - { - Error(Error::UNKNOWN_AUDIO_FORMAT, path).raise(); - } - - vorbis_info* vorbisInfo = ov_info(&mOggStream, -1); - mFormat = getAudioFormat(vorbisInfo); - mFreq = vorbisInfo->rate; - } - - - void loadAll(ALuint source) - { - if (!mOggStream.datasource) init(getName()); - if (!mOggStream.datasource) return; - - char data[BUFFER_SIZE]; - int size = 0; - - for (;;) - { - int section; - int result = ov_read(&mOggStream, data + size, - BUFFER_SIZE - size, 0, 2, 1, §ion); - - if (result > 0) - { - size += result; - } - else - { - if (result < 0) logWarning("vorbis playback error"); - break; - } - } - if (size == 0) - { - logWarning << "decoded no bytes from " - << getName() << std::endl; - return; - } - - alGenBuffers(1, &mBuffer); - - alBufferData(mBuffer, mFormat, data, size, mFreq); - alSourcei(source, AL_BUFFER, mBuffer); - - // don't need to keep this loaded - ov_clear(&mOggStream); - mOggStream.datasource = 0; - } - - bool stream(ALuint buffer) - { - char data[BUFFER_SIZE]; - int size = 0; - - while (size < BUFFER_SIZE) - { - int section; - int result = ov_read(&mOggStream, data + size, - BUFFER_SIZE - size, 0, 2, 1, §ion); - - if (result > 0) - { - size += result; - } - else - { - if (result < 0) logWarning("vorbis playback error"); - break; - } - } - - if (size == 0) return false; - - alBufferData(buffer, mFormat, data, size, mFreq); - - return true; - } - - void rewind() - { - if (!mOggStream.datasource) init(getName()); - else ov_raw_seek(&mOggStream, 0); - } - - - private: - - OggVorbis_File mOggStream; - ALenum mFormat; - ALsizei mFreq; - ALuint mBuffer; - }; - - - Impl() - { - init(); - } - - Impl(const std::string& name) - { - init(); - enqueue(name); - } - - void init() - { - retainBackend(); - - mIsLoaded = false; - mIsPlaying = false; - mIsLooping = false; - - alGenSources(1, &mSource); - - ALfloat zero[] = {0.0f, 0.0f, 0.0f}; - alSourcef(mSource, AL_PITCH, 1.0f); - alSourcef(mSource, AL_GAIN, 1.0f); - alSourcefv(mSource, AL_POSITION, zero); - alSourcefv(mSource, AL_VELOCITY, zero); - - alSourcei(mSource, AL_LOOPING, mIsLooping); - } - - ~Impl() - { - stop(); - - alDeleteSources(1, &mSource); - - while (!mBuffers.empty()) - { - alDeleteBuffers(1, &mBuffers.back()); - mBuffers.pop_back(); - } - - releaseBackend(); - } - - - void play() - { - if (mQueue.empty()) return; - - if (!mIsLoaded) mQueue.front()->loadAll(mSource); - - alSourcePlay(mSource); - mIsLoaded = true; - } - - - void playStream() - { - if (mQueue.empty()) return; - - if (!mIsPlaying) - { - alSourcei(mSource, AL_LOOPING, false); - bufferStream(); - } - - if (!mStreamTimer.isValid()) - { - mStreamTimer.init(boost::bind(&Impl::streamUpdate, this, _1, _2), - 1.0, Timer::REPEAT); - } - - alSourcePlay(mSource); - mIsPlaying = true; - } - - void bufferStream() - { - ALuint buffer; - for (int i = mBuffers.size(); i <= 8; ++i) - { - alGenBuffers(1, &buffer); - - if (mQueue.front()->stream(buffer)) - { - alSourceQueueBuffers(mSource, 1, &buffer); - mBuffers.push_back(buffer); - } - else - { - alDeleteBuffers(1, &buffer); - break; - } - } - } - - - void update() - { - ALint finished = 0; - - alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &finished); - - while (finished-- > 0) - { - ALuint bufferObj; - alSourceUnqueueBuffers(mSource, 1, &bufferObj); - - BufferP buffer = mQueue.front(); - bool streamed = buffer->stream(bufferObj); - - if (streamed) - { - alSourceQueueBuffers(mSource, 1, &bufferObj); - } - else - { - // the buffer couldn't be streamed, so get rid of it - mQueue.pop_front(); - - if (!mQueue.empty()) - { - // begin the next buffer in the queue - mQueue.front()->rewind(); - mQueue.front()->stream(bufferObj); - alSourceQueueBuffers(mSource, 1, &bufferObj); - logInfo("loading new buffer"); - - // queue up any unused buffers - bufferStream(); - } - else if (mIsLooping) - { - // reload the same buffer - mQueue.push_back(buffer); - buffer->rewind(); - buffer->stream(bufferObj); - alSourceQueueBuffers(mSource, 1, &bufferObj); - logInfo("looping same buffer"); - } - else - { - // nothing more to play, stopping... - mIsPlaying = false; - std::remove(mBuffers.begin(), mBuffers.end(), - bufferObj); - } - } - } - - ALenum state; - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - - // restart playing if we're stopped but supposed to be playing... - // this means we didn't queue enough and the audio skipped :-( - if (mIsPlaying && state != AL_PLAYING) - { - alSourcePlay(mSource); - } - } - - - void stop() - { - alSourceStop(mSource); - mIsPlaying = false; - - mStreamTimer.invalidate(); - } - - void pause() - { - alSourcePause(mSource); - mIsPlaying = false; - - mStreamTimer.invalidate(); - } - - - void setSample(const std::string& name) - { - stop(); - alSourcei(mSource, AL_BUFFER, AL_NONE); - - mQueue.clear(); - mIsLoaded = false; - - enqueue(name); - - while (!mBuffers.empty()) - { - alDeleteBuffers(1, &mBuffers.back()); - mBuffers.pop_back(); - } - } - - void enqueue(const std::string& name) - { - BufferP buffer = Buffer::getInstance(name); - mQueue.push_back(buffer); - } - - - bool isPlaying() const - { - if (mIsPlaying) return true; - - ALenum state; - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - - return state == AL_PLAYING; - } - - - void setLooping(bool looping) - { - mIsLooping = looping; - - ALenum type; - alGetSourcei(mSource, AL_SOURCE_TYPE, &type); - - if (type != AL_STREAMING) - { - alSourcei(mSource, AL_LOOPING, mIsLooping); - } - } - - - void streamUpdate(Timer& timer, Scalar t) - { - // don't let the music die! - update(); - // TODO - might be nice to also allow using threads for streaming - // rather than a timer, probably as a compile-time option - } - - static void retainBackend() - { - if (gRetainCount++ == 0) - { - gAlDevice = alcOpenDevice(0); - gAlContext = alcCreateContext(gAlDevice, 0); - if (!gAlDevice || !gAlContext) - { - const char* error = alcGetString(gAlDevice, - alcGetError(gAlDevice)); - logError << "audio subsystem initialization failure: " - << error << std::endl; - } - else - { - alcMakeContextCurrent(gAlContext); - logInfo << "opened sound device `" - << alcGetString(gAlDevice, - ALC_DEFAULT_DEVICE_SPECIFIER) - << "'" << std::endl; - } - } - } - - static void releaseBackend() - { - if (--gRetainCount == 0) - { - alcMakeContextCurrent(0); - alcDestroyContext(gAlContext); - alcCloseDevice(gAlDevice); - } - } - - - ALuint mSource; - std::list mBuffers; - - bool mIsLoaded; - bool mIsPlaying; - bool mIsLooping; - - std::deque mQueue; - - Timer mStreamTimer; - - static unsigned gRetainCount; - static ALCdevice* gAlDevice; - static ALCcontext* gAlContext; -}; - -unsigned Sound::Impl::gRetainCount = 0; -ALCdevice* Sound::Impl::gAlDevice = 0; -ALCcontext* Sound::Impl::gAlContext = 0; - - -Sound::Sound() : - // pass through - mImpl(new Sound::Impl) {} - -Sound::Sound(const std::string& name) : - // pass through - mImpl(new Sound::Impl(name)) {} - - -void Sound::setSample(const std::string& name) -{ - // pass through - mImpl->setSample(name); -} - - -void Sound::play() -{ - // pass through - mImpl->play(); -} - -void Sound::stop() -{ - // pass through - mImpl->stop(); -} - -void Sound::pause() -{ - // pass through - mImpl->pause(); -} - - -void Sound::toggle() -{ - if (isPlaying()) pause(); - else play(); -} - -bool Sound::isPlaying() const -{ - // pass through - return mImpl->isPlaying(); -} - - -void Sound::setPosition(const Vector3& position) -{ - float vec[3] = {position[0], position[1], position[2]}; - alSourcefv(mImpl->mSource, AL_POSITION, vec); -} - -void Sound::setVelocity(const Vector3& velocity) -{ - float vec[3] = {velocity[0], velocity[1], velocity[2]}; - alSourcefv(mImpl->mSource, AL_VELOCITY, vec); -} - -void Sound::setGain(Scalar gain) -{ - alSourcef(mImpl->mSource, AL_GAIN, float(gain)); -} - -void Sound::setPitch(Scalar pitch) -{ - alSourcef(mImpl->mSource, AL_PITCH, float(pitch)); -} - -void Sound::setLooping(bool looping) -{ - // pass through - mImpl->setLooping(looping); -} - - -void Sound::setListenerPosition(const Vector3& position) -{ - float vec[] = {position[0], position[1], position[2]}; - alListenerfv(AL_POSITION, vec); -} - -void Sound::setListenerVelocity(const Vector3& velocity) -{ - float vec[] = {velocity[0], velocity[1], velocity[2]}; - alListenerfv(AL_VELOCITY, vec); -} - -void Sound::setListenerOrientation(const Vector3& forward, - const Vector3& up) -{ - float vec[6]; - vec[0] = float(forward[0]); - vec[1] = float(forward[1]); - vec[2] = float(forward[2]); - vec[3] = float(up[0]); - vec[4] = float(up[1]); - vec[5] = float(up[2]); - alListenerfv(AL_ORIENTATION, vec); -} - - -bool Sound::getPath(std::string& name) -{ - return Resource::getPath(name, "sounds/", "ogg"); -} - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -void SoundStream::enqueue(const std::string& name) -{ - // pass through - mImpl->enqueue(name); -} - - -void SoundStream::play() -{ - // pass through - mImpl->playStream(); -} - - -} // namespace Mf -