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, &section);
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, &section);
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