From 10cdb043b613d60c5de8f1cce0f7a5512b0d0074 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 21 Nov 2012 00:37:25 +0200 Subject: [PATCH] Make SoundDecoder a base class and split off Ogg decoding Decoders are now created with a static factory function, without a separate open call. This allows autodetecting the decoder type later and simplifies resource management. The Ogg specific stuff was also hidden behind a private pointer to further improve encapsulation and reduce namespace pollution. --- source/jukebox.cpp | 3 +- source/oggdecoder.cpp | 99 +++++++++++++++++++++++++++++++++ source/oggdecoder.h | 27 +++++++++ source/sounddecoder.cpp | 119 +++++----------------------------------- source/sounddecoder.h | 24 ++++---- source/waveform.cpp | 11 ++-- 6 files changed, 155 insertions(+), 128 deletions(-) create mode 100644 source/oggdecoder.cpp create mode 100644 source/oggdecoder.h diff --git a/source/jukebox.cpp b/source/jukebox.cpp index 02a33cd..52f673e 100644 --- a/source/jukebox.cpp +++ b/source/jukebox.cpp @@ -70,8 +70,7 @@ void Jukebox::play() if(tracks.empty() || decoder) return; - decoder = new AL::SoundDecoder; - decoder->open_file(*current_track); + decoder = SoundDecoder::open_file(*current_track); streamer.play(*decoder); } diff --git a/source/oggdecoder.cpp b/source/oggdecoder.cpp new file mode 100644 index 0000000..a00b78e --- /dev/null +++ b/source/oggdecoder.cpp @@ -0,0 +1,99 @@ +#include +#include +#include "oggdecoder.h" + +using namespace std; + +namespace { + +size_t read(void *ptr, size_t size, size_t nmemb, void *src) +{ + Msp::IO::Base *in = reinterpret_cast(src); + unsigned len = in->read(reinterpret_cast(ptr), size*nmemb); + return len/size; +} + +int seek(void *src, ogg_int64_t offset, int whence) +{ + Msp::IO::SeekType type; + if(whence==SEEK_SET) + type = Msp::IO::S_BEG; + else if(whence==SEEK_CUR) + type = Msp::IO::S_CUR; + else if(whence==SEEK_END) + type = Msp::IO::S_END; + else + return -1; + + Msp::IO::Seekable *in = reinterpret_cast(src); + return in->seek(offset, type); +} + +long tell(void *src) +{ + return reinterpret_cast(src)->tell(); +} + +ov_callbacks io_callbacks = +{ + &read, + &seek, + 0, + &tell +}; + +} // namespace + + +namespace Msp { +namespace AL { + +struct OggDecoder::Private +{ + OggVorbis_File ovfile; +}; + +OggDecoder::OggDecoder(IO::Seekable &io): + priv(new Private) +{ + if(ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks)<0) + throw runtime_error("Could not open ogg vorbis resource"); + + vorbis_info *info = ov_info(&priv->ovfile, -1); + freq = info->rate; + + size = ov_pcm_total(&priv->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"); + } +} + +OggDecoder::~OggDecoder() +{ + if(priv->ovfile.datasource) + ov_clear(&priv->ovfile); + delete priv; +} + +void OggDecoder::rewind() +{ + ov_pcm_seek(&priv->ovfile, 0); +} + +unsigned OggDecoder::read(char *buf, unsigned len) +{ + int section = 0; + int res = ov_read(&priv->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/oggdecoder.h b/source/oggdecoder.h new file mode 100644 index 0000000..a3f5504 --- /dev/null +++ b/source/oggdecoder.h @@ -0,0 +1,27 @@ +#ifndef MSP_AL_OGGDECODER_H_ +#define MSP_AL_OGGDECODER_H_ + +#include "sounddecoder.h" + +namespace Msp { +namespace AL { + +class OggDecoder: public SoundDecoder +{ +private: + struct Private; + + Private *priv; + +public: + OggDecoder(IO::Seekable &); + ~OggDecoder(); + + virtual void rewind(); + virtual unsigned read(char *, unsigned); +}; + +} // namespace AL +} // namespace Msp + +#endif diff --git a/source/sounddecoder.cpp b/source/sounddecoder.cpp index c9da9b8..77e3b40 100644 --- a/source/sounddecoder.cpp +++ b/source/sounddecoder.cpp @@ -1,130 +1,37 @@ -#include -#include +#include #include -#include +#include "oggdecoder.h" #include "sounddecoder.h" using namespace std; -namespace { - -size_t read(void *ptr, size_t size, size_t nmemb, void *src) -{ - Msp::IO::Base *in = reinterpret_cast(src); - unsigned len = in->read(reinterpret_cast(ptr), size*nmemb); - return len/size; -} - -int seek(void *src, ogg_int64_t offset, int whence) -{ - Msp::IO::SeekType type; - if(whence==SEEK_SET) - type = Msp::IO::S_BEG; - else if(whence==SEEK_CUR) - type = Msp::IO::S_CUR; - else if(whence==SEEK_END) - type = Msp::IO::S_END; - else - return -1; - - Msp::IO::Seekable *in = reinterpret_cast(src); - return in->seek(offset, type); -} - -long tell(void *src) -{ - return reinterpret_cast(src)->tell(); -} - -ov_callbacks io_callbacks = -{ - &read, - &seek, - 0, - &tell -}; - -} // namespace - namespace Msp { namespace AL { SoundDecoder::SoundDecoder(): source(0), + freq(0), + size(0), + format(MONO8), eof_flag(false) -{ - ovfile.datasource = 0; -} +{ } SoundDecoder::~SoundDecoder() { - close(); -} - -void SoundDecoder::open_file(const string &fn) -{ - if(ovfile.datasource) - throw logic_error("Sound has already been opened"); - - IO::BufferedFile *file = new IO::BufferedFile(fn); - if(ov_open_callbacks(file, &ovfile, 0, 0, io_callbacks)<0) - { - delete file; - throw runtime_error("Could not open ogg vorbis file "+fn); - } - source = file; - - open_common(); -} - -void SoundDecoder::open_io(Msp::IO::Seekable &io) -{ - if(ovfile.datasource) - throw logic_error("Sound has already been opened"); - - if(ov_open_callbacks(&io, &ovfile, 0, 0, io_callbacks)<0) - throw runtime_error("Could not open ogg vorbis resource"); - - 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); delete source; - source = 0; } -void SoundDecoder::rewind() +SoundDecoder *SoundDecoder::open_file(const string &fn) { - ov_pcm_seek(&ovfile, 0); + RefPtr file = new IO::BufferedFile(fn); + SoundDecoder *decoder = new OggDecoder(*file); + decoder->source = file.release(); + return decoder; } -unsigned SoundDecoder::read(char *buf, unsigned len) +SoundDecoder *SoundDecoder::open_io(IO::Seekable &io) { - 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; + return new OggDecoder(io); } } // namespace AL diff --git a/source/sounddecoder.h b/source/sounddecoder.h index c956659..7a08644 100644 --- a/source/sounddecoder.h +++ b/source/sounddecoder.h @@ -1,8 +1,7 @@ -#ifndef MSP_AL_SOUND_H_ -#define MSP_AL_SOUND_H_ +#ifndef MSP_AL_SOUNDDECODER_H_ +#define MSP_AL_SOUNDDECODER_H_ #include -#include #include #include "format.h" @@ -16,25 +15,22 @@ supported. class SoundDecoder { private: - OggVorbis_File ovfile; IO::Seekable *source; +protected: unsigned freq; unsigned size; Format format; bool eof_flag; -public: SoundDecoder(); - ~SoundDecoder(); - - void open_file(const std::string &); - void open_io(IO::Seekable &); -private: - void open_common(); public: - void close(); - void rewind(); - unsigned read(char *, unsigned); + virtual ~SoundDecoder(); + + static SoundDecoder *open_file(const std::string &); + static SoundDecoder *open_io(IO::Seekable &); + + virtual void rewind() = 0; + virtual unsigned read(char *, unsigned) = 0; bool eof() const { return eof_flag; } Format get_format() const { return format; } diff --git a/source/waveform.cpp b/source/waveform.cpp index de195f7..57fc291 100644 --- a/source/waveform.cpp +++ b/source/waveform.cpp @@ -1,3 +1,4 @@ +#include #include "sounddecoder.h" #include "waveform.h" @@ -20,16 +21,14 @@ Waveform::~Waveform() void Waveform::load_file(const string &fn) { - SoundDecoder decoder; - decoder.open_file(fn); - load(decoder); + RefPtr decoder = SoundDecoder::open_file(fn); + load(*decoder); } void Waveform::load_io(IO::Seekable &io) { - SoundDecoder decoder; - decoder.open_io(io); - load(decoder); + RefPtr decoder = SoundDecoder::open_io(io); + load(*decoder); } void Waveform::load(SoundDecoder &decoder) -- 2.43.0