#include "buffer.h"
-#include "sound.h"
+#include "waveform.h"
using namespace std;
alBufferData(id, fmt, dt, size, freq);
}
-void Buffer::data(const Sound &snd)
+void Buffer::data(const Waveform &wave)
{
- data(snd.get_format(), snd.get_data(), snd.get_size(), snd.get_frequency());
+ data(wave.get_format(), wave.get_data(), wave.get_size(), wave.get_frequency());
}
void Buffer::load_data(const string &fn)
{
- Sound sound;
- sound.load_file(fn);
+ Waveform wave;
+ wave.load_file(fn);
- data(sound);
+ data(wave);
}
void Buffer::Loader::sound_data(const string &data)
{
- Sound sound;
- sound.load_memory(data.data(), data.size());
+ Waveform wave;
+ wave.load_memory(data.data(), data.size());
- buf.data(sound);
+ buf.data(wave);
}
} // namespace AL
namespace Msp {
namespace AL {
-class Sound;
+class Waveform;
/**
Buffers are used to store audio data and feed it into a Source.
uint get_id() const { return id; }
void data(Format, const void *, sizei, sizei);
- void data(const Sound &);
+ void data(const Waveform &);
void load_data(const std::string &);
};
#include <cstdlib>
#include <stdexcept>
#include "jukebox.h"
-#include "sound.h"
+#include "sounddecoder.h"
using namespace std;
Jukebox::Jukebox():
streamer(source),
- sound(0),
+ decoder(0),
current_track(tracks.end()),
shuffle(false)
{ }
Jukebox::~Jukebox()
{
streamer.stop();
- delete sound;
+ delete decoder;
}
void Jukebox::add_track(const string &trk)
void Jukebox::play()
{
- if(tracks.empty() || sound)
+ if(tracks.empty() || decoder)
return;
- sound = new AL::Sound;
- sound->open_file(*current_track);
- streamer.play(*sound);
+ decoder = new AL::SoundDecoder;
+ decoder->open_file(*current_track);
+ streamer.play(*decoder);
}
void Jukebox::next()
void Jukebox::stop()
{
streamer.stop();
- delete sound;
- sound = 0;
+ delete decoder;
+ decoder = 0;
}
void Jukebox::tick()
{
streamer.tick();
- if(sound && sound->eof())
+ if(decoder && decoder->eof())
next();
}
namespace Msp {
namespace AL {
-class Sound;
+class SoundDecoder;
class Jukebox
{
private:
Source source;
Streamer streamer;
- Sound *sound;
+ SoundDecoder *decoder;
std::list<std::string> tracks;
std::list<std::string>::iterator current_track;
bool shuffle;
+++ /dev/null
-#include <cstring>
-#include <stdexcept>
-#include "sound.h"
-
-using namespace std;
-
-namespace {
-
-struct MemorySource
-{
- const void *data;
- unsigned length;
- unsigned pos;
-
- MemorySource(const void *d, unsigned l): data(d), length(l), pos(0) { }
-};
-
-size_t memory_read(void *ptr, size_t size, size_t nmemb, void *src)
-{
- MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
- unsigned len = min<unsigned>(size*nmemb, memsrc.length-memsrc.pos);
- memcpy(ptr, reinterpret_cast<const char *>(memsrc.data)+memsrc.pos, len);
- memsrc.pos += len;
-
- return len/size;
-}
-
-int memory_seek(void *src, ogg_int64_t offset, int whence)
-{
- MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
- if(whence==SEEK_SET)
- memsrc.pos = offset;
- else if(whence==SEEK_CUR)
- memsrc.pos += offset;
- else if(whence==SEEK_END)
- memsrc.pos = memsrc.length-offset;
- memsrc.pos = min(memsrc.pos, memsrc.length);
-
- return memsrc.pos;
-}
-
-int memory_close(void *src)
-{
- delete reinterpret_cast<MemorySource *>(src);
- return 0;
-}
-
-long memory_tell(void *src)
-{
- MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
- return memsrc.pos;
-}
-
-ov_callbacks memory_callbacks=
-{
- &memory_read,
- &memory_seek,
- &memory_close,
- &memory_tell
-};
-
-} // namespace
-
-namespace Msp {
-namespace AL {
-
-Sound::Sound():
- data(0),
- eof_flag(false)
-{
- ovfile.datasource = 0;
-}
-
-Sound::~Sound()
-{
- delete[] data;
- if(ovfile.datasource)
- ov_clear(&ovfile);
-}
-
-void Sound::open_file(const string &fn)
-{
- if(ovfile.datasource)
- throw logic_error("Sound has already been opened");
- if(ov_fopen(const_cast<char *>(fn.c_str()), &ovfile)<0)
- throw runtime_error("Could not open ogg vorbis file "+fn);
-
- open_common();
-}
-
-void Sound::open_memory(const void *d, unsigned len)
-{
- if(ovfile.datasource)
- throw logic_error("Sound has already been opened");
-
- MemorySource *src = new MemorySource(d, len);
- if(ov_open_callbacks(src, &ovfile, 0, 0, memory_callbacks)<0)
- {
- delete src;
- throw runtime_error("Could not open ogg vorbis memory block");
- }
-
- open_common();
-}
-
-void Sound::open_common()
-{
- delete data;
- data = 0;
-
- vorbis_info *info = ov_info(&ovfile, -1);
- freq = info->rate;
- switch(info->channels)
- {
- case 1: format = MONO16; break;
- case 2: format = STEREO16; break;
- default: throw runtime_error("Unsupported number of channels");
- }
-}
-
-void Sound::load_data()
-{
- if(data)
- throw logic_error("Data has already been loaded");
-
- size = ov_pcm_total(&ovfile, 0)*4;
- char *dptr = new char[size];
- unsigned pos = 0;
- while(unsigned len = read(dptr+pos, size-pos))
- pos += len;
- data = dptr;
- size = pos;
- read_pos = 0;
-}
-
-void Sound::load_file(const std::string &fn)
-{
- open_file(fn);
- load_data();
- close();
-}
-
-void Sound::load_memory(const void *d, unsigned len)
-{
- open_memory(d, len);
- load_data();
- close();
-}
-
-void Sound::close()
-{
- 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)
-{
- 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 runtime_error("Error reading ogg vorbis file");
- else if(res==0)
- eof_flag = true;
- return res;
- }
- else
- throw logic_error("No data available");
-}
-
-const char *Sound::get_data() const
-{
- if(!data)
- throw logic_error("Data has not been loaded");
- return data;
-}
-
-} // namespace AL
-} // namespace Msp
+++ /dev/null
-#ifndef MSP_AL_SOUND_H_
-#define MSP_AL_SOUND_H_
-
-#include <string>
-#include <vorbis/vorbisfile.h>
-#include "format.h"
-
-namespace Msp {
-namespace AL {
-
-/**
-This class facilitates loading sound files. Currently only Ogg Vorbis is
-supported.
-*/
-class Sound
-{
-private:
- OggVorbis_File ovfile;
- unsigned freq;
- unsigned size;
- char *data;
- Format format;
- unsigned read_pos;
- bool eof_flag;
-
-public:
- Sound();
- ~Sound();
-
- void open_file(const std::string &);
- void open_memory(const void *, unsigned);
-private:
- void open_common();
-public:
- void load_data();
- void load_file(const std::string &);
- void load_memory(const void *, unsigned);
- 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;
-};
-
-} // namespace AL
-} // namespace Msp
-
-#endif
--- /dev/null
+#include <cstring>
+#include <stdexcept>
+#include "sounddecoder.h"
+
+using namespace std;
+
+namespace {
+
+struct MemorySource
+{
+ const void *data;
+ unsigned length;
+ unsigned pos;
+
+ MemorySource(const void *d, unsigned l): data(d), length(l), pos(0) { }
+};
+
+size_t memory_read(void *ptr, size_t size, size_t nmemb, void *src)
+{
+ MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
+ unsigned len = min<unsigned>(size*nmemb, memsrc.length-memsrc.pos);
+ memcpy(ptr, reinterpret_cast<const char *>(memsrc.data)+memsrc.pos, len);
+ memsrc.pos += len;
+
+ return len/size;
+}
+
+int memory_seek(void *src, ogg_int64_t offset, int whence)
+{
+ MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
+ if(whence==SEEK_SET)
+ memsrc.pos = offset;
+ else if(whence==SEEK_CUR)
+ memsrc.pos += offset;
+ else if(whence==SEEK_END)
+ memsrc.pos = memsrc.length-offset;
+ memsrc.pos = min(memsrc.pos, memsrc.length);
+
+ return memsrc.pos;
+}
+
+int memory_close(void *src)
+{
+ delete reinterpret_cast<MemorySource *>(src);
+ return 0;
+}
+
+long memory_tell(void *src)
+{
+ MemorySource &memsrc = *reinterpret_cast<MemorySource *>(src);
+ return memsrc.pos;
+}
+
+ov_callbacks memory_callbacks=
+{
+ &memory_read,
+ &memory_seek,
+ &memory_close,
+ &memory_tell
+};
+
+} // namespace
+
+namespace Msp {
+namespace AL {
+
+SoundDecoder::SoundDecoder():
+ eof_flag(false)
+{
+ ovfile.datasource = 0;
+}
+
+SoundDecoder::~SoundDecoder()
+{
+ if(ovfile.datasource)
+ ov_clear(&ovfile);
+}
+
+void SoundDecoder::open_file(const string &fn)
+{
+ if(ovfile.datasource)
+ throw logic_error("Sound has already been opened");
+ if(ov_fopen(const_cast<char *>(fn.c_str()), &ovfile)<0)
+ throw runtime_error("Could not open ogg vorbis file "+fn);
+
+ open_common();
+}
+
+void SoundDecoder::open_memory(const void *d, unsigned len)
+{
+ if(ovfile.datasource)
+ throw logic_error("Sound has already been opened");
+
+ MemorySource *src = new MemorySource(d, len);
+ if(ov_open_callbacks(src, &ovfile, 0, 0, memory_callbacks)<0)
+ {
+ delete src;
+ throw runtime_error("Could not open ogg vorbis memory block");
+ }
+
+ open_common();
+}
+
+void SoundDecoder::open_common()
+{
+ vorbis_info *info = ov_info(&ovfile, -1);
+ freq = info->rate;
+
+ size = ov_pcm_total(&ovfile, 0)*info->channels*2;
+
+ switch(info->channels)
+ {
+ case 1: format = MONO16; break;
+ case 2: format = STEREO16; break;
+ default: throw runtime_error("Unsupported number of channels");
+ }
+}
+
+void SoundDecoder::close()
+{
+ if(ovfile.datasource)
+ ov_clear(&ovfile);
+}
+
+void SoundDecoder::rewind()
+{
+ ov_pcm_seek(&ovfile, 0);
+}
+
+unsigned SoundDecoder::read(char *buf, unsigned len)
+{
+ int section = 0;
+ int res = ov_read(&ovfile, buf, len, 0, 2, 1, §ion);
+ if(res<0)
+ throw runtime_error("Error reading ogg vorbis file");
+ else if(res==0)
+ eof_flag = true;
+ return res;
+}
+
+} // namespace AL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_AL_SOUND_H_
+#define MSP_AL_SOUND_H_
+
+#include <string>
+#include <vorbis/vorbisfile.h>
+#include "format.h"
+
+namespace Msp {
+namespace AL {
+
+/**
+This class facilitates loading sound files. Currently only Ogg Vorbis is
+supported.
+*/
+class SoundDecoder
+{
+private:
+ OggVorbis_File ovfile;
+ unsigned freq;
+ unsigned size;
+ Format format;
+ bool eof_flag;
+
+public:
+ SoundDecoder();
+ ~SoundDecoder();
+
+ void open_file(const std::string &);
+ void open_memory(const void *, unsigned);
+private:
+ void open_common();
+public:
+ 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; }
+};
+
+} // namespace AL
+} // namespace Msp
+
+#endif
#include "buffer.h"
-#include "sound.h"
+#include "sounddecoder.h"
#include "streamer.h"
using namespace std;
Streamer::Streamer(Source &s):
src(s),
- snd(0)
+ decoder(0)
{ }
Streamer::~Streamer()
delete *i;
}
-void Streamer::play(Sound &s)
+void Streamer::play(SoundDecoder &s)
{
- snd = &s;
+ decoder = &s;
tick();
src.play();
}
void Streamer::stop()
{
- snd = 0;
+ decoder = 0;
src.stop();
}
}
}
- if(!snd)
+ if(!decoder)
return;
if(src.get_state()!=PLAYING && src.get_state()!=PAUSED)
src.play();
- unsigned freq = snd->get_frequency();
+ unsigned freq = decoder->get_frequency();
unsigned chunk_size = freq&~0xF;
unsigned queued = src.get_buffers_queued();
vector<char> data(chunk_size);
unsigned pos = 0;
while(pos<chunk_size)
{
- unsigned len = snd->read(&data[0]+pos, chunk_size-pos);
+ unsigned len = decoder->read(&data[0]+pos, chunk_size-pos);
if(len==0)
break;
pos += len;
if(pos)
{
Buffer *buf = new Buffer;
- buf->data(snd->get_format(), &data[0], pos, freq);
+ buf->data(decoder->get_format(), &data[0], pos, freq);
src.queue_buffer(*buf);
buffers.push_back(buf);
}
}
- if(snd->eof())
- snd = 0;
+ if(decoder->eof())
+ decoder = 0;
}
} // namespace AL
namespace Msp {
namespace AL {
-class Sound;
+class SoundDecoder;
class Buffer;
/**
-A streamer transfers data from a Sound to a Source. It is permanently attached
-to the same Source, but can play multiple Sounds during its lifetime. A single
-Sound can only be played by one Streamer at a time.
+A streamer transfers data from a SoundDecoder to a Source. It is permanently
+attached to the same Source, but can read from multiple decoders during its
+lifetime.
*/
class Streamer
{
private:
Source &src;
- Sound *snd;
+ SoundDecoder *decoder;
std::list<Buffer *> buffers;
public:
Streamer(Source &);
~Streamer();
- void play(Sound &);
+ void play(SoundDecoder &);
void stop();
void tick();
};
--- /dev/null
+#include "sounddecoder.h"
+#include "waveform.h"
+
+using namespace std;
+
+namespace Msp {
+namespace AL {
+
+Waveform::Waveform():
+ format(MONO8),
+ freq(0),
+ size(0),
+ data(0)
+{ }
+
+Waveform::~Waveform()
+{
+ delete[] data;
+}
+
+void Waveform::load_file(const string &fn)
+{
+ SoundDecoder decoder;
+ decoder.open_file(fn);
+ load(decoder);
+}
+
+void Waveform::load_memory(const void *d, unsigned len)
+{
+ SoundDecoder decoder;
+ decoder.open_memory(d, len);
+ load(decoder);
+}
+
+void Waveform::load(SoundDecoder &decoder)
+{
+ delete[] data;
+
+ format = decoder.get_format();
+ freq = decoder.get_frequency();
+ size = decoder.get_size();
+ data = new char[size];
+ unsigned pos = 0;
+ while(unsigned len = decoder.read(data+pos, size-pos))
+ pos += len;
+ size = pos;
+}
+
+} // namespace AL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_AL_WAVEFORM_H_
+#define MSP_AL_WAVEFORM_H_
+
+#include <string>
+#include "format.h"
+
+namespace Msp {
+namespace AL {
+
+class SoundDecoder;
+
+class Waveform
+{
+private:
+ Format format;
+ unsigned freq;
+ unsigned size;
+ char *data;
+
+public:
+ Waveform();
+ ~Waveform();
+
+ void load_file(const std::string &);
+ void load_memory(const void *, unsigned);
+ void load(SoundDecoder &);
+
+ Format get_format() const { return format; }
+ unsigned get_frequency() const { return freq; }
+ unsigned get_size() const { return size; }
+ const char *get_data() const { return data; }
+};
+
+} // namespace AL
+} // namespace Msp
+
+#endif