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