Rename the mBlockAlign field to mFrameSize
[alure.git] / src / decoders / flac.cpp
blob3b25a75dc494e8e3f2e6f5550a7461e2fc4e50ec
2 #include "flac.hpp"
4 #include <stdexcept>
5 #include <iostream>
6 #include <cstring>
8 #include "FLAC/all.h"
11 namespace alure
14 class FlacDecoder : public Decoder {
15 SharedPtr<std::istream> mFile;
17 FLAC__StreamDecoder *mFlacFile;
18 SampleConfig mSampleConfig;
19 SampleType mSampleType;
20 ALuint mFrequency;
21 ALuint mFrameSize;
22 uint64_t mSamplePos;
24 std::vector<ALubyte> mData;
26 ALubyte *mOutBytes;
27 ALuint mOutMax;
28 ALuint mOutLen;
30 void CopySamples(ALubyte *output, ALuint todo, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], ALuint offset)
32 if(mSampleType == SampleType_UInt8)
34 ALubyte *samples = output;
35 for(ALuint i = 0;i < todo;i++)
37 for(ALuint c = 0;c < frame->header.channels;c++)
38 *(samples++) = ALubyte(buffer[c][offset+i] + 0x80);
41 else
43 int shift = frame->header.bits_per_sample - 16;
44 ALshort *samples = reinterpret_cast<ALshort*>(output);
45 for(ALuint i = 0;i < todo;i++)
47 for(ALuint c = 0;c < frame->header.channels;c++)
48 *(samples++) = buffer[c][offset+i] >> shift;
53 static FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder*, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
55 FlacDecoder *self = static_cast<FlacDecoder*>(client_data);
57 if(self->mFrequency == 0)
59 ALuint bps = frame->header.bits_per_sample;
60 if(bps == 8)
61 self->mSampleType = SampleType_UInt8;
62 else
64 self->mSampleType = SampleType_Int16;
65 bps = 16;
68 if(frame->header.channels == 1)
69 self->mSampleConfig = SampleConfig_Mono;
70 else if(frame->header.channels == 2)
71 self->mSampleConfig = SampleConfig_Stereo;
72 else
73 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
75 self->mFrameSize = frame->header.channels * bps/8;
76 self->mFrequency = frame->header.sample_rate;
79 ALubyte *data = self->mOutBytes + self->mOutLen;
80 ALuint todo = std::min<ALuint>((self->mOutMax-self->mOutLen) / self->mFrameSize,
81 frame->header.blocksize);
82 self->CopySamples(data, todo, frame, buffer, 0);
83 self->mOutLen += self->mFrameSize * todo;
85 if(todo < frame->header.blocksize)
87 ALuint offset = todo;
88 todo = frame->header.blocksize - todo;
90 ALuint blocklen = todo * self->mFrameSize;
91 ALuint start = self->mData.size();
93 self->mData.resize(start+blocklen);
94 data = &self->mData[start];
96 self->CopySamples(data, todo, frame, buffer, offset);
99 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
101 static void MetadataCallback(const FLAC__StreamDecoder*,const FLAC__StreamMetadata*,void*)
104 static void ErrorCallback(const FLAC__StreamDecoder*,FLAC__StreamDecoderErrorStatus,void*)
108 static FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t *bytes, void *client_data)
110 std::istream *stream = static_cast<FlacDecoder*>(client_data)->mFile.get();
111 stream->clear();
113 if(*bytes <= 0)
114 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
116 stream->read(reinterpret_cast<char*>(buffer), *bytes);
117 *bytes = stream->gcount();
118 if(*bytes == 0 && stream->eof())
119 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
121 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
123 static FLAC__StreamDecoderSeekStatus SeekCallback(const FLAC__StreamDecoder*, FLAC__uint64 absolute_byte_offset, void *client_data)
125 std::istream *stream = static_cast<FlacDecoder*>(client_data)->mFile.get();
126 stream->clear();
128 if(!stream->seekg(absolute_byte_offset))
129 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
130 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
132 static FLAC__StreamDecoderTellStatus TellCallback(const FLAC__StreamDecoder*, FLAC__uint64 *absolute_byte_offset, void *client_data)
134 std::istream *stream = static_cast<FlacDecoder*>(client_data)->mFile.get();
135 stream->clear();
137 *absolute_byte_offset = stream->tellg();
138 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
140 static FLAC__StreamDecoderLengthStatus LengthCallback(const FLAC__StreamDecoder*, FLAC__uint64 *stream_length, void *client_data)
142 std::istream *stream = static_cast<FlacDecoder*>(client_data)->mFile.get();
143 stream->clear();
145 std::streampos pos = stream->tellg();
146 if(stream->seekg(0, std::ios_base::end))
148 *stream_length = stream->tellg();
149 stream->seekg(pos);
152 if(!stream->good())
153 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
154 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
156 static FLAC__bool EofCallback(const FLAC__StreamDecoder*, void *client_data)
158 std::istream *stream = static_cast<FlacDecoder*>(client_data)->mFile.get();
159 return stream->eof() ? true : false;
162 public:
163 FlacDecoder(SharedPtr<std::istream> file)
164 : mFile(file), mFlacFile(nullptr), mSampleConfig(SampleConfig_Mono), mSampleType(SampleType_Int16), mFrequency(0),
165 mFrameSize(0), mSamplePos(0), mOutBytes(nullptr), mOutMax(0), mOutLen(0)
167 virtual ~FlacDecoder();
169 bool open();
171 virtual ALuint getFrequency() final;
172 virtual SampleConfig getSampleConfig() final;
173 virtual SampleType getSampleType() final;
175 virtual uint64_t getLength() final;
176 virtual uint64_t getPosition() final;
177 virtual bool seek(uint64_t pos) final;
179 virtual ALuint read(ALvoid *ptr, ALuint count) final;
182 FlacDecoder::~FlacDecoder()
184 if(mFlacFile)
186 FLAC__stream_decoder_finish(mFlacFile);
187 FLAC__stream_decoder_delete(mFlacFile);
188 mFlacFile = nullptr;
193 bool FlacDecoder::open()
195 mFlacFile = FLAC__stream_decoder_new();
196 if(mFlacFile)
198 if(FLAC__stream_decoder_init_stream(mFlacFile, ReadCallback, SeekCallback, TellCallback, LengthCallback, EofCallback, WriteCallback, MetadataCallback, ErrorCallback, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK)
200 while(mData.size() == 0)
202 if(FLAC__stream_decoder_process_single(mFlacFile) == false ||
203 FLAC__stream_decoder_get_state(mFlacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
204 break;
206 if(mData.size() > 0)
207 return true;
209 FLAC__stream_decoder_finish(mFlacFile);
211 FLAC__stream_decoder_delete(mFlacFile);
212 mFlacFile = nullptr;
215 return false;
219 ALuint FlacDecoder::getFrequency()
221 return mFrequency;
224 SampleConfig FlacDecoder::getSampleConfig()
226 return mSampleConfig;
229 SampleType FlacDecoder::getSampleType()
231 return mSampleType;
235 uint64_t FlacDecoder::getLength()
237 return FLAC__stream_decoder_get_total_samples(mFlacFile);
240 uint64_t FlacDecoder::getPosition()
242 return mSamplePos;
245 bool FlacDecoder::seek(uint64_t pos)
247 if(!FLAC__stream_decoder_seek_absolute(mFlacFile, pos))
248 return false;
249 mSamplePos = pos;
250 return true;
253 ALuint FlacDecoder::read(ALvoid *ptr, ALuint count)
255 mOutBytes = reinterpret_cast<ALubyte*>(ptr);
256 mOutLen = 0;
257 mOutMax = count * mFrameSize;
259 if(mData.size() > 0)
261 size_t rem = std::min(mData.size(), (size_t)mOutMax);
262 memcpy(ptr, &mData[0], rem);
263 mOutLen += rem;
264 mData.erase(mData.begin(), mData.begin()+rem);
267 while(mOutLen < mOutMax)
269 if(FLAC__stream_decoder_process_single(mFlacFile) == false ||
270 FLAC__stream_decoder_get_state(mFlacFile) == FLAC__STREAM_DECODER_END_OF_STREAM)
271 break;
273 ALuint ret = mOutLen / mFrameSize;
275 mSamplePos += ret;
277 return ret;
281 SharedPtr<Decoder> FlacDecoderFactory::createDecoder(SharedPtr<std::istream> file)
283 SharedPtr<FlacDecoder> decoder(new FlacDecoder(file));
284 if(!decoder->open()) decoder.reset();
285 return decoder;