]> git.tdb.fi Git - libs/al.git/blob - source/sound.cpp
Drop copyright notices and Id tags from source files
[libs/al.git] / source / sound.cpp
1 #include <cstring>
2 #include <msp/core/except.h>
3 #include "sound.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(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 Sound::Sound():
68         data(0),
69         eof_flag(false)
70 {
71         ovfile.datasource = 0;
72 }
73
74 Sound::~Sound()
75 {
76         delete[] data;
77         if(ovfile.datasource)
78                 ov_clear(&ovfile);
79 }
80
81 void Sound::open_file(const string &fn)
82 {
83         if(ovfile.datasource)
84                 throw InvalidState("Sound has already been opened");
85         if(ov_fopen(const_cast<char *>(fn.c_str()), &ovfile)<0)
86                 throw Exception("Could not open ogg vorbis file "+fn);
87
88         open_common();
89 }
90
91 void Sound::open_memory(const void *d, unsigned len)
92 {
93         if(ovfile.datasource)
94                 throw InvalidState("Sound has already been opened");
95
96         MemorySource *src = new MemorySource(d, len);
97         if(ov_open_callbacks(src, &ovfile, 0, 0, memory_callbacks)<0)
98         {
99                 delete src;
100                 throw Exception("Could not open ogg vorbis memory block");
101         }
102
103         open_common();
104 }
105
106 void Sound::load_data()
107 {
108         if(data)
109                 throw InvalidState("Data has already been loaded");
110
111         size = ov_pcm_total(&ovfile, 0)*4;
112         char *dptr = new char[size];
113         unsigned pos = 0;
114         while(unsigned len = read(dptr+pos, size-pos))
115                 pos += len;
116         data = dptr;
117         size = pos;
118         read_pos = 0;
119 }
120
121 void Sound::load_file(const std::string &fn)
122 {
123         open_file(fn);
124         load_data();
125         close();
126 }
127
128 void Sound::load_memory(const void *d, unsigned len)
129 {
130         open_memory(d, len);
131         load_data();
132         close();
133 }
134
135 void Sound::close()
136 {
137         if(ovfile.datasource)
138                 ov_clear(&ovfile);
139 }
140
141 void Sound::rewind()
142 {
143         if(data)
144                 read_pos = 0;
145         else
146                 ov_pcm_seek(&ovfile, 0);
147 }
148
149 unsigned Sound::read(char *buf, unsigned len)
150 {
151         if(data)
152         {
153                 len = min(len, size-read_pos);
154                 memcpy(buf, data+read_pos, len);
155                 read_pos += len;
156                 return len;
157         }
158         else if(ovfile.datasource)
159         {
160                 int section = 0;
161                 int res = ov_read(&ovfile, buf, len, 0, 2, 1, &section);
162                 if(res<0)
163                         throw Exception("Error reading ogg vorbis file");
164                 else if(res==0)
165                         eof_flag = true;
166                 return res;
167         }
168         else
169                 throw InvalidState("No data available");
170 }
171
172 const char *Sound::get_data() const
173 {
174         if(!data)
175                 throw InvalidState("Data has not been loaded");
176         return data;
177 }
178
179 void Sound::open_common()
180 {
181         delete data;
182         data = 0;
183
184         vorbis_info *info = ov_info(&ovfile, -1);
185         freq = info->rate;
186         switch(info->channels)
187         {
188         case 1: format = MONO16; break;
189         case 2: format = STEREO16; break;
190         default: throw Exception("Unsupported number of channels");
191         }
192 }
193
194 } // namespace AL
195 } // namespace Msp