From 932465442bd97c3bcb3a8630414c16bdd887fa9f Mon Sep 17 00:00:00 2001 From: Nicolay Korslund Date: Tue, 17 Aug 2010 11:25:26 +0200 Subject: [PATCH] Moved OpenAL_Sound to cpp file, added delayed buffer creation (prelude for streaming) --- sound/output.hpp | 2 +- sound/outputs/openal_out.cpp | 131 ++++++++++++++++++++++++++--- sound/outputs/openal_out.hpp | 66 ++------------- sound/sources/mpg123_source.cpp | 7 +- sound/tests/openal_output_test.cpp | 16 +++- stream/filters/buffer_stream.hpp | 9 +- 6 files changed, 145 insertions(+), 86 deletions(-) diff --git a/sound/output.hpp b/sound/output.hpp index 596e08c58..a9012b958 100644 --- a/sound/output.hpp +++ b/sound/output.hpp @@ -72,7 +72,7 @@ class Sound /** Playback status is not cloned, only the sound data itself. Back-ends can use this as a means of sharing data and saving memory. */ - virtual SoundPtr clone() const = 0; + virtual SoundPtr clone() = 0; /// Virtual destructor virtual ~Sound() {} diff --git a/sound/outputs/openal_out.cpp b/sound/outputs/openal_out.cpp index f0d5b1c0e..a49840f4e 100644 --- a/sound/outputs/openal_out.cpp +++ b/sound/outputs/openal_out.cpp @@ -4,6 +4,9 @@ #include "../../stream/filters/buffer_stream.hpp" #include "../../tools/str_exception.hpp" +#include +#include + using namespace Mangle::Sound; // ---- Helper functions and classes ---- @@ -69,17 +72,91 @@ static void getALFormat(SampleSourcePtr inp, int &fmt, int &rate) fail("Unsupported input format"); } +/// OpenAL sound output +class OpenAL_Sound : public Sound +{ + ALuint inst; + ALuint bufferID; + + // Poor mans reference counting. Might improve this later. When + // NULL, the buffer has not been set up yet. + int *refCnt; + + bool streaming; + + // Input stream + SampleSourcePtr input; + + void setupBuffer(); + + public: + /// Read samples from the given input buffer + OpenAL_Sound(SampleSourcePtr input); + + /// Play an existing buffer, with a given ref counter. Used + /// internally for cloning. + OpenAL_Sound(ALuint buf, int *ref); + + ~OpenAL_Sound(); + + void play(); + void stop(); + void pause(); + bool isPlaying() const; + void setVolume(float); + void setPos(float x, float y, float z); + void setPitch(float); + void setRepeat(bool); + void setStreaming(bool s) { streaming = s; } + SoundPtr clone(); + + // a = AL_REFERENCE_DISTANCE + // b = AL_MAX_DISTANCE + // c = ignored + void setRange(float a, float b=0.0, float c=0.0); + + /// Not implemented + void setPan(float) {} +}; + // ---- OpenAL_Factory ---- -OpenAL_Factory::OpenAL_Factory(bool doSetup) - : didSetup(doSetup) +SoundPtr OpenAL_Factory::loadRaw(SampleSourcePtr input) { - needsUpdate = false; + return SoundPtr(new OpenAL_Sound(input)); +} + +void OpenAL_Factory::update() +{ +} + +void OpenAL_Factory::setListenerPos(float x, float y, float z, + float fx, float fy, float fz, + float ux, float uy, float uz) +{ + ALfloat orient[6]; + orient[0] = fx; + orient[1] = fy; + orient[2] = fz; + orient[3] = ux; + orient[4] = uy; + orient[5] = uz; + alListener3f(AL_POSITION, x, y, z); + alListenerfv(AL_ORIENTATION, orient); +} + +OpenAL_Factory::OpenAL_Factory(bool doSetup) + : device(NULL), context(NULL), didSetup(doSetup) +{ + needsUpdate = true; has3D = true; canLoadFile = false; canLoadStream = false; canLoadSource = true; + ALCdevice *Device; + ALCcontext *Context; + if(doSetup) { // Set up sound system @@ -90,6 +167,9 @@ OpenAL_Factory::OpenAL_Factory(bool doSetup) fail("Failed to initialize context or device"); alcMakeContextCurrent(Context); + + device = Device; + context = Context; } } @@ -99,8 +179,8 @@ OpenAL_Factory::~OpenAL_Factory() if(didSetup) { alcMakeContextCurrent(NULL); - if(Context) alcDestroyContext(Context); - if(Device) alcCloseDevice(Device); + if(context) alcDestroyContext((ALCcontext*)context); + if(device) alcCloseDevice((ALCdevice*)device); } } @@ -108,6 +188,7 @@ OpenAL_Factory::~OpenAL_Factory() void OpenAL_Sound::play() { + setupBuffer(); alSourcePlay(inst); checkALError("starting playback"); } @@ -164,14 +245,16 @@ void OpenAL_Sound::setRepeat(bool rep) alSourcei(inst, AL_LOOPING, rep?AL_TRUE:AL_FALSE); } -SoundPtr OpenAL_Sound::clone() const +SoundPtr OpenAL_Sound::clone() { + setupBuffer(); + assert(!streaming && "cloning streamed sounds not supported"); return SoundPtr(new OpenAL_Sound(bufferID, refCnt)); } // Constructor used for cloned sounds OpenAL_Sound::OpenAL_Sound(ALuint buf, int *ref) - : bufferID(buf), refCnt(ref) + : bufferID(buf), refCnt(ref), streaming(false) { // Increase the reference count assert(ref != NULL); @@ -185,12 +268,35 @@ OpenAL_Sound::OpenAL_Sound(ALuint buf, int *ref) } // Constructor used for original (non-cloned) sounds -OpenAL_Sound::OpenAL_Sound(SampleSourcePtr input) +OpenAL_Sound::OpenAL_Sound(SampleSourcePtr _input) + : bufferID(0), refCnt(NULL), streaming(false), input(_input) { + // Create a source + alGenSources(1, &inst); + checkALError("creating source"); + + // By default, the sound starts out in a buffer-less mode. We don't + // create a buffer until the sound is played. This gives the user + // the chance to call setStreaming(true) first. +} + +void OpenAL_Sound::setupBuffer() +{ + if(refCnt != NULL) return; + + assert(input); + // Get the format int fmt, rate; getALFormat(input, fmt, rate); + if(streaming) + { + // To be done + } + + // NON-STREAMING + // Set up the OpenAL buffer alGenBuffers(1, &bufferID); checkALError("generating buffer"); @@ -205,17 +311,16 @@ OpenAL_Sound::OpenAL_Sound(SampleSourcePtr input) else { // Read the entire stream into a temporary buffer first - Mangle::Stream::BufferStream buf(input); + Mangle::Stream::BufferStream buf(input, streaming?1024*1024:32*1024); // Then copy that into OpenAL alBufferData(bufferID, fmt, buf.getPtr(), buf.size(), rate); } - checkALError("loading sound buffer"); - // Create a source - alGenSources(1, &inst); - checkALError("creating source"); + // We're done with the input stream, release the pointer + input.reset(); + alSourcei(inst, AL_BUFFER, bufferID); checkALError("assigning buffer"); diff --git a/sound/outputs/openal_out.hpp b/sound/outputs/openal_out.hpp index c22be0de7..f3828ff1b 100644 --- a/sound/outputs/openal_out.hpp +++ b/sound/outputs/openal_out.hpp @@ -3,57 +3,13 @@ #include "../output.hpp" -#include -#include -#include - namespace Mangle { namespace Sound { -/// OpenAL sound output -class OpenAL_Sound : public Sound -{ - protected: - ALuint inst; - ALuint bufferID; - - // Poor mans reference counting. Might improve this later. - int *refCnt; - - public: - /// Read samples from the given input buffer - OpenAL_Sound(SampleSourcePtr input); - - /// Play an existing buffer, with a given ref counter. Used - /// internally for cloning. - OpenAL_Sound(ALuint buf, int *ref); - - ~OpenAL_Sound(); - - void play(); - void stop(); - void pause(); - bool isPlaying() const; - void setVolume(float); - void setPos(float x, float y, float z); - void setPitch(float); - void setRepeat(bool); - void setStreaming(bool) {} // Not implemented yet - SoundPtr clone() const; - - // a = AL_REFERENCE_DISTANCE - // b = AL_MAX_DISTANCE - // c = ignored - void setRange(float a, float b=0.0, float c=0.0); - - /// Not implemented - void setPan(float) {} -}; - class OpenAL_Factory : public SoundFactory { - ALCdevice *Device; - ALCcontext *Context; + void *device; + void *context; bool didSetup; public: @@ -65,24 +21,12 @@ class OpenAL_Factory : public SoundFactory SoundPtr load(const std::string &file) { assert(0); } SoundPtr load(Stream::StreamPtr input) { assert(0); } - SoundPtr loadRaw(SampleSourcePtr input) - { return SoundPtr(new OpenAL_Sound(input)); } + SoundPtr loadRaw(SampleSourcePtr input); - void update() {} + void update(); void setListenerPos(float x, float y, float z, float fx, float fy, float fz, - float ux, float uy, float uz) - { - ALfloat orient[6]; - orient[0] = fx; - orient[1] = fy; - orient[2] = fz; - orient[3] = ux; - orient[4] = uy; - orient[5] = uz; - alListener3f(AL_POSITION, x, y, z); - alListenerfv(AL_ORIENTATION, orient); - } + float ux, float uy, float uz); }; }} // namespaces diff --git a/sound/sources/mpg123_source.cpp b/sound/sources/mpg123_source.cpp index 26e3fd7f4..327279b85 100644 --- a/sound/sources/mpg123_source.cpp +++ b/sound/sources/mpg123_source.cpp @@ -17,14 +17,13 @@ using namespace Mangle::Stream; support), but that's more messy. - the library also supports output, via various other sources, - including ALSO, OSS, PortAudio, PulseAudio and SDL. Using this + including ALSA, OSS, PortAudio, PulseAudio and SDL. Using this library as a pure output library (if that is possible) would be a nice shortcut over using those libraries - OTOH it's another - dependency. But it also means we could scavenge the mpg123 source - for these parts if we want them. + dependency. - we could implement seek(), tell() and size(), but they aren't - really necessary. Further more, since the returned size is only a + really necessary. Furthermore, since the returned size is only a guess, it is not safe to rely on it. */ diff --git a/sound/tests/openal_output_test.cpp b/sound/tests/openal_output_test.cpp index bc781c1a4..c5b99f56f 100644 --- a/sound/tests/openal_output_test.cpp +++ b/sound/tests/openal_output_test.cpp @@ -25,15 +25,23 @@ int main() cout << "Playing\n"; - // This initializes OpenAL for us, and serves no other purpose. OpenAL_Factory mg; - OpenAL_Sound snd(source); + SoundPtr snd = mg.loadRaw(source); + try { - snd.play(); + // Try setting all kinds of stuff before playing. OpenAL_Sound + // uses delayed buffer loading, but these should still work + // without a buffer. + snd->stop(); + snd->pause(); + snd->setVolume(0.8); + snd->setPitch(0.9); - while(snd.isPlaying()) + snd->play(); + + while(snd->isPlaying()) { usleep(10000); } diff --git a/stream/filters/buffer_stream.hpp b/stream/filters/buffer_stream.hpp index 63b70000e..f037212a3 100644 --- a/stream/filters/buffer_stream.hpp +++ b/stream/filters/buffer_stream.hpp @@ -16,7 +16,11 @@ class BufferStream : public MemoryStream std::vector buffer; public: - BufferStream(StreamPtr input) + /* + input = stream to copy + ADD = each read increment (for streams without size()) + */ + BufferStream(StreamPtr input, size_t ADD = 32*1024) { assert(input); @@ -37,7 +41,6 @@ class BufferStream : public MemoryStream { // We DON'T know how big the stream is. We'll have to read // it in increments. - const unsigned int ADD = 32*1024; size_t len=0, newlen; while(!input->eof()) @@ -52,7 +55,7 @@ class BufferStream : public MemoryStream // If we read less than expected, we should be at the // end of the stream - assert(read == ADD || input->eof()); + assert(read == ADD || (read < ADD && input->eof())); } // Downsize to match the real length