]> git.tdb.fi Git - libs/al.git/blob - source/sounddecoder.cpp
Use Msp::IO in SoundDecoder
[libs/al.git] / source / sounddecoder.cpp
1 #include <cstring>
2 #include <stdexcept>
3 #include <msp/io/file.h>
4 #include <msp/io/memory.h>
5 #include "sounddecoder.h"
6
7 using namespace std;
8
9 namespace {
10
11 size_t read(void *ptr, size_t size, size_t nmemb, void *src)
12 {
13         Msp::IO::Base *in = reinterpret_cast<Msp::IO::Base *>(src);
14         unsigned len = in->read(reinterpret_cast<char *>(ptr), size*nmemb);
15         return len/size;
16 }
17
18 int seek(void *src, ogg_int64_t offset, int whence)
19 {
20         Msp::IO::SeekType type;
21         if(whence==SEEK_SET)
22                 type = Msp::IO::S_BEG;
23         else if(whence==SEEK_CUR)
24                 type = Msp::IO::S_CUR;
25         else if(whence==SEEK_END)
26                 type = Msp::IO::S_END;
27         else
28                 return -1;
29
30         Msp::IO::Seekable *in = reinterpret_cast<Msp::IO::Seekable *>(src);
31         return in->seek(offset, type);
32 }
33
34 long tell(void *src)
35 {
36         return reinterpret_cast<Msp::IO::Seekable *>(src)->tell();
37 }
38
39 ov_callbacks io_callbacks =
40 {
41         &read,
42         &seek,
43         0,
44         &tell
45 };
46
47 } // namespace
48
49 namespace Msp {
50 namespace AL {
51
52 SoundDecoder::SoundDecoder():
53         source(0),
54         eof_flag(false)
55 {
56         ovfile.datasource = 0;
57 }
58
59 SoundDecoder::~SoundDecoder()
60 {
61         close();
62 }
63
64 void SoundDecoder::open_file(const string &fn)
65 {
66         if(ovfile.datasource)
67                 throw logic_error("Sound has already been opened");
68
69         IO::BufferedFile *file = new IO::BufferedFile(fn);
70         if(ov_open_callbacks(file, &ovfile, 0, 0, io_callbacks)<0)
71         {
72                 delete file;
73                 throw runtime_error("Could not open ogg vorbis file "+fn);
74         }
75         source = file;
76
77         open_common();
78 }
79
80 void SoundDecoder::open_io(Msp::IO::Seekable &io)
81 {
82         if(ovfile.datasource)
83                 throw logic_error("Sound has already been opened");
84
85         if(ov_open_callbacks(&io, &ovfile, 0, 0, io_callbacks)<0)
86                 throw runtime_error("Could not open ogg vorbis resource");
87
88         open_common();
89 }
90
91 void SoundDecoder::open_common()
92 {
93         vorbis_info *info = ov_info(&ovfile, -1);
94         freq = info->rate;
95
96         size = ov_pcm_total(&ovfile, 0)*info->channels*2;
97
98         switch(info->channels)
99         {
100         case 1: format = MONO16; break;
101         case 2: format = STEREO16; break;
102         default: throw runtime_error("Unsupported number of channels");
103         }
104 }
105
106 void SoundDecoder::close()
107 {
108         if(ovfile.datasource)
109                 ov_clear(&ovfile);
110         delete source;
111         source = 0;
112 }
113
114 void SoundDecoder::rewind()
115 {
116         ov_pcm_seek(&ovfile, 0);
117 }
118
119 unsigned SoundDecoder::read(char *buf, unsigned len)
120 {
121         int section = 0;
122         int res = ov_read(&ovfile, buf, len, 0, 2, 1, &section);
123         if(res<0)
124                 throw runtime_error("Error reading ogg vorbis file");
125         else if(res==0)
126                 eof_flag = true;
127         return res;
128 }
129
130 } // namespace AL
131 } // namespace Msp