From: Mikko Rasa Date: Tue, 20 Nov 2012 14:48:04 +0000 (+0200) Subject: Split Sound into SoundDecoder and Waveform parts X-Git-Url: http://git.tdb.fi/?p=libs%2Fal.git;a=commitdiff_plain;h=6cc0f1735a00e8f9eb80ff0c9468fb67205f6d20 Split Sound into SoundDecoder and Waveform parts --- diff --git a/source/buffer.cpp b/source/buffer.cpp index 1d7510e..5aef1b4 100644 --- a/source/buffer.cpp +++ b/source/buffer.cpp @@ -1,5 +1,5 @@ #include "buffer.h" -#include "sound.h" +#include "waveform.h" using namespace std; @@ -21,17 +21,17 @@ void Buffer::data(Format fmt, const void *dt, sizei size, sizei freq) 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); } @@ -43,10 +43,10 @@ Buffer::Loader::Loader(Buffer &b): 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 diff --git a/source/buffer.h b/source/buffer.h index d84e46a..38ca36d 100644 --- a/source/buffer.h +++ b/source/buffer.h @@ -10,7 +10,7 @@ namespace Msp { namespace AL { -class Sound; +class Waveform; /** Buffers are used to store audio data and feed it into a Source. @@ -38,7 +38,7 @@ public: 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 &); }; diff --git a/source/jukebox.cpp b/source/jukebox.cpp index d2a997d..02a33cd 100644 --- a/source/jukebox.cpp +++ b/source/jukebox.cpp @@ -2,7 +2,7 @@ #include #include #include "jukebox.h" -#include "sound.h" +#include "sounddecoder.h" using namespace std; @@ -11,7 +11,7 @@ namespace AL { Jukebox::Jukebox(): streamer(source), - sound(0), + decoder(0), current_track(tracks.end()), shuffle(false) { } @@ -19,7 +19,7 @@ Jukebox::Jukebox(): Jukebox::~Jukebox() { streamer.stop(); - delete sound; + delete decoder; } void Jukebox::add_track(const string &trk) @@ -67,12 +67,12 @@ void Jukebox::set_shuffle(bool s) 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() @@ -123,14 +123,14 @@ void Jukebox::previous() 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(); } diff --git a/source/jukebox.h b/source/jukebox.h index 1367295..fe17f2e 100644 --- a/source/jukebox.h +++ b/source/jukebox.h @@ -10,7 +10,7 @@ namespace Msp { namespace AL { -class Sound; +class SoundDecoder; class Jukebox { @@ -20,7 +20,7 @@ public: private: Source source; Streamer streamer; - Sound *sound; + SoundDecoder *decoder; std::list tracks; std::list::iterator current_track; bool shuffle; diff --git a/source/sound.cpp b/source/sound.cpp deleted file mode 100644 index fe2de5e..0000000 --- a/source/sound.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include -#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(src); - unsigned len = min(size*nmemb, memsrc.length-memsrc.pos); - memcpy(ptr, reinterpret_cast(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(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(src); - return 0; -} - -long memory_tell(void *src) -{ - MemorySource &memsrc = *reinterpret_cast(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(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 diff --git a/source/sound.h b/source/sound.h deleted file mode 100644 index 60bdf45..0000000 --- a/source/sound.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef MSP_AL_SOUND_H_ -#define MSP_AL_SOUND_H_ - -#include -#include -#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 diff --git a/source/sounddecoder.cpp b/source/sounddecoder.cpp new file mode 100644 index 0000000..d4d1767 --- /dev/null +++ b/source/sounddecoder.cpp @@ -0,0 +1,142 @@ +#include +#include +#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(src); + unsigned len = min(size*nmemb, memsrc.length-memsrc.pos); + memcpy(ptr, reinterpret_cast(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(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(src); + return 0; +} + +long memory_tell(void *src) +{ + MemorySource &memsrc = *reinterpret_cast(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(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 diff --git a/source/sounddecoder.h b/source/sounddecoder.h new file mode 100644 index 0000000..ad56646 --- /dev/null +++ b/source/sounddecoder.h @@ -0,0 +1,46 @@ +#ifndef MSP_AL_SOUND_H_ +#define MSP_AL_SOUND_H_ + +#include +#include +#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 diff --git a/source/streamer.cpp b/source/streamer.cpp index b90a9d1..bca08a2 100644 --- a/source/streamer.cpp +++ b/source/streamer.cpp @@ -1,5 +1,5 @@ #include "buffer.h" -#include "sound.h" +#include "sounddecoder.h" #include "streamer.h" using namespace std; @@ -9,7 +9,7 @@ namespace AL { Streamer::Streamer(Source &s): src(s), - snd(0) + decoder(0) { } Streamer::~Streamer() @@ -20,16 +20,16 @@ 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(); } @@ -45,13 +45,13 @@ void Streamer::tick() } } - 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 data(chunk_size); @@ -60,7 +60,7 @@ void Streamer::tick() unsigned pos = 0; while(posread(&data[0]+pos, chunk_size-pos); + unsigned len = decoder->read(&data[0]+pos, chunk_size-pos); if(len==0) break; pos += len; @@ -69,14 +69,14 @@ void Streamer::tick() 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 diff --git a/source/streamer.h b/source/streamer.h index 7843e9e..192ede9 100644 --- a/source/streamer.h +++ b/source/streamer.h @@ -7,26 +7,26 @@ 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 buffers; public: Streamer(Source &); ~Streamer(); - void play(Sound &); + void play(SoundDecoder &); void stop(); void tick(); }; diff --git a/source/waveform.cpp b/source/waveform.cpp new file mode 100644 index 0000000..36978c6 --- /dev/null +++ b/source/waveform.cpp @@ -0,0 +1,50 @@ +#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 diff --git a/source/waveform.h b/source/waveform.h new file mode 100644 index 0000000..c1f0a2d --- /dev/null +++ b/source/waveform.h @@ -0,0 +1,37 @@ +#ifndef MSP_AL_WAVEFORM_H_ +#define MSP_AL_WAVEFORM_H_ + +#include +#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