1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3
4 This file is part of Aquaria.
5
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "OggStream.h"
22 #include "SoundManager.h"
23 #include "Base.h"
24
25 #define BUFFER_SIZE (4096 * 4)
26
OggStream()27 OggStream::OggStream()
28 {
29 loop=false;
30 source = 0;
31 buffers[0] = 0;
32 buffers[1] = 0;
33 }
34
open(std::string path)35 void OggStream::open(std::string path)
36 {
37 int result;
38
39 oggFile = fopen(core->adjustFilenameCase(path.c_str()), "rb");
40
41 if (!oggFile)
42 {
43 sound->error("Could not open Ogg file.");
44 return;
45 }
46
47 result = ov_open(oggFile, &oggStream, NULL, 0);
48
49 if (result < 0)
50 {
51 fclose(oggFile);
52
53 sound->error(std::string("Could not open Ogg stream. ") + errorString(result));
54 return;
55 }
56
57 vorbisInfo = ov_info(&oggStream, -1);
58 vorbisComment = ov_comment(&oggStream, -1);
59
60 if(vorbisInfo->channels == 1)
61 format = AL_FORMAT_MONO16;
62 else
63 format = AL_FORMAT_STEREO16;
64
65
66 alGenBuffers(2, buffers);
67 check();
68 alGenSources(1, &source);
69 check();
70
71 alSource3f(source, AL_POSITION, 0.0, 0.0, 0.0);
72 alSource3f(source, AL_VELOCITY, 0.0, 0.0, 0.0);
73 alSource3f(source, AL_DIRECTION, 0.0, 0.0, 0.0);
74 alSourcef (source, AL_ROLLOFF_FACTOR, 0.0 );
75 alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE );
76 }
77
release()78 void OggStream::release()
79 {
80 BBGE_PROF(OggStream::release);
81 if (source)
82 {
83 alSourceStop(source);
84 empty();
85 alDeleteSources(1, &source);
86 check();
87 }
88 if (buffers && (buffers[0] || buffers[1]))
89 {
90 alDeleteBuffers(1, buffers);
91 check();
92 }
93
94 ov_clear(&oggStream);
95
96 source = 0;
97 buffers[0] = 0;
98 buffers[1] = 0;
99 }
100
display()101 void OggStream::display()
102 {
103 std::cout
104 << "version " << vorbisInfo->version << "\n"
105 << "channels " << vorbisInfo->channels << "\n"
106 << "rate (hz) " << vorbisInfo->rate << "\n"
107 << "bitrate upper " << vorbisInfo->bitrate_upper << "\n"
108 << "bitrate nominal " << vorbisInfo->bitrate_nominal << "\n"
109 << "bitrate lower " << vorbisInfo->bitrate_lower << "\n"
110 << "bitrate window " << vorbisInfo->bitrate_window << "\n"
111 << "\n"
112 << "vendor " << vorbisComment->vendor << "\n";
113
114 for(int i = 0; i < vorbisComment->comments; i++)
115 std::cout << " " << vorbisComment->user_comments[i] << "\n";
116
117 std::cout << std::endl;
118 }
119
play(bool l)120 bool OggStream::play(bool l)
121 {
122 BBGE_PROF(OggStream::play);
123 if(isPlaying())
124 return true;
125
126 if(!stream(buffers[0]))
127 return false;
128
129 if(!stream(buffers[1]))
130 return false;
131
132 loop=l;
133
134 alSourceQueueBuffers(source, 2, buffers);
135 alSourcePlay(source);
136
137 return true;
138 }
139
isPlaying()140 bool OggStream::isPlaying()
141 {
142 ALenum state;
143
144 if (source)
145 {
146 alGetSourcei(source, AL_SOURCE_STATE, &state);
147
148 return (state == AL_PLAYING);
149 }
150
151 return false;
152 }
153
setGain(float gain)154 void OggStream::setGain(float gain)
155 {
156 if (!source) return;
157
158 alSourcef(source, AL_GAIN, gain);
159 ALenum error=alGetError();
160
161 if(error!=AL_FALSE)
162 {
163 switch(error)
164 {
165 case(AL_INVALID_VALUE):
166 sound->error("Invalid value for gain");
167 break;
168 default:
169 sound->error("Error trying to set gain!");
170 break;
171 }
172 }
173 }
174
update()175 bool OggStream::update()
176 {
177 if (!source) return false;
178
179 int processed;
180 bool active = true;
181
182 if (!isPlaying())
183 {
184 alSourcePlay(source);
185 }
186
187 alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
188
189 while(processed--)
190 {
191 ALuint buffer;
192
193 alSourceUnqueueBuffers(source, 1, &buffer);
194 check();
195
196 active = stream(buffer);
197
198 alSourceQueueBuffers(source, 1, &buffer);
199 check();
200 }
201
202 if (!active)
203 {
204 release();
205 }
206
207 return active;
208 }
209
stream(ALuint buffer)210 bool OggStream::stream(ALuint buffer)
211 {
212 char pcm[BUFFER_SIZE];
213 int size = 0;
214 int section;
215 int result;
216
217 while(size < BUFFER_SIZE)
218 {
219 result = ov_read(&oggStream, pcm + size, BUFFER_SIZE - size, 0, 2, 1, §ion);
220
221 if(result > 0)
222 size += result;
223 else
224 { if(result < 0) {} else break; }
225 }
226
227 if(size == 0)
228 {
229 if (loop)
230 {
231 std::cout << "looping\n";
232 int r = ov_pcm_seek(&oggStream, 0);
233 if (r != 0)
234 {
235 std::cout << "error\n";
236 }
237
238 while(size < BUFFER_SIZE)
239 {
240 result = ov_read(&oggStream, pcm + size, BUFFER_SIZE - size, 0, 2, 1, §ion);
241
242 if(result > 0)
243 size += result;
244 else
245 { if(result < 0) {} else break; }
246 }
247 }
248 else
249 {
250 return false;
251 }
252 }
253
254 alBufferData(buffer, format, pcm, size, vorbisInfo->rate);
255 //check();
256
257 return true;
258 }
259
empty()260 void OggStream::empty()
261 {
262 if (!source) return;
263 int queued;
264
265 alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
266
267 while(queued--)
268 {
269 ALuint buffer;
270
271 alSourceUnqueueBuffers(source, 1, &buffer);
272 check();
273 }
274 }
275
check()276 void OggStream::check()
277 {
278 int error = alGetError();
279
280 if(error != AL_NO_ERROR)
281 sound->error(std::string("OpenAL error was raised."));
282 }
283
errorString(int code)284 std::string OggStream::errorString(int code)
285 {
286 switch(code)
287 {
288 case OV_EREAD:
289 return std::string("Read from media.");
290 case OV_ENOTVORBIS:
291 return std::string("Not Vorbis data.");
292 case OV_EVERSION:
293 return std::string("Vorbis version mismatch.");
294 case OV_EBADHEADER:
295 return std::string("Invalid Vorbis header.");
296 case OV_EFAULT:
297 return std::string("Internal logic fault (bug or heap/stack corruption.");
298 default:
299 return std::string("Unknown Ogg error.");
300 }
301 }
302
303