]> git.tdb.fi Git - libs/al.git/commitdiff
Add Streamer class
authorMikko Rasa <tdb@tdb.fi>
Tue, 8 Jul 2008 15:21:39 +0000 (15:21 +0000)
committerMikko Rasa <tdb@tdb.fi>
Tue, 8 Jul 2008 15:21:39 +0000 (15:21 +0000)
Add buffer unqueuing and query commands to Source
Properly destroy Device and Context in destructor
More functionality in Sound
Some minor tweaks

12 files changed:
source/context.cpp
source/context.h
source/device.cpp
source/device.h
source/sound.cpp
source/sound.h
source/soundscape.cpp
source/soundscape.h
source/source.cpp
source/source.h
source/streamer.cpp [new file with mode: 0644]
source/streamer.h [new file with mode: 0644]

index 1ca0eac92d3d6a6b6f88fcbb7dac054395152a92..847680a20a338c7439be2beb3fed0a3f54a081b7 100644 (file)
@@ -21,5 +21,10 @@ Context::Context(Device &dev)
        alcMakeContextCurrent(context);
 }
 
+Context::~Context()
+{
+       alcDestroyContext(context);
+}
+
 } // namespace AL
 } // namespace Msp
index de26ac71aa8733b54dd1cd9c79db8ccc36c684c5..10b9061cc7e7fe0bcf396e1709ff7c950ce99a54 100644 (file)
@@ -22,6 +22,7 @@ private:
 
 public:
        Context(Device &);
+       ~Context();
 };
 
 } // namespace AL
index 1500100cf66a8ef0945e262df4e3dcecb4a70dc8..dcc78f1aa949b37dbe173adf96a3cb140e1f41ff 100644 (file)
@@ -27,5 +27,10 @@ Device::Device(const string &spec)
                throw Exception("Couldn't get OpenAL device");
 }
 
+Device::~Device()
+{
+       alcCloseDevice(dev);
+}
+
 } // namespace AL
 } // namespace Msp
index d96901fabe1ad8d39cd7a4bebfd086952de6983a..1a4692d909292fb685993255c84685ee761e59f2 100644 (file)
@@ -22,6 +22,8 @@ private:
 public:
        Device();
        Device(const std::string &);
+       ~Device();
+
        ALCdevice *get_device() { return dev; }
 };
 
index 896d1d5c392798eb63595b0bb1b1f402a990a1fa..b2744b3abedeb9682a8c08e6ffbead563280f2dd 100644 (file)
@@ -5,6 +5,7 @@ Copyright © 2008 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
 
+#include <cstring>
 #include <msp/core/except.h>
 #include "sound.h"
 
@@ -14,22 +15,37 @@ namespace Msp {
 namespace AL {
 
 Sound::Sound():
-       data(0)
+       data(0),
+       eof_flag(false)
 {
        ovfile.datasource=0;
 }
 
+Sound::Sound(const std::string &fn):
+       data(0),
+       eof_flag(false)
+{
+       ovfile.datasource=0;
+       open(fn);
+}
+
 Sound::~Sound()
 {
+       delete data;
        if(ovfile.datasource)
                ov_clear(&ovfile);
 }
 
 void Sound::open(const string &fn)
 {
+       if(ovfile.datasource)
+               throw InvalidState("Sound has already been opened");
        if(ov_fopen(const_cast<char *>(fn.c_str()), &ovfile)<0)
                throw Exception("Could not open ogg vorbis file "+fn);
 
+       delete data;
+       data=0;
+
        vorbis_info *info=ov_info(&ovfile, -1);
        freq=info->rate;
        switch(info->channels)
@@ -46,10 +62,11 @@ void Sound::load_data()
                throw InvalidState("Data has already been loaded");
 
        size=ov_pcm_total(&ovfile, 0)*4;
-       data=new char[size];
+       char *dptr=new char[size];
        unsigned pos=0;
-       while(unsigned len=read(data+pos, size-pos))
+       while(unsigned len=read(dptr+pos, size-pos))
                pos+=len;
+       data=dptr;
        size=pos;
 }
 
@@ -57,22 +74,51 @@ void Sound::load(const string &fn)
 {
        open(fn);
        load_data();
+       close();
 }
 
-const char *Sound::get_data() const
+void Sound::close()
 {
-       if(!data)
-               throw InvalidState("Data has not been loaded");
-       return data;
+       if(ovfile.datasource)
+               ov_clear(&ovfile);
+}
+
+void Sound::rewind()
+{
+       if(data)
+               read_pos=0;
+       else
+               ov_pcm_seek(&ovfile, 0);
 }
 
 unsigned Sound::read(char *buf, unsigned len)
 {
-       int section=0;
-       int res=ov_read(&ovfile, buf, len, 0, 2, 1, &section);
-       if(res<0)
-               throw Exception("Error reading ogg vorbis file");
-       return res;
+       if(data)
+       {
+               len=min(len, size-read_pos);
+               memcpy(buf, data+read_pos, len);
+               read_pos+=len;
+               return len;
+       }
+       else if(ovfile.datasource)
+       {
+               int section=0;
+               int res=ov_read(&ovfile, buf, len, 0, 2, 1, &section);
+               if(res<0)
+                       throw Exception("Error reading ogg vorbis file");
+               else if(res==0)
+                       eof_flag=true;
+               return res;
+       }
+       else
+               throw InvalidState("No data available");
+}
+
+const char *Sound::get_data() const
+{
+       if(!data)
+               throw InvalidState("Data has not been loaded");
+       return data;
 }
 
 } // namespace AL
index e903bcb395acf185df355f444793557a4c590b2f..1badf3c03a9d01ff03f211daf539579278faec3b 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the LGPL
 #ifndef MSP_AL_SOUND_H_
 #define MSP_AL_SOUND_H_
 
+#include <string>
 #include <vorbis/vorbisfile.h>
 #include "format.h"
 
@@ -22,19 +23,26 @@ private:
        unsigned size;
        char *data;
        Format format;
+       unsigned read_pos;
+       bool eof_flag;
 
 public:
        Sound();
+       Sound(const std::string &);
        ~Sound();
 
        void open(const std::string &);
        void load_data();
        void load(const std::string &);
+       void close();
+       void rewind();
+       unsigned read(char *, unsigned);
+       bool eof() const { return eof_flag; }
+
        Format get_format() const { return format; }
        unsigned get_frequency() const { return freq; }
        unsigned get_size() const { return size; }
        const char *get_data() const;
-       unsigned read(char *, unsigned);
 };
 
 } // namespace AL
