2 * ALURE OpenAL utility library
3 * Copyright (C) 2009 by Chris Robinson.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 /* Title: Streaming */
31 static alureStream
*InitStream(alureStream
*instream
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
33 std::auto_ptr
<alureStream
> stream(instream
);
35 ALuint freq
, blockAlign
;
37 if(!stream
->GetFormat(&format
, &freq
, &blockAlign
))
39 SetError("Could not get stream format");
45 SetError("No valid format");
50 SetError("Invalid block size");
55 SetError("Invalid sample rate");
59 chunkLength
-= chunkLength
%blockAlign
;
62 SetError("Chunk length too small");
66 stream
->chunkLen
= chunkLength
;
67 stream
->dataChunk
= new ALubyte
[stream
->chunkLen
];
69 alGenBuffers(numBufs
, bufs
);
70 if(alGetError() != AL_NO_ERROR
)
72 SetError("Buffer creation failed");
76 ALsizei filled
= alureBufferDataFromStream(stream
.get(), numBufs
, bufs
);
79 alDeleteBuffers(numBufs
, bufs
);
82 SetError("Buffering error");
86 while(filled
< numBufs
)
88 alBufferData(bufs
[filled
], format
, stream
->dataChunk
, 0, freq
);
89 if(alGetError() != AL_NO_ERROR
)
91 SetError("Buffer load failed");
97 return stream
.release();
103 /* Function: alureCreateStreamFromFile
105 * Opens a file and sets it up for streaming. The given chunkLength is the
106 * number of bytes each buffer will fill with. ALURE will optionally generate
107 * the specified number of buffer objects, fill them with the beginning of the
108 * data, then place the new IDs into the provided storage, before returning.
109 * Requires an active context.
112 * An opaque handle used to control the opened stream, or NULL on error.
115 * <alureCreateStreamFromMemory>, <alureCreateStreamFromStaticMemory>,
116 * <alureCreateStreamFromCallback>
118 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromFile(const ALchar
*fname
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
120 if(alGetError() != AL_NO_ERROR
)
122 SetError("Existing OpenAL error");
128 SetError("Invalid chunk length");
134 SetError("Invalid buffer count");
138 alureStream
*stream
= create_stream(fname
);
139 if(!stream
->IsValid())
145 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
148 /* Function: alureCreateStreamFromMemory
150 * Opens a file image from memory and sets it up for streaming, similar to
151 * alureCreateStreamFromFile. The given data buffer can be safely deleted after
152 * calling this function. Requires an active context.
155 * An opaque handle used to control the opened stream, or NULL on error.
158 * <alureCreateStreamFromFile>, <alureCreateStreamFromStaticMemory>,
159 * <alureCreateStreamFromCallback>
161 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromMemory(const ALubyte
*fdata
, ALuint length
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
163 if(alGetError() != AL_NO_ERROR
)
165 SetError("Existing OpenAL error");
171 SetError("Invalid chunk length");
177 SetError("Invalid buffer count");
183 SetError("Invalid data length");
187 ALubyte
*streamData
= new ALubyte
[length
];
188 memcpy(streamData
, fdata
, length
);
191 memData
.Data
= streamData
;
192 memData
.Length
= length
;
195 alureStream
*stream
= create_stream(memData
);
196 stream
->data
= streamData
;
197 if(!stream
->IsValid())
203 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
206 /* Function: alureCreateStreamFromStaticMemory
208 * Identical to alureCreateStreamFromMemory, except the given memory is used
209 * directly and not duplicated. As a consequence, the data buffer must remain
210 * valid while the stream is alive. Requires an active context.
213 * An opaque handle used to control the opened stream, or NULL on error.
216 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
217 * <alureCreateStreamFromCallback>
219 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromStaticMemory(const ALubyte
*fdata
, ALuint length
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
221 if(alGetError() != AL_NO_ERROR
)
223 SetError("Existing OpenAL error");
229 SetError("Invalid chunk length");
235 SetError("Invalid buffer count");
241 SetError("Invalid data length");
246 memData
.Data
= fdata
;
247 memData
.Length
= length
;
250 alureStream
*stream
= create_stream(memData
);
251 if(!stream
->IsValid())
257 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
260 /* Function: alureCreateStreamFromCallback
262 * Creates a stream using the specified callback to retrieve data. Requires an
266 * callback - This is called when more data is needed from the stream. Up to
267 * the specified number of bytes should be written to the data
268 * pointer, and the number of bytes actually written should be
269 * returned. The number of bytes written must be block aligned for
270 * the format (eg. a multiple of 4 for AL_FORMAT_STEREO16), or an
271 * OpenAL error may occur during buffering.
272 * userdata - A handle passed through to the callback.
273 * format - The format of the data the callback will be giving. The format must
274 * be valid for the context.
275 * samplerate - The sample rate (frequency) of the stream
278 * An opaque handle used to control the opened stream, or NULL on error.
281 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
282 * <alureCreateStreamFromStaticMemory>
284 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromCallback(
285 ALuint (*callback
)(void *userdata
, ALubyte
*data
, ALuint bytes
),
286 void *userdata
, ALenum format
, ALuint samplerate
,
287 ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
289 if(alGetError() != AL_NO_ERROR
)
291 SetError("Existing OpenAL error");
297 SetError("Invalid callback");
303 SetError("Invalid chunk length");
309 SetError("Invalid buffer count");
314 newcb
.open_file
= NULL
;
315 newcb
.open_mem
= NULL
;
316 newcb
.get_fmt
= NULL
;
317 newcb
.decode
= callback
;
321 customStream
*stream
= new customStream(userdata
, format
, samplerate
, newcb
);
322 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
325 /* Function: alureGetStreamFormat
327 * Retrieves the format, frequency, and block-alignment used for the given
328 * stream. If a parameter is NULL, that value will not be returned.
333 ALURE_API ALboolean ALURE_APIENTRY
alureGetStreamFormat(alureStream
*stream
,
334 ALenum
*format
, ALuint
*frequency
, ALuint
*blockAlign
)
337 ALuint _rate
, _balign
;
339 if(!alureStream::Verify(stream
))
341 SetError("Invalid stream pointer");
345 if(!format
) format
= &_fmt
;
346 if(!frequency
) frequency
= &_rate
;
347 if(!blockAlign
) blockAlign
= &_balign
;
349 if(!stream
->GetFormat(format
, frequency
, blockAlign
))
351 SetError("Could not get stream format");
358 /* Function: alureBufferDataFromStream
360 * Buffers the given buffer objects with the next chunks of data from the
361 * stream. The given buffer objects do not need to be ones given by the
362 * alureCreateStreamFrom* functions. Requires an active context.
365 * The number of buffers filled with new data, or -1 on error. If the value
366 * returned is less than the number requested, the end of the stream has been
369 ALURE_API ALsizei ALURE_APIENTRY
alureBufferDataFromStream(alureStream
*stream
, ALsizei numBufs
, ALuint
*bufs
)
371 if(alGetError() != AL_NO_ERROR
)
373 SetError("Existing OpenAL error");
377 if(!alureStream::Verify(stream
))
379 SetError("Invalid stream pointer");
385 SetError("Invalid buffer count");
390 ALuint freq
, blockAlign
;
392 if(!stream
->GetFormat(&format
, &freq
, &blockAlign
))
394 SetError("Could not get stream format");
399 for(filled
= 0;filled
< numBufs
;filled
++)
401 ALuint got
= stream
->GetData(stream
->dataChunk
, stream
->chunkLen
);
402 got
-= got
%blockAlign
;
405 alBufferData(bufs
[filled
], format
, stream
->dataChunk
, got
, freq
);
406 if(alGetError() != AL_NO_ERROR
)
408 SetError("Buffer load failed");
416 /* Function: alureRewindStream
418 * Rewinds the stream so that the next alureBufferDataFromStream call will
419 * restart from the beginning of the audio file.
425 * <alureSetStreamOrder>
427 ALURE_API ALboolean ALURE_APIENTRY
alureRewindStream(alureStream
*stream
)
429 if(!alureStream::Verify(stream
))
431 SetError("Invalid stream pointer");
435 return stream
->Rewind();
438 /* Function: alureSetStreamOrder
440 * Skips the module decoder to the specified order, so following buffering
441 * calls will decode from the specified order. For non-module formats, setting
442 * order 0 is identical to rewinding the stream (other orders will fail).
448 * <alureRewindStream>
450 ALURE_API ALboolean ALURE_APIENTRY
alureSetStreamOrder(alureStream
*stream
, ALuint order
)
452 if(!alureStream::Verify(stream
))
454 SetError("Invalid stream pointer");
458 return stream
->SetOrder(order
);
461 /* Function: alureDestroyStream
463 * Closes an opened stream. For convenience, it will also delete the given
464 * buffer objects. The given buffer objects do not need to be ones given by the
465 * alureCreateStreamFrom* functions. Requires an active context.
470 ALURE_API ALboolean ALURE_APIENTRY
alureDestroyStream(alureStream
*stream
, ALsizei numBufs
, ALuint
*bufs
)
472 if(alGetError() != AL_NO_ERROR
)
474 SetError("Existing OpenAL error");
480 SetError("Invalid buffer count");
484 if(stream
&& !alureStream::Verify(stream
))
486 SetError("Invalid stream pointer");
490 alDeleteBuffers(numBufs
, bufs
);
491 if(alGetError() != AL_NO_ERROR
)
493 SetError("Buffer deletion failed");
500 std::istream
*f
= stream
->fstream
;
501 delete stream
; delete f
;