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