]> git.tdb.fi Git - libs/al.git/commitdiff
Make SoundDecoder a base class and split off Ogg decoding
authorMikko Rasa <tdb@tdb.fi>
Tue, 20 Nov 2012 22:37:25 +0000 (00:37 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 20 Nov 2012 22:38:55 +0000 (00:38 +0200)
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
source/oggdecoder.cpp [new file with mode: 0644]
source/oggdecoder.h [new file with mode: 0644]
source/sounddecoder.cpp
source/sounddecoder.h
source/waveform.cpp

index 02a33cdfee3e1d55e56eed59b647b7fe630131a0..52f673e796c49bf875de112c9a0ecb937d7e630e 100644 (file)
@@ -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 (file)
index 0000000..a00b78e
--- /dev/null
@@ -0,0 +1,99 @@
+#include <stdexcept>
+#include <vorbis/vorbisfile.h>
+#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<Msp::IO::Base *>(src);
+       unsigned len = in->read(reinterpret_cast<char *>(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<Msp::IO::Seekable *>(src);
+       return in->seek(offset, type);
+}
+
+long tell(void *src)
+{
+       return reinterpret_cast<Msp::IO::Seekable *>(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, &section);
+       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 (file)
index 0000000..a3f5504
--- /dev/null
@@ -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
index c9da9b808e75b87b540179e4932907fbd92b6858..77e3b408da40737cb7854af1a8283e489ae7ae99 100644 (file)
-#include <cstring>
-#include <stdexcept>
+#include <msp/core/refptr.h>
 #include <msp/io/file.h>
-#include <msp/io/memory.h>
+#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<Msp::IO::Base *>(src);
-       unsigned len = in->read(reinterpret_cast<char *>(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<Msp::IO::Seekable *>(src);
-       return in->seek(offset, type);
-}
-
-long tell(void *src)
-{
-       return reinterpret_cast<Msp::IO::Seekable *>(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<IO::BufferedFile> 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, &section);
-       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
index c9566592f38870198e84bc8a263cf65d5b177522..7a08644117317623d629b88559788036b5f16e8b 100644 (file)
@@ -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 <string>
-#include <vorbis/vorbisfile.h>
 #include <msp/io/seekable.h>
 #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; }
index de195f7671ab00e8a95dda3539318e5aeae11f09..57fc291eb4b10a47a2f9818358151a6cbefae0d2 100644 (file)
@@ -1,3 +1,4 @@
+#include <msp/core/refptr.h>
 #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<SoundDecoder> decoder = SoundDecoder::open_file(fn);
+       load(*decoder);
 }
 
 void Waveform::load_io(IO::Seekable &io)
 {
-       SoundDecoder decoder;
-       decoder.open_io(io);
-       load(decoder);
+       RefPtr<SoundDecoder> decoder = SoundDecoder::open_io(io);
+       load(*decoder);
 }
 
 void Waveform::load(SoundDecoder &decoder)