]> git.tdb.fi Git - libs/al.git/blob - source/oggdecoder.cpp
Some compilation fixes for Windows too
[libs/al.git] / source / oggdecoder.cpp
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"
7
8 using namespace std;
9
10 namespace {
11
12 size_t read(void *ptr, size_t size, size_t nmemb, void *src)
13 {
14         Msp::IO::Base *in = reinterpret_cast<Msp::IO::Base *>(src);
15         unsigned len = in->read(reinterpret_cast<char *>(ptr), size*nmemb);
16         return len/size;
17 }
18
19 int seek(void *src, ogg_int64_t offset, int whence)
20 {
21         Msp::IO::SeekType type;
22         if(whence==SEEK_SET)
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;
28         else
29                 return -1;
30
31         Msp::IO::Seekable *in = reinterpret_cast<Msp::IO::Seekable *>(src);
32         return in->seek(offset, type);
33 }
34
35 long tell(void *src)
36 {
37         return reinterpret_cast<Msp::IO::Seekable *>(src)->tell();
38 }
39
40 ov_callbacks io_callbacks =
41 {
42         &read,
43         &seek,
44         0,
45         &tell
46 };
47
48 } // namespace
49
50
51 namespace Msp {
52 namespace AL {
53
54 ogg_error::ogg_error(const std::string &func, int code):
55         runtime_error(format("%s: %s", func, get_message(code)))
56 { }
57
58 string ogg_error::get_message(int code)
59 {
60         switch(code)
61         {
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);
74         }
75 }
76
77
78 struct OggDecoder::Private
79 {
80         OggVorbis_File ovfile;  
81 };
82
83 OggDecoder::OggDecoder(IO::Seekable &io):
84         priv(new Private)
85 {
86         int ret = ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks);
87         if(ret<0)
88                 throw ogg_error("ov_open_callbacks", ret);
89
90         vorbis_info *info = ov_info(&priv->ovfile, -1);
91         freq = info->rate;
92
93         size = ov_pcm_total(&priv->ovfile, 0)*info->channels*2;
94
95         switch(info->channels)
96         {
97         case 1: format = MONO16; break;
98         case 2: format = STEREO16; break;
99         default: throw unsupported_sound(Msp::format("%d channels", info->channels));
100         }
101 }
102
103 OggDecoder::~OggDecoder()
104 {
105         if(priv->ovfile.datasource)
106                 ov_clear(&priv->ovfile);
107         delete priv;
108 }
109
110 void OggDecoder::rewind()
111 {
112         ov_pcm_seek(&priv->ovfile, 0);
113 }
114
115 unsigned OggDecoder::read(char *buf, unsigned len)
116 {
117         int section = 0;
118         int res = ov_read(&priv->ovfile, buf, len, 0, 2, 1, &section);
119         if(res<0)
120                 throw ogg_error("ov_read", res);
121         else if(res==0)
122                 eof_flag = true;
123         return res;
124 }
125
126 } // namespace AL
127 } // namespace Msp