From d57051375dda480be65fbc5127b4d4433d99e0e1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Mar 2012 09:15:47 -0700 Subject: [PATCH] Implement non-streaming sounds with OpenAL --- apps/openmw/mwsound/openal_output.cpp | 166 +++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a183909d3..ac639416f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -47,6 +47,32 @@ static ALenum getALFormat(Sound_Decoder::ChannelConfig chans, Sound_Decoder::Sam } +ALuint LoadBuffer(std::auto_ptr decoder) +{ + int srate; + Sound_Decoder::ChannelConfig chans; + Sound_Decoder::SampleType type; + ALenum format; + + decoder->GetInfo(&srate, &chans, &type); + format = getALFormat(chans, type); + + std::vector data(32768); + size_t got, total = 0; + while((got=decoder->Read(&data[total], data.size()-total)) > 0) + { + total += got; + data.resize(total*2); + } + data.resize(total); + + ALuint buf; + alGenBuffers(1, &buf); + alBufferData(buf, format, &data[0], total, srate); + return buf; +} + + class OpenAL_SoundStream : public Sound { // This should be something sane, like 4, but currently cell loads tend to @@ -71,6 +97,21 @@ public: virtual bool isPlaying(); }; +class OpenAL_Sound : public Sound +{ +public: + ALuint Source; + ALuint Buffer; + + OpenAL_Sound(ALuint src, ALuint buf); + virtual ~OpenAL_Sound(); + + virtual void Play(); + virtual void Stop(); + virtual bool isPlaying(); +}; + + OpenAL_SoundStream::OpenAL_SoundStream(std::auto_ptr decoder) : Decoder(decoder) { @@ -190,6 +231,38 @@ bool OpenAL_SoundStream::isPlaying() } +OpenAL_Sound::OpenAL_Sound(ALuint src, ALuint buf) + : Source(src), Buffer(buf) +{ +} +OpenAL_Sound::~OpenAL_Sound() +{ + alDeleteSources(1, &Source); + alDeleteBuffers(1, &Buffer); + alGetError(); +} + +void OpenAL_Sound::Play() +{ +} + +void OpenAL_Sound::Stop() +{ + alSourceStop(Source); + throwALerror(); +} + +bool OpenAL_Sound::isPlaying() +{ + ALint state; + + alGetSourcei(Source, AL_SOURCE_STATE, &state); + throwALerror(); + + return state==AL_PLAYING; +} + + bool OpenAL_Output::Initialize(const std::string &devname) { if(Context) @@ -233,16 +306,97 @@ void OpenAL_Output::Deinitialize() Sound* OpenAL_Output::PlaySound(const std::string &fname, std::auto_ptr decoder, float volume, float pitch, bool loop) { - fail("PlaySound not yet supported"); - return NULL; + throwALerror(); + + decoder->Open(fname); + + ALuint src=0, buf=0; + try + { + buf = LoadBuffer(decoder); + alGenSources(1, &src); + throwALerror(); + } + catch(std::exception &e) + { + if(alIsSource(buf)) + alDeleteSources(1, &src); + if(alIsBuffer(buf)) + alDeleteBuffers(1, &buf); + alGetError(); + throw; + } + + std::auto_ptr sound(new OpenAL_Sound(src, buf)); + alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(src, AL_MAX_DISTANCE, 1000.0f); + alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); + + alSourcef(src, AL_GAIN, volume); + alSourcef(src, AL_PITCH, pitch); + + alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE)); + throwALerror(); + + alSourcei(src, AL_BUFFER, buf); + alSourcePlay(src); + throwALerror(); + + return sound.release(); } Sound* OpenAL_Output::PlaySound3D(const std::string &fname, std::auto_ptr decoder, - MWWorld::Ptr ptr, float volume, float pitch, - float min, float max, bool loop) + MWWorld::Ptr ptr, float volume, float pitch, + float min, float max, bool loop) { - fail("PlaySound3D not yet supported"); - return NULL; + throwALerror(); + + decoder->Open(fname); + + ALuint src=0, buf=0; + try + { + buf = LoadBuffer(decoder); + alGenSources(1, &src); + throwALerror(); + } + catch(std::exception &e) + { + if(alIsSource(buf)) + alDeleteSources(1, &src); + if(alIsBuffer(buf)) + alDeleteBuffers(1, &buf); + alGetError(); + throw; + } + + std::auto_ptr sound(new OpenAL_Sound(src, buf)); + const float *pos = ptr.getCellRef().pos.pos; + alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]); + alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(src, AL_REFERENCE_DISTANCE, min); + alSourcef(src, AL_MAX_DISTANCE, max); + alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f); + + alSourcef(src, AL_GAIN, volume); + alSourcef(src, AL_PITCH, pitch); + + alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE)); + throwALerror(); + + alSourcei(src, AL_BUFFER, buf); + alSourcePlay(src); + throwALerror(); + + return sound.release(); }