index 6ec00f06b9113909ff6e20d4bb976836b758095f..d36b3bf7c1648c236fa3fde5c0890a9e707b0268 100644 (file)
@@ -19,19 +19,19 @@ SoundScape::~SoundScape()
                delete *i;
 }
 
-void SoundScape::add_source(Source *src)
+void SoundScape::add_source(Source &src)
 {
-       sources.push_back(src);
+       sources.push_back(&src);
 }
 
-Source *SoundScape::play(const Buffer &buf, float x, float y, float z)
+Source &SoundScape::play(const Buffer &buf, float x, float y, float z)
 {
        Source *src=new Source;
-       add_source(src);
+       add_source(*src);
        src->set_buffer(buf);
        src->set_position(x, y, z);
        src->play();
-       return src;
+       return *src;
 }
 
 void SoundScape::tick()
index 1d8a9c7a798acc052196f442c87682091e11832d..db935572a709149f987ca278e43592eda18d871e 100644 (file)
@@ -24,8 +24,8 @@ private:
 public:
        ~SoundScape();
 
-       void add_source(Source *);
-       Source *play(const Buffer &, float, float, float);
+       void add_source(Source &);
+       Source &play(const Buffer &, float, float, float);
        void tick();
 };
 
index e8f33c0d8be5e1014d9082879f5032ca81a12d77..3619b1d61205c9128d0ffb87d7e66909acf738f2 100644 (file)
@@ -43,12 +43,12 @@ void Source::attribute(ALenum attr, const float *v)
        alSourcefv(id, attr, v);
 }
 
-void Source::get_attr(ALenum attr, int *v) const
+void Source::get_attribute(ALenum attr, int *v) const
 {
        alGetSourcei(id, attr, v);
 }
 
-void Source::get_attr(ALenum attr, float *v) const
+void Source::get_attribute(ALenum attr, float *v) const
 {
        alGetSourcef(id, attr, v);
 }
@@ -56,10 +56,24 @@ void Source::get_attr(ALenum attr, float *v) const
 SourceState Source::get_state() const
 {
        int state;
-       get_attr(AL_SOURCE_STATE, &state);
+       get_attribute(AL_SOURCE_STATE, &state);
        return static_cast<SourceState>(state);
 }
 
+unsigned Source::get_buffers_queued() const
+{
+       int n;
+       get_attribute(AL_BUFFERS_QUEUED, &n);
+       return n;
+}
+
+unsigned Source::get_buffers_processed() const
+{
+       int n;
+       get_attribute(AL_BUFFERS_PROCESSED, &n);
+       return n;
+}
+
 void Source::set_position(float x, float y, float z)
 {
        attribute(AL_POSITION, x, y, z);
@@ -90,6 +104,26 @@ void Source::queue_buffer(const Buffer &buffer)
        alSourceQueueBuffers(id, 1, &bid);
 }
 
