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");
77 for(filled
= 0;filled
< numBufs
;filled
++)
79 ALuint got
= stream
->GetData(stream
->dataChunk
, stream
->chunkLen
);
80 got
-= got
%blockAlign
;
83 alBufferData(bufs
[filled
], format
, stream
->dataChunk
, got
, freq
);
84 if(alGetError() != AL_NO_ERROR
)
86 alDeleteBuffers(numBufs
, bufs
);
89 SetError("Buffering error");
94 while(filled
< numBufs
)
96 alBufferData(bufs
[filled
], format
, stream
->dataChunk
, 0, freq
);
97 if(alGetError() != AL_NO_ERROR
)
99 SetError("Buffer load failed");
105 return stream
.release();
111 /* Function: alureCreateStreamFromFile
113 * Opens a file and sets it up for streaming. The given chunkLength is the
114 * number of bytes each buffer will fill with. ALURE will optionally generate
115 * the specified number of buffer objects, fill them with the beginning of the
116 * data, then place the new IDs into the provided storage, before returning.
117 * Requires an active context.
120 * An opaque handle used to control the opened stream, or NULL on error.
123 * <alureCreateStreamFromMemory>, <alureCreateStreamFromStaticMemory>,
124 * <alureCreateStreamFromCallback>
126 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromFile(const ALchar
*fname
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
128 if(alGetError() != AL_NO_ERROR
)
130 SetError("Existing OpenAL error");
136 SetError("Invalid chunk length");
142 SetError("Invalid buffer count");
146 alureStream
*stream
= create_stream(fname
);
147 if(!stream
->IsValid())
153 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
156 /* Function: alureCreateStreamFromMemory
158 * Opens a file image from memory and sets it up for streaming, similar to
159 * alureCreateStreamFromFile. The given data buffer can be safely deleted after
160 * calling this function. Requires an active context.
163 * An opaque handle used to control the opened stream, or NULL on error.
166 * <alureCreateStreamFromFile>, <alureCreateStreamFromStaticMemory>,
167 * <alureCreateStreamFromCallback>
169 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromMemory(const ALubyte
*fdata
, ALuint length
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
171 if(alGetError() != AL_NO_ERROR
)
173 SetError("Existing OpenAL error");
179 SetError("Invalid chunk length");
185 SetError("Invalid buffer count");
191 SetError("Invalid data length");
195 ALubyte
*streamData
= new ALubyte
[length
];
196 memcpy(streamData
, fdata
, length
);
199 memData
.Data
= streamData
;
200 memData
.Length
= length
;
203 alureStream
*stream
= create_stream(memData
);
204 stream
->data
= streamData
;
205 if(!stream
->IsValid())
211 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
214 /* Function: alureCreateStreamFromStaticMemory
216 * Identical to alureCreateStreamFromMemory, except the given memory is used
217 * directly and not duplicated. As a consequence, the data buffer must remain
218 * valid while the stream is alive. Requires an active context.
221 * An opaque handle used to control the opened stream, or NULL on error.
224 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
225 * <alureCreateStreamFromCallback>
227 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromStaticMemory(const ALubyte
*fdata
, ALuint length
, ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
229 if(alGetError() != AL_NO_ERROR
)
231 SetError("Existing OpenAL error");
237 SetError("Invalid chunk length");
243 SetError("Invalid buffer count");
249 SetError("Invalid data length");
254 memData
.Data
= fdata
;
255 memData
.Length
= length
;
258 alureStream
*stream
= create_stream(memData
);
259 if(!stream
->IsValid())
265 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
268 /* Function: alureCreateStreamFromCallback
270 * Creates a stream using the specified callback to retrieve data. Requires an
274 * callback - This is called when more data is needed from the stream. Up to
275 * the specified number of bytes should be written to the data
276 * pointer, and the number of bytes actually written should be
277 * returned. The number of bytes written must be block aligned for
278 * the format (eg. a multiple of 4 for AL_FORMAT_STEREO16), or an
279 * OpenAL error may occur during buffering.
280 * userdata - A handle passed through to the callback.
281 * format - The format of the data the callback will be giving. The format must
282 * be valid for the context.
283 * samplerate - The sample rate (frequency) of the stream
286 * An opaque handle used to control the opened stream, or NULL on error.
289 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
290 * <alureCreateStreamFromStaticMemory>
292 ALURE_API alureStream
* ALURE_APIENTRY
alureCreateStreamFromCallback(
293 ALuint (*callback
)(void *userdata
, ALubyte
*data
, ALuint bytes
),
294 void *userdata
, ALenum format
, ALuint samplerate
,
295 ALsizei chunkLength
, ALsizei numBufs
, ALuint
*bufs
)
297 if(alGetError() != AL_NO_ERROR
)
299 SetError("Existing OpenAL error");
305 SetError("Invalid callback");
311 SetError("Invalid chunk length");
317 SetError("Invalid buffer count");
322 newcb
.open_file
= NULL
;
323 newcb
.open_mem
= NULL
;
324 newcb
.get_fmt
= NULL
;
325 newcb
.decode
= callback
;
329 alureStream
*stream
= create_stream(userdata
, format
, samplerate
, newcb
);
330 return InitStream(stream
, chunkLength
, numBufs
, bufs
);
333 /* Function: alureGetStreamFormat
335 * Retrieves the format, frequency, and block-alignment used for the given
336 * stream. If a parameter is NULL, that value will not be returned.
341 ALURE_API ALboolean ALURE_APIENTRY
alureGetStreamFormat(alureStream
*stream
,
342 ALenum
*format
, ALuint
*frequency
, ALuint
*blockAlign
)
345 ALuint _rate
, _balign
;
347 if(!alureStream::Verify(stream
))
349 SetError("Invalid stream pointer");
353 if(!format
) format
= &_fmt
;
354 if(!frequency
) frequency
= &_rate
;
355 if(!blockAlign
) blockAlign
= &_balign
;
357 if(!stream
->GetFormat(format
, frequency
, blockAlign
))
359 SetError("Could not get stream format");
366 /* Function: alureBufferDataFromStream
368 * Buffers the given buffer objects with the next chunks of data from the
369 * stream. The given buffer objects do not need to be ones given by the
370 * alureCreateStreamFrom* functions. Requires an active context.
373 * The number of buffers filled with new data, or -1 on error. If the value
374 * returned is less than the number requested, the end of the stream has been
377 ALURE_API ALsizei ALURE_APIENTRY
alureBufferDataFromStream(alureStream
*stream
, ALsizei numBufs
, ALuint
*bufs
)
379 if(alGetError() != AL_NO_ERROR
)
381 SetError("Existing OpenAL error");
385 if(!alureStream::Verify(stream
))
387 SetError("Invalid stream pointer");
393 SetError("Invalid buffer count");
398 ALuint freq
, blockAlign
;
400 if(!stream
->GetFormat(&format
, &freq
, &blockAlign
))
402 SetError("Could not get stream format");
407 for(filled
= 0;filled
< numBufs
;filled
++)
409 ALuint got
= stream
->GetData(stream
->dataChunk
, stream
->chunkLen
);
410 got
-= got
%blockAlign
;
413 alBufferData(bufs
[filled
], format
, stream
->dataChunk
, got
, freq
);
414 if(alGetError() != AL_NO_ERROR
)
416 SetError("Buffer load failed");
424 /* Function: alureRewindStream
426 * Rewinds the stream so that the next alureBufferDataFromStream call will
427 * restart from the beginning of the audio file.
433 * <alureSetStreamOrder>
435 ALURE_API ALboolean ALURE_APIENTRY
alureRewindStream(alureStream
*stream
)
437 if(!alureStream::Verify(stream
))
439 SetError("Invalid stream pointer");
443 return stream
->Rewind();
446 /* Function: alureSetStreamOrder
448 * Skips the module decoder to the specified order, so following buffering
449 * calls will decode from the specified order. For non-module formats, setting
450 * order 0 is identical to rewinding the stream (other orders will fail).
456 * <alureRewindStream>
458 ALURE_API ALboolean ALURE_APIENTRY
alureSetStreamOrder(alureStream
*stream
, ALuint order
)
460 if(!alureStream::Verify(stream
))
462 SetError("Invalid stream pointer");
466 return stream
->SetOrder(order
);
469 /* Function: alureDestroyStream
471 * Closes an opened stream. For convenience, it will also delete the given
472 * buffer objects. The given buffer objects do not need to be ones given by the
473 * alureCreateStreamFrom* functions. Requires an active context.
478 ALURE_API ALboolean ALURE_APIENTRY
alureDestroyStream(alureStream
*stream
, ALsizei numBufs
, ALuint
*bufs
)
480 if(alGetError() != AL_NO_ERROR
)
482 SetError("Existing OpenAL error");
488 SetError("Invalid buffer count");
492 if(stream
&& !alureStream::Verify(stream
))
494 SetError("Invalid stream pointer");
498 alDeleteBuffers(numBufs
, bufs
);
499 if(alGetError() != AL_NO_ERROR
)
501 SetError("Buffer deletion failed");
508 std::istream
*f
= stream
->fstream
;
509 delete stream
; delete f
;