Fix the FluidSynth decoder
[alure.git] / src / codec_flac.cpp
blobf4969f2388f60e4bf6fa7c6b77cd75fd77fc6018
1 /*
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
21 * IN THE SOFTWARE.
24 #include "config.h"
26 #include "main.h"
28 #include <string.h>
29 #include <assert.h>
31 #include <istream>
33 #include <FLAC/all.h>
36 #ifdef _WIN32
37 #define FLAC_LIB "libFLAC.dll"
38 #elif defined(__APPLE__)
39 #define FLAC_LIB "libFLAC.8.dylib"
40 #else
41 #define FLAC_LIB "libFLAC.so.8"
42 #endif
44 static void *flac_handle;
45 #define MAKE_FUNC(x) static typeof(x)* p##x
46 MAKE_FUNC(FLAC__stream_decoder_get_state);
47 MAKE_FUNC(FLAC__stream_decoder_finish);
48 MAKE_FUNC(FLAC__stream_decoder_new);
49 MAKE_FUNC(FLAC__stream_decoder_seek_absolute);
50 MAKE_FUNC(FLAC__stream_decoder_delete);
51 MAKE_FUNC(FLAC__stream_decoder_process_single);
52 MAKE_FUNC(FLAC__stream_decoder_init_stream);
53 #undef MAKE_FUNC
56 struct flacStream : public alureStream {
57 private:
58 FLAC__StreamDecoder *flacFile;
59 ALenum format;
60 ALuint samplerate;
61 ALuint blockAlign;
62 ALboolean useFloat;
64 std::vector<ALubyte> initialData;
66 ALubyte *outBytes;
67 ALuint outLen;
68 ALuint outTotal;
70 public:
71 static void Init()
73 flac_handle = OpenLib(FLAC_LIB);
74 if(!flac_handle) return;
76 LOAD_FUNC(flac_handle, FLAC__stream_decoder_get_state);
77 LOAD_FUNC(flac_handle, FLAC__stream_decoder_finish);
78 LOAD_FUNC(flac_handle, FLAC__stream_decoder_new);
79 LOAD_FUNC(flac_handle, FLAC__stream_decoder_seek_absolute);
80 LOAD_FUNC(flac_handle, FLAC__stream_decoder_delete);
81 LOAD_FUNC(flac_handle, FLAC__stream_decoder_process_single);
82 LOAD_FUNC(flac_handle, FLAC__stream_decoder_init_stream);
84 static void Deinit()
86 if(flac_handle)
87 CloseLib(flac_handle);
88 flac_handle = NULL;
91 virtual bool IsValid()
92 { return flacFile != NULL; }
94 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
96 *fmt = format;
97 *frequency = samplerate;
98 *blockalign = blockAlign;
99 return true;
102 virtual ALuint GetData(ALubyte *data, ALuint bytes)
104 outBytes = data;
105 outTotal = 0;
106 outLen = bytes;
108 if(initialData.size() > 0)
110 size_t rem = std::min(initialData.size(), (size_t)bytes);
111 memcpy(data, &initialData[0], rem);
112 outTotal += rem;
113 initialData.erase(initialData.begin(), initialData.begin()+rem);
116 while(outTotal < bytes)
118 if(pFLAC__stream_decoder_process_single(flacFile) == false ||
119 pFLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
120 break;
123 return outTotal;
126 virtual bool Rewind()
128 if(pFLAC__stream_decoder_seek_absolute(flacFile, 0) != false)
130 initialData.clear();
131 return true;
134 SetError("Seek failed");
135 return false;
138 flacStream(std::istream *_fstream)
139 : alureStream(_fstream), flacFile(NULL), format(AL_NONE), samplerate(0),
140 blockAlign(0), useFloat(AL_FALSE)
142 if(!flac_handle) return;
144 flacFile = pFLAC__stream_decoder_new();
145 if(flacFile)
147 if(pFLAC__stream_decoder_init_stream(flacFile, ReadCallback, SeekCallback, TellCallback, LengthCallback, EofCallback, WriteCallback, MetadataCallback, ErrorCallback, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK)
149 if(InitFlac())
151 // all ok
152 return;
155 pFLAC__stream_decoder_finish(flacFile);
157 pFLAC__stream_decoder_delete(flacFile);
158 flacFile = NULL;
162 virtual ~flacStream()
164 if(flacFile)
166 pFLAC__stream_decoder_finish(flacFile);
167 pFLAC__stream_decoder_delete(flacFile);
168 flacFile = NULL;
172 private:
173 bool InitFlac()
175 // We need to decode some data to be able to get the channel count, bit
176 // depth, and sample rate. It also ensures the file has FLAC data, as
177 // the FLAC__stream_decoder_init_* functions can succeed on non-FLAC
178 // Ogg files.
179 outLen = 0;
180 outTotal = 0;
181 while(initialData.size() == 0)
183 if(pFLAC__stream_decoder_process_single(flacFile) == false ||
184 pFLAC__stream_decoder_get_state(flacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
185 break;
188 if(initialData.size() > 0)
189 return true;
190 return false;
193 static FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder*, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
195 flacStream *self = static_cast<flacStream*>(client_data);
196 ALubyte *data = self->outBytes + self->outTotal;
197 ALuint i = 0;
199 if(self->format == AL_NONE)
201 ALuint bps = frame->header.bits_per_sample;
202 if(bps == 24 || bps == 32)
204 self->format = GetSampleFormat(frame->header.channels, 32, true);
205 if(self->format != AL_NONE)
207 self->useFloat = AL_TRUE;
208 bps = 32;
210 else bps = 16;
212 if(self->format == AL_NONE)
213 self->format = GetSampleFormat(frame->header.channels, bps, false);
214 self->blockAlign = frame->header.channels * bps/8;
215 self->samplerate = frame->header.sample_rate;
218 const ALboolean useFloat = self->useFloat;
219 while(self->outTotal < self->outLen && i < frame->header.blocksize)
221 for(ALuint c = 0;c < frame->header.channels;c++)
223 if(frame->header.bits_per_sample == 8)
224 ((ALubyte*)data)[c] = buffer[c][i]+128;
225 else if(frame->header.bits_per_sample == 16)
226 ((ALshort*)data)[c] = buffer[c][i];
227 else if(frame->header.bits_per_sample == 24)
229 if(useFloat)
230 ((ALfloat*)data)[c] = buffer[c][i] * (1.0/8388607.0);
231 else
232 ((ALshort*)data)[c] = buffer[c][i]>>8;
234 else if(frame->header.bits_per_sample == 32)
236 if(useFloat)
237 ((ALfloat*)data)[c] = buffer[c][i] * (1.0/2147483647.0);
238 else
239 ((ALshort*)data)[c] = buffer[c][i]>>16;
242 self->outTotal += self->blockAlign;
243 data += self->blockAlign;
244 i++;
247 if(i < frame->header.blocksize)
249 ALuint blocklen = (frame->header.blocksize-i) *
250 self->blockAlign;
251 ALuint start = self->initialData.size();
253 self->initialData.resize(start+blocklen);
254 data = &self->initialData[start];
256 do {
257 for(ALuint c = 0;c < frame->header.channels;c++)
259 if(frame->header.bits_per_sample == 8)
260 ((ALubyte*)data)[c] = buffer[c][i]+128;
261 else if(frame->header.bits_per_sample == 16)
262 ((ALshort*)data)[c] = buffer[c][i];
263 else if(frame->header.bits_per_sample == 24)
265 if(useFloat)
266 ((ALfloat*)data)[c] = buffer[c][i] * (1.0/8388607.0);
267 else
268 ((ALshort*)data)[c] = buffer[c][i]>>8;
270 else if(frame->header.bits_per_sample == 32)
272 if(useFloat)
273 ((ALfloat*)data)[c] = buffer[c][i] * (1.0/2147483647.0);
274 else
275 ((ALshort*)data)[c] = buffer[c][i]>>16;
278 data += self->blockAlign;
279 i++;
280 } while(i < frame->header.blocksize);
283 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
285 static void MetadataCallback(const FLAC__StreamDecoder*,const FLAC__StreamMetadata*,void*)
288 static void ErrorCallback(const FLAC__StreamDecoder*,FLAC__StreamDecoderErrorStatus,void*)
292 static FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t *bytes, void *client_data)
294 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
295 stream->clear();
297 if(*bytes <= 0)
298 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
300 stream->read(reinterpret_cast<char*>(buffer), *bytes);
301 *bytes = stream->gcount();
302 if(*bytes == 0 && stream->eof())
303 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
305 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
307 static FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder*, FLAC__uint64 absolute_byte_offset, void *client_data)
309 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
310 stream->clear();
312 if(!stream->seekg(absolute_byte_offset))
313 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
314 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
316 static FLAC__StreamDecoderTellStatus TellCallback(const FLAC__StreamDecoder*, FLAC__uint64 *absolute_byte_offset, void *client_data)
318 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
319 stream->clear();
321 *absolute_byte_offset = stream->tellg();
322 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
324 static FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder*, FLAC__uint64 *stream_length, void *client_data)
326 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
327 stream->clear();
329 std::streampos pos = stream->tellg();
330 if(stream->seekg(0, std::ios_base::end))
332 *stream_length = stream->tellg();
333 stream->seekg(pos);
336 if(!stream->good())
337 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
338 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
340 static FLAC__bool EofCallback(const FLAC__StreamDecoder*, void *client_data)
342 std::istream *stream = static_cast<flacStream*>(client_data)->fstream;
343 return (stream->eof()) ? true : false;
346 // Priority = 1, so it's preferred over libsndfile
347 static DecoderDecl<flacStream,1> flacStream_decoder;