2 * ALURE OpenAL utility library
3 * Copyright (c) 2009-2010 by Chris Robinson.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
37 static void *flac_handle;
38 #define MAKE_FUNC(x) static typeof(x)* p##x
39 MAKE_FUNC(FLAC__stream_decoder_get_state);
40 MAKE_FUNC(FLAC__stream_decoder_finish);
41 MAKE_FUNC(FLAC__stream_decoder_new);
42 MAKE_FUNC(FLAC__stream_decoder_seek_absolute);
43 MAKE_FUNC(FLAC__stream_decoder_delete);
44 MAKE_FUNC(FLAC__stream_decoder_get_total_samples);
45 MAKE_FUNC(FLAC__stream_decoder_process_single);
46 MAKE_FUNC(FLAC__stream_decoder_init_stream);
49 #define FLAC__stream_decoder_get_state pFLAC__stream_decoder_get_state
50 #define FLAC__stream_decoder_finish pFLAC__stream_decoder_finish
51 #define FLAC__stream_decoder_new pFLAC__stream_decoder_new
52 #define FLAC__stream_decoder_seek_absolute pFLAC__stream_decoder_seek_absolute
53 #define FLAC__stream_decoder_delete pFLAC__stream_decoder_delete
54 #define FLAC__stream_decoder_get_total_samples pFLAC__stream_decoder_get_total_samples
55 #define FLAC__stream_decoder_process_single pFLAC__stream_decoder_process_single
56 #define FLAC__stream_decoder_init_stream pFLAC__stream_decoder_init_stream
62 struct flacStream : public alureStream {
64 FLAC__StreamDecoder *flacFile;
70 std::vector<ALubyte> initialData;
81 #define FLAC_LIB "libFLAC.dll"
82 #elif defined(__APPLE__)
83 #define FLAC_LIB "libFLAC.8.dylib"
85 #define FLAC_LIB "libFLAC.so.8"
88 flac_handle = OpenLib(FLAC_LIB);
89 if(!flac_handle) return;
91 LOAD_FUNC(flac_handle, FLAC__stream_decoder_get_state);
92 LOAD_FUNC(flac_handle, FLAC__stream_decoder_finish);
93 LOAD_FUNC(flac_handle, FLAC__stream_decoder_new);
94 LOAD_FUNC(flac_handle, FLAC__stream_decoder_seek_absolute);
95 LOAD_FUNC(flac_handle, FLAC__stream_decoder_delete);
96 LOAD_FUNC(flac_handle, FLAC__stream_decoder_get_total_samples);
97 LOAD_FUNC(flac_handle, FLAC__stream_decoder_process_single);
98 LOAD_FUNC(flac_handle, FLAC__stream_decoder_init_stream);
103 CloseLib(flac_handle);
107 static void Init() { }
108 static void Deinit() { }
111 virtual bool IsValid()
112 { return flacFile != NULL; }
114 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
117 *frequency = samplerate;
118 *blockalign = blockAlign;
122 virtual ALuint GetData(ALubyte *data, ALuint bytes)
128 if(initialData.size() > 0)
130 size_t rem = std::min(initialData.size(), (size_t)bytes);
131 memcpy(data, &initialData[0], rem);
133 initialData.erase(initialData.begin(), initialData.begin()+rem);
136 while(outLen < outMax)
138 if(FLAC__stream_decoder_process_single(flacFile) == false ||
139 FLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
146 virtual bool Rewind()
148 if(FLAC__stream_decoder_seek_absolute(flacFile, 0) != false)
154 SetError("Seek failed");
158 virtual alureInt64 GetLength()
160 return FLAC__stream_decoder_get_total_samples(flacFile);
163 flacStream(std::istream *_fstream)
164 : alureStream(_fstream), flacFile(NULL), format(AL_NONE), samplerate(0),
165 blockAlign(0), useFloat(AL_FALSE)
167 if(!flac_handle) return;
169 flacFile = FLAC__stream_decoder_new();
172 if(FLAC__stream_decoder_init_stream(flacFile, ReadCallback, SeekCallback, TellCallback, LengthCallback, EofCallback, WriteCallback, MetadataCallback, ErrorCallback, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK)
180 FLAC__stream_decoder_finish(flacFile);
182 FLAC__stream_decoder_delete(flacFile);
187 virtual ~flacStream()
191 FLAC__stream_decoder_finish(flacFile);
192 FLAC__stream_decoder_delete(flacFile);
200 // We need to decode some data to be able to get the channel count, bit
201 // depth, and sample rate. It also ensures the file has FLAC data, as
202 // the FLAC__stream_decoder_init_* functions can succeed on non-FLAC
207 while(initialData.size() == 0)
209 if(FLAC__stream_decoder_process_single(flacFile) == false ||
210 FLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
214 if(initialData.size() > 0)
220 template<ALuint shift, ALint offset, typename T>
221 static void CopySamples(T *data, const FLAC__int32 *const buffer[], ALuint off, ALuint todo, ALuint channels)
223 for(ALuint i = 0;i < todo;i++)
225 for(ALuint c = 0;c < channels;c++)
226 *(data++) = (buffer[c][off+i]>>shift) + offset;
230 template<ALuint bits>
231 static void CopySamplesFloat(ALfloat *data, const FLAC__int32 *const buffer[], ALuint off, ALuint todo, ALuint channels)
233 for(ALuint i = 0;i < todo;i++)
235 for(ALuint c = 0;c < channels;c++)
236 *(data++) = buffer[c][off+i] * (1./((1u<<(bits-1))-1));
240 static FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder*, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
242 flacStream *self = static_cast<flacStream*>(client_data);
244 if(self->format == AL_NONE)
246 ALuint bps = frame->header.bits_per_sample;
247 if(bps == 24 || bps == 32)
249 self->format = GetSampleFormat(frame->header.channels, 32, true);
250 if(self->format != AL_NONE)
252 self->useFloat = AL_TRUE;
257 if(self->format == AL_NONE)
258 self->format = GetSampleFormat(frame->header.channels, bps, false);
259 self->blockAlign = frame->header.channels * bps/8;
260 self->samplerate = frame->header.sample_rate;
263 ALubyte *data = self->outBytes + self->outLen;
264 ALuint todo = std::min<ALuint>((self->outMax-self->outLen) / self->blockAlign,
265 frame->header.blocksize);
266 if(frame->header.bits_per_sample == 8)
267 CopySamples<0,128>((ALubyte*)data, buffer, 0,
268 todo, frame->header.channels);
269 else if(frame->header.bits_per_sample == 16)
270 CopySamples<0,0>((ALshort*)data, buffer, 0,
271 todo, frame->header.channels);
272 else if(frame->header.bits_per_sample == 24)
275 CopySamplesFloat<24>((ALfloat*)data, buffer, 0,
276 todo, frame->header.channels);
278 CopySamples<8,0>((ALshort*)data, buffer, 0,
279 todo, frame->header.channels);
281 else if(frame->header.bits_per_sample == 32)
284 CopySamplesFloat<32>((ALfloat*)data, buffer, 0,
285 todo, frame->header.channels);
287 CopySamples<16,0>((ALshort*)data, buffer, 0,
288 todo, frame->header.channels);
290 self->outLen += self->blockAlign * todo;
292 if(todo < frame->header.blocksize)
294 ALuint offset = todo;
295 todo = frame->header.blocksize - todo;
297 ALuint blocklen = todo * self->blockAlign;
298 ALuint start = self->initialData.size();
300 self->initialData.resize(start+blocklen);
301 data = &self->initialData[start];
303 if(frame->header.bits_per_sample == 8)
304 CopySamples<0,128>((ALubyte*)data, buffer, offset,
305 todo, frame->header.channels);
306 else if(frame->header.bits_per_sample == 16)
307 CopySamples<0,0>((ALshort*)data, buffer, offset,
308 todo, frame->header.channels);
309 else if(frame->header.bits_per_sample == 24)
312 CopySamplesFloat<24>((ALfloat*)data, buffer, offset,
313 todo, frame->header.channels);
315 CopySamples<8,0>((ALshort*)data, buffer, offset,
316 todo, frame->header.channels);
318 else if(frame->header.bits_per_sample == 32)
321 CopySamplesFloat<32>((ALfloat*)data, buffer, offset,
322 todo, frame->header.channels);
324 CopySamples<16,0>((ALshort*)data, buffer, offset,
325 todo, frame->header.channels);
329 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
331 static void MetadataCallback(const FLAC__StreamDecoder*,const FLAC__StreamMetadata*,void*)
334 static void ErrorCallback(const FLAC__StreamDecoder*,FLAC__StreamDecoderErrorStatus,void*)
338 static FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t *bytes, void *client_data)
340 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
344 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
346 stream->read(reinterpret_cast<char*>(buffer), *bytes);
347 *bytes = stream->gcount();
348 if(*bytes == 0 && stream->eof())
349 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
351 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
353 static FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder*, FLAC__uint64 absolute_byte_offset, void *client_data)
355 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
358 if(!stream->seekg(absolute_byte_offset))
359 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
360 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
362 static FLAC__StreamDecoderTellStatus TellCallback(const FLAC__StreamDecoder*, FLAC__uint64 *absolute_byte_offset, void *client_data)
364 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
367 *absolute_byte_offset = stream->tellg();
368 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
370 static FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder*, FLAC__uint64 *stream_length, void *client_data)
372 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
375 std::streampos pos = stream->tellg();
376 if(stream->seekg(0, std::ios_base::end))
378 *stream_length = stream->tellg();
383 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
384 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
386 static FLAC__bool EofCallback(const FLAC__StreamDecoder*, void *client_data)
388 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
389 return (stream->eof()) ? true : false;
392 // Priority = 1, so it's preferred over libsndfile
393 static DecoderDecl<flacStream,1> flacStream_decoder;
394 Decoder &alure_init_flac(void)
395 { return flacStream_decoder; }