From 58dc1e7c15f928d0f861a20c46f2be4112bf5baf Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 8 Jul 2008 15:21:39 +0000 Subject: [PATCH] Add Streamer class Add buffer unqueuing and query commands to Source Properly destroy Device and Context in destructor More functionality in Sound Some minor tweaks --- source/context.cpp | 5 +++ source/context.h | 1 + source/device.cpp | 5 +++ source/device.h | 2 ++ source/sound.cpp | 70 +++++++++++++++++++++++++++++------- source/sound.h | 10 +++++- source/soundscape.cpp | 10 +++--- source/soundscape.h | 4 +-- source/source.cpp | 40 +++++++++++++++++++-- source/source.h | 9 +++-- source/streamer.cpp | 84 +++++++++++++++++++++++++++++++++++++++++++ source/streamer.h | 39 ++++++++++++++++++++ 12 files changed, 254 insertions(+), 25 deletions(-) create mode 100644 source/streamer.cpp create mode 100644 source/streamer.h diff --git a/source/context.cpp b/source/context.cpp index 1ca0eac..847680a 100644 --- a/source/context.cpp +++ b/source/context.cpp @@ -21,5 +21,10 @@ Context::Context(Device &dev) alcMakeContextCurrent(context); } +Context::~Context() +{ + alcDestroyContext(context); +} + } // namespace AL } // namespace Msp diff --git a/source/context.h b/source/context.h index de26ac7..10b9061 100644 --- a/source/context.h +++ b/source/context.h @@ -22,6 +22,7 @@ private: public: Context(Device &); + ~Context(); }; } // namespace AL diff --git a/source/device.cpp b/source/device.cpp index 1500100..dcc78f1 100644 --- a/source/device.cpp +++ b/source/device.cpp @@ -27,5 +27,10 @@ Device::Device(const string &spec) throw Exception("Couldn't get OpenAL device"); } +Device::~Device() +{ + alcCloseDevice(dev); +} + } // namespace AL } // namespace Msp diff --git a/source/device.h b/source/device.h index d96901f..1a4692d 100644 --- a/source/device.h +++ b/source/device.h @@ -22,6 +22,8 @@ private: public: Device(); Device(const std::string &); + ~Device(); + ALCdevice *get_device() { return dev; } }; diff --git a/source/sound.cpp b/source/sound.cpp index 896d1d5..b2744b3 100644 --- a/source/sound.cpp +++ b/source/sound.cpp @@ -5,6 +5,7 @@ Copyright © 2008 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#include #include #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(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, §ion); - 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, §ion); + 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 diff --git a/source/sound.h b/source/sound.h index e903bcb..1badf3c 100644 --- a/source/sound.h +++ b/source/sound.h @@ -8,6 +8,7 @@ Distributed under the LGPL #ifndef MSP_AL_SOUND_H_ #define MSP_AL_SOUND_H_ +#include #include #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 diff --git a/source/soundscape.cpp b/source/soundscape.cpp index 6ec00f0..d36b3bf 100644 --- a/source/soundscape.cpp +++ b/source/soundscape.cpp @@ -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() diff --git a/source/soundscape.h b/source/soundscape.h index 1d8a9c7..db93557 100644 --- a/source/soundscape.h +++ b/source/soundscape.h @@ -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(); }; diff --git a/source/source.cpp b/source/source.cpp index e8f33c0..3619b1d 100644 --- a/source/source.cpp +++ b/source/source.cpp @@ -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(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 &buffers) +{ + vector ids; + ids.reserve(buffers.size()); + for(vector::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); diff --git a/source/source.h b/source/source.h index df8bbc5..090de0f 100644 --- a/source/source.h +++ b/source/source.h @@ -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 &); void queue_buffer(const Buffer &); + void unqueue_buffers(const std::vector &); + 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 index 0000000..36545f6 --- /dev/null +++ b/source/streamer.cpp @@ -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::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; iget_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(posread(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 index 0000000..eddd49d --- /dev/null +++ b/source/streamer.h @@ -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 +#include "source.h" + +namespace Msp { +namespace AL { + +class Sound; +class Buffer; + +class Streamer +{ +private: + Source &src; + Sound *snd; + std::list buffers; + +public: + Streamer(Source &); + ~Streamer(); + + void play(Sound &); + void stop(); + void tick(); +}; + +} // namespace AL +} // namespace Msp + +#endif -- 2.45.2