1 #pragma GCC diagnostic push
2 #pragma GCC diagnostic ignored "-Wunused-variable"
3 #include <vorbis/vorbisfile.h>
4 #pragma GCC diagnostic pop
5 #include <msp/strings/format.h>
6 #include "oggdecoder.h"
12 size_t read(void *ptr, size_t size, size_t nmemb, void *src)
14 Msp::IO::Base *in = reinterpret_cast<Msp::IO::Base *>(src);
15 unsigned len = in->read(reinterpret_cast<char *>(ptr), size*nmemb);
19 int seek(void *src, ogg_int64_t offset, int whence)
21 Msp::IO::SeekType type;
23 type = Msp::IO::S_BEG;
24 else if(whence==SEEK_CUR)
25 type = Msp::IO::S_CUR;
26 else if(whence==SEEK_END)
27 type = Msp::IO::S_END;
31 Msp::IO::Seekable *in = reinterpret_cast<Msp::IO::Seekable *>(src);
32 return in->seek(offset, type);
37 return reinterpret_cast<Msp::IO::Seekable *>(src)->tell();
40 ov_callbacks io_callbacks =
54 ogg_error::ogg_error(const std::string &func, int code):
55 runtime_error(format("%s: %s", func, get_message(code)))
58 string ogg_error::get_message(int code)
62 case OV_FALSE: return "No data available";
63 case OV_HOLE: return "Missing or corrupt data";
64 case OV_EREAD: return "Read error";
65 case OV_EFAULT: return "Internal inconsistency";
66 case OV_EIMPL: return "Not implemented";
67 case OV_EINVAL: return "Invalid argument";
68 case OV_ENOTVORBIS: return "Not Vorbis data";
69 case OV_EBADHEADER: return "Corrupt Vorbis header";
70 case OV_EVERSION: return "Unsupported version";
71 case OV_EBADLINK: return "Bad link";
72 case OV_ENOSEEK: return "Stream is not seekable";
73 default: return format("Unknown error (%d)", code);
78 struct OggDecoder::Private
80 OggVorbis_File ovfile;
83 OggDecoder::OggDecoder(IO::Seekable &io):
86 int ret = ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks);
88 throw ogg_error("ov_open_callbacks", ret);
90 vorbis_info *info = ov_info(&priv->ovfile, -1);
93 size = ov_pcm_total(&priv->ovfile, 0)*info->channels*2;
95 switch(info->channels)
97 case 1: format = MONO16; break;
98 case 2: format = STEREO16; break;
99 default: throw unsupported_sound(Msp::format("%d channels", info->channels));
103 OggDecoder::~OggDecoder()
105 if(priv->ovfile.datasource)
106 ov_clear(&priv->ovfile);
110 bool OggDecoder::detect(const std::string &sig)
112 static const char ogg_sig[] = { 'O', 'g', 'g', 'S' };
113 if(sig.size()<sizeof(ogg_sig))
115 return !sig.compare(0, sizeof(ogg_sig), ogg_sig);
118 void OggDecoder::rewind()
120 ov_pcm_seek(&priv->ovfile, 0);
123 unsigned OggDecoder::read(char *buf, unsigned len)
126 int res = ov_read(&priv->ovfile, buf, len, 0, 2, 1, §ion);
128 throw ogg_error("ov_read", res);