]> git.tdb.fi Git - libs/al.git/blobdiff - source/oggdecoder.cpp
Make SoundDecoder a base class and split off Ogg decoding
[libs/al.git] / source / oggdecoder.cpp
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