]> git.tdb.fi Git - libs/al.git/blob - source/oggdecoder.cpp
a00b78ed7341bbfb42e1229d006490f15a6514b1
[libs/al.git] / source / oggdecoder.cpp
1 #include <stdexcept>
2 #include <vorbis/vorbisfile.h>
3 #include "oggdecoder.h"
4
5 using namespace std;
6
7 namespace {
8
9 size_t read(void *ptr, size_t size, size_t nmemb, void *src)
10 {
11         Msp::IO::Base *in = reinterpret_cast<Msp::IO::Base *>(src);
12         unsigned len = in->read(reinterpret_cast<char *>(ptr), size*nmemb);
13         return len/size;
14 }
15
16 int seek(void *src, ogg_int64_t offset, int whence)
17 {
18         Msp::IO::SeekType type;
19         if(whence==SEEK_SET)
20                 type = Msp::IO::S_BEG;
21         else if(whence==SEEK_CUR)
22                 type = Msp::IO::S_CUR;
23         else if(whence==SEEK_END)
24                 type = Msp::IO::S_END;
25         else
26                 return -1;
27
28         Msp::IO::Seekable *in = reinterpret_cast<Msp::IO::Seekable *>(src);
29         return in->seek(offset, type);
30 }
31
32 long tell(void *src)
33 {
34         return reinterpret_cast<Msp::IO::Seekable *>(src)->tell();
35 }
36
37 ov_callbacks io_callbacks =
38 {
39         &read,
40         &seek,
41         0,
42         &tell
43 };
44
45 } // namespace
46
47
48 namespace Msp {
49 namespace AL {
50
51 struct OggDecoder::Private
52 {
53         OggVorbis_File ovfile;  
54 };
55
56 OggDecoder::OggDecoder(IO::Seekable &io):
57         priv(new Private)
58 {
59         if(ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks)<0)
60                 throw runtime_error("Could not open ogg vorbis resource");
61
62         vorbis_info *info = ov_info(&priv->ovfile, -1);
63         freq = info->rate;
64
65         size = ov_pcm_total(&priv->ovfile, 0)*info->channels*2;
66
67         switch(info->channels)
68         {
69         case 1: format = MONO16; break;
70         case 2: format = STEREO16; break;
71         default: throw runtime_error("Unsupported number of channels");
72         }
73 }
74
75 OggDecoder::~OggDecoder()
76 {
77         if(priv->ovfile.datasource)
78                 ov_clear(&priv->ovfile);
79         delete priv;
80 }
81
82 void OggDecoder::rewind()
83 {
84         ov_pcm_seek(&priv->ovfile, 0);
85 }
86
87 unsigned OggDecoder::read(char *buf, unsigned len)
88 {
89         int section = 0;
90         int res = ov_read(&priv->ovfile, buf, len, 0, 2, 1, &section);
91         if(res<0)
92                 throw runtime_error("Error reading ogg vorbis file");
93         else if(res==0)
94                 eof_flag = true;
95         return res;
96 }
97
98 } // namespace AL
99 } // namespace Msp