]> git.tdb.fi Git - libs/al.git/blob - source/sound.cpp
Fix some uninitialized variables and memory leaks
[libs/al.git] / source / sound.cpp
1 /* $Id$
2
3 This file is part of libmspal
4 Copyright © 2008-2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <cstring>
9 #include <msp/core/except.h>
10 #include "sound.h"
11
12 using namespace std;
13
14 namespace {
15
16 struct MemorySource
17 {
18         const void *data;
19         unsigned length;
20         unsigned pos;
21
22         MemorySource(const void *d, unsigned l): data(d), length(l), pos(0) { }
23 };
24
25 size_t memory_read(void *ptr, size_t size, size_t nmemb, void *src)
26 {
27         MemorySource &memsrc=*reinterpret_cast<MemorySource *>(src);
28         unsigned len=min(size*nmemb, memsrc.length-memsrc.pos);
29         memcpy(ptr, reinterpret_cast<const char *>(memsrc.data)+memsrc.pos, len);
30         memsrc.pos+=len;
31
32         return len/size;
33 }
34
35 int memory_seek(void *src, ogg_int64_t offset, int whence)
36 {
37         MemorySource &memsrc=*reinterpret_cast<MemorySource *>(src);
38         if(whence==SEEK_SET)
39                 memsrc.pos=offset;
40         else if(whence==SEEK_CUR)
41                 memsrc.pos+=offset;
42         else if(whence==SEEK_END)
43                 memsrc.pos=memsrc.length-offset;
44         memsrc.pos=min(memsrc.pos, memsrc.length);
45
46         return memsrc.pos;
47 }
48
49 int memory_close(void *src)
50 {
51         delete reinterpret_cast<MemorySource *>(src);
52         return 0;
53 }
54
55 long memory_tell(void *src)
56 {
57         MemorySource &memsrc=*reinterpret_cast<MemorySource *>(src);
58         return memsrc.pos;
59 }
60
61 ov_callbacks memory_callbacks=
62 {
63         &memory_read,
64         &memory_seek,
65         &memory_close,
66         &memory_tell
67 };
68
69 } // namespace
70
71 namespace Msp {
72 namespace AL {
73
74 Sound::Sound():
75         data(0),
76         eof_flag(false)
77 {
78         ovfile.datasource=0;
79 }
80
81 Sound::~Sound()
82 {
83         delete[] data;
84         if(ovfile.datasource)
85                 ov_clear(&ovfile);
86 }
87
88 void Sound::open_file(const string &fn)
89 {
90         if(ovfile.datasource)
91                 throw InvalidState("Sound has already been opened");
92         if(ov_fopen(const_cast<char *>(fn.c_str()), &ovfile)<0)
93                 throw Exception("Could not open ogg vorbis file "+fn);
94
95         open_common();
96 }
97
98 void Sound::open_memory(const void *d, unsigned len)
99 {
100         if(ovfile.datasource)
101                 throw InvalidState("Sound has already been opened");
102
103         MemorySource *src=new MemorySource(d, len);
104         if(ov_open_callbacks(src, &ovfile, 0, 0, memory_callbacks)<0)
105         {
106                 delete src;
107                 throw Exception("Could not open ogg vorbis memory block");
108         }
109
110         open_common();
111 }
112
113 void Sound::load_data()
114 {
115         if(data)
116                 throw InvalidState("Data has already been loaded");
117
118         size=ov_pcm_total(&ovfile, 0)*4;
119         char *dptr=new char[size];
120         unsigned pos=0;
121         while(unsigned len=read(dptr+pos, size-pos))
122                 pos+=len;
123         data=dptr;
124         size=pos;
125         read_pos=0;
126 }
127
128 void Sound::load_file(const std::string &fn)
129 {
130         open_file(fn);
131         load_data();
132         close();
133 }
134
135 void Sound::load_memory(const void *d, unsigned len)
136 {
137         open_memory(d, len);
138         load_data();
139         close();
140 }
141
142 void Sound::close()
143 {
144         if(ovfile.datasource)
145                 ov_clear(&ovfile);
146 }
147
148 void Sound::rewind()
149 {
150         if(data)
151                 read_pos=0;
152         else
153                 ov_pcm_seek(&ovfile, 0);
154 }
155
156 unsigned Sound::read(char *buf, unsigned len)
157 {
158         if(data)
159         {
160                 len=min(len, size-read_pos);
161                 memcpy(buf, data+read_pos, len);
162                 read_pos+=len;
163                 return len;
164         }
165         else if(ovfile.datasource)
166         {
167                 int section=0;
168                 int res=ov_read(&ovfile, buf, len, 0, 2, 1, &section);
169                 if(res<0)
170                         throw Exception("Error reading ogg vorbis file");
171                 else if(res==0)
172                         eof_flag=true;
173                 return res;
174         }
175         else
176                 throw InvalidState("No data available");
177 }
178
179 const char *Sound::get_data() const
180 {
181         if(!data)
182                 throw InvalidState("Data has not been loaded");
183         return data;
184 }
185
186 void Sound::open_common()
187 {
188         delete data;
189         data=0;
190
191         vorbis_info *info=ov_info(&ovfile, -1);
192         freq=info->rate;
193         switch(info->channels)
194         {
195         case 1: format=MONO16; break;
196         case 2: format=STEREO16; break;
197         default: throw Exception("Unsupported number of channels");
198         }
199 }
200
201 } // namespace AL
202 } // namespace Msp