alcMakeContextCurrent(context);
}
+Context::~Context()
+{
+ alcDestroyContext(context);
+}
+
} // namespace AL
} // namespace Msp
public:
Context(Device &);
+ ~Context();
};
} // namespace AL
throw Exception("Couldn't get OpenAL device");
}
+Device::~Device()
+{
+ alcCloseDevice(dev);
+}
+
} // namespace AL
} // namespace Msp
public:
Device();
Device(const std::string &);
+ ~Device();
+
ALCdevice *get_device() { return dev; }
};
Distributed under the LGPL
*/
+#include <cstring>
#include <msp/core/except.h>
#include "sound.h"
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)
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;
}
{
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
#ifndef MSP_AL_SOUND_H_
#define MSP_AL_SOUND_H_
+#include <string>
#include <vorbis/vorbisfile.h>
#include "format.h"
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
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()
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();
};
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);
}
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);
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);
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();
--- /dev/null
+/* $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
--- /dev/null
+/* $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