+void Source::unqueue_buffers(const vector<const Buffer *> &buffers)
+{
+       vector<uint> ids;
+       ids.reserve(buffers.size());
+       for(vector<const Buffer *>::const_iterator i=buffers.begin(); i!=buffers.end(); ++i)
+               ids.push_back((*i)->get_id());
+       alSourceUnqueueBuffers(id, ids.size(), &ids.front());
+}
+
+void Source::unqueue_buffer(const Buffer &buffer)
+{
+       uint bid=buffer.get_id();
+       alSourceUnqueueBuffers(id, 1, &bid);
+}
+
+void Source::clear_buffers()
+{
+       attribute(AL_BUFFER, AL_NONE);
+}
+
 void Source::play()
 {
        alSourcePlay(id);
index df8bbc54c06310e91d430888a2aaddf5cedbad30..090de0ff36b12e30666fdff8f55c2bd821122046 100644 (file)
@@ -38,14 +38,19 @@ public:
        void attribute(ALenum, float);
        void attribute(ALenum, float, float, float);
        void attribute(ALenum, const float *);
-       void get_attr(ALenum, int *) const;
-       void get_attr(ALenum, float *) const;
+       void get_attribute(ALenum, int *) const;
+       void get_attribute(ALenum, float *) const;
        SourceState get_state() const;
+       unsigned get_buffers_queued() const;
+       unsigned get_buffers_processed() const;
        void set_position(float, float, float);
        void set_looping(bool);
        void set_buffer(const Buffer &);
        void queue_buffers(const std::vector<const Buffer *> &);
        void queue_buffer(const Buffer &);
+       void unqueue_buffers(const std::vector<const Buffer *> &);
+       void unqueue_buffer(const Buffer &);
+       void clear_buffers();
        void play();
        void pause();
        void stop();
diff --git a/source/streamer.cpp b/source/streamer.cpp
new file mode 100644 (file)
index 0000000..36545f6
--- /dev/null
@@ -0,0 +1,84 @@
+/* $Id$
+
+This file is part of libmspal
+Copyright © 2008 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "buffer.h"
+#include "sound.h"
+#include "streamer.h"
+
+using namespace std;
+
+namespace Msp {
+namespace AL {
+
+Streamer::Streamer(Source &s):
+       src(s),
+       snd(0)
+{ }
+
+Streamer::~Streamer()
+{
+       src.stop();
+       src.clear_buffers();
+       for(list<Buffer *>::iterator i=buffers.begin(); i!=buffers.end(); ++i)
+               delete *i;
+}
+
+void Streamer::play(Sound &s)
+{
+       snd=&s;
+       tick();
+       src.play();
+}
+
+void Streamer::stop()
+{
+       snd=0;
+       src.stop();
+}
+
+void Streamer::tick()
+{
+       if(unsigned n=src.get_buffers_processed())
+       {
+               for(unsigned i=0; i<n; ++i)
+               {
+                       src.unqueue_buffer(*buffers.front());
+                       delete buffers.front();
+                       buffers.erase(buffers.begin());
+               }
+       }
+
+       if(!snd)
+               return;
+
+       unsigned freq=snd->get_frequency();
+       unsigned chunk_size=freq&~0xF;
+       unsigned queued=src.get_buffers_queued();
+       for(unsigned i=queued; i<4; ++i)
+       {
+               char data[chunk_size];
+               unsigned pos=0;
+               while(pos<chunk_size)
+               {
+                       unsigned len=snd->read(data+pos, chunk_size-pos);
+                       if(len==0)
+                               break;
+                       pos+=len;
+               }
+
+               if(pos)
+               {
+                       Buffer *buf=new Buffer;
+                       buf->data(snd->get_format(), data, pos, freq);
+                       src.queue_buffer(*buf);
+                       buffers.push_back(buf);
+               }
+       }
+}
+
+} // namespace AL
+} // namespace Msp
diff --git a/source/streamer.h b/source/streamer.h
new file mode 100644 (file)
index 0000000..eddd49d
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id$
+
+This file is part of libmspal
+Copyright © 2008 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_AL_STREAMER_H_
+#define MSP_AL_STREAMER_H_
+
+#include <list>
+#include "source.h"
+
+namespace Msp {
+namespace AL {
+
+class Sound;
+class Buffer;
+
+class Streamer
+{
+private:
+       Source &src;
+       Sound  *snd;
+       std::list<Buffer *> buffers;
+
+public:
+       Streamer(Source &);
+       ~Streamer();
+
+       void play(Sound &);
+       void stop();
+       void tick();
+};
+
+} // namespace AL
+} // namespace Msp
+
+#endif