arduino-audio-tools
Loading...
Searching...
No Matches
CodecFLAC.h
Go to the documentation of this file.
1
9#pragma once
10
14#include "flac.h"
15
16#ifndef FLAC_READ_TIMEOUT_MS
17#define FLAC_READ_TIMEOUT_MS 10000
18#endif
19
20#ifndef FLAC_BUFFER_SIZE
21#define FLAC_BUFFER_SIZE (8 * 1024)
22#endif
23
24
25namespace audio_tools {
26
37 public:
39 FLACDecoder(bool isOgg=false) {
40 is_ogg = isOgg;
41 }
42
45
49 void setOgg(bool isOgg) {
50 is_ogg = isOgg;
51 }
52
60
61 bool begin() {
62 TRACEI();
63 is_active = false;
64 if (decoder == nullptr) {
66 LOGE("ERROR: allocating decoder");
67 is_active = false;
68 return false;
69 }
70 LOGI("FLAC__stream_decoder_new");
71 }
72
73 // if it is already active we close it
77 }
78
79 // deactivate md5 checking
81
82 // init decoder
83 if (is_ogg){
84 init_status = FLAC__stream_decoder_init_ogg_stream( decoder, read_callback, nullptr, nullptr, nullptr, nullptr, write_callback, nullptr, error_callback, this);
85 } else {
86 init_status = FLAC__stream_decoder_init_stream( decoder, read_callback, nullptr, nullptr, nullptr, nullptr, write_callback, nullptr, error_callback, this);
87 }
88
90 LOGE("ERROR: initializing decoder: %s", FLAC__StreamDecoderInitStatusString[init_status]);
91 is_active = false;
92 return false;
93 }
94 LOGI("FLAC is open");
95 is_active = true;
96 return true;
97 }
98
99 void end() {
100 TRACEI();
101 if (decoder != nullptr){
102 flush();
104 decoder = nullptr;
105 }
106 is_active = false;
107 }
108
113
114
115 operator bool() { return is_active; }
116
117
119 bool copy() {
120 LOGD("copy");
121 if (!is_active) {
122 LOGW("FLAC not active");
123 return false;
124 }
125 if (p_input == nullptr) {
126 LOGE("setInput was not called");
127 return false;
128 }
130 LOGE("FLAC__stream_decoder_process_single");
131 return false;
132 }
133 return true;
134 }
135
137 void setMD5(bool flag){
139 }
140
142 bool isOgg() const { return is_ogg; }
143
145 const char *mime() override { return is_ogg ? "audio/ogg; codecs=flac" : "audio/flac"; }
146
147
148 protected:
149 bool is_active = false;
150 bool is_ogg = false;
151 bool is_md5_checing = false;
157
158
160 bool isInputFromStream() { return p_input != nullptr; }
161
168
169 size_t readBytes(uint8_t *data, size_t len) override {
170 return p_input->readBytes(data, len);
171 }
172
176 LOGD("read_callback: %d", (int) *bytes);
178 if (self == nullptr || !self->is_active) {
180 }
181
182 // get data directly from stream
183 *bytes = self->readBytes(result_buffer, *bytes);
184 LOGD("-> %d", (int) *bytes);
185 if (self->isEof(*bytes)){
187 self->is_active = false;
188 }
189 return result;
190 }
191
193 bool isEof(int bytes) {
194 bool result = false;
195 if (bytes==0){
196 delay(5);
197 } else {
199 }
201 result = true;
202 }
203 return result;
204 }
205
208 LOGD("write_callback: %u", (unsigned)frame->header.blocksize);
210
211 AudioInfo actual_info = self->audioInfo();
212 if (self->info != actual_info){
213 self->info = actual_info;
214 self->info.logInfo();
216 if (bps!=16){
217 LOGI("Converting from %d bits", bps);
218 }
219 self->info = actual_info;
220 self->notifyAudioChange(self->info);
221 }
222
223 // write audio data
225 int16_t result_frame[actual_info.channels];
226
227 switch(bps){
228 case 8:
229 for (int j = 0; j < frame->header.blocksize; j++) {
230 for (int i = 0; i < actual_info.channels; i++) {
231 //self->output_buffer[j*actual_info.channels + i] = buffer[i][j]<<8;
232 result_frame[i] = buffer[i][j]<<8;
233 }
234 self->p_print->write((uint8_t *)result_frame, sizeof(result_frame));
235 }
236 break;
237 case 16:
238 for (int j = 0; j < frame->header.blocksize; j++) {
239 for (int i = 0; i < actual_info.channels; i++) {
240 result_frame[i] = buffer[i][j];
241 }
242 self->p_print->write((uint8_t *)result_frame, sizeof(result_frame));
243 }
244 break;
245 case 24:
246 for (int j = 0; j < frame->header.blocksize; j++) {
247 for (int i = 0; i < actual_info.channels; i++) {
248 result_frame[i] = buffer[i][j] >> 8;
249 }
250 self->p_print->write((uint8_t *)result_frame, sizeof(result_frame));
251 }
252 break;
253 case 32:
254 for (int j = 0; j < frame->header.blocksize; j++) {
255 for (int i = 0; i < actual_info.channels; i++) {
256 result_frame[i] = buffer[i][j] >> 16;
257 }
258 self->p_print->write((uint8_t *)result_frame, sizeof(result_frame));
259 }
260 break;
261 default:
262 LOGE("Unsupported bps: %d", bps);
263 }
264
266 }
267};
268
269
277class FLACEncoder : public AudioEncoder {
278 public:
280 FLACEncoder(bool isOgg = false) {
281 setOgg(isOgg);
282 }
283
286
287 void setOgg(bool isOgg) {
288 is_ogg = isOgg;
289 }
290
291 bool isOgg() {return is_ogg;}
292
293 void setBlockSize(int size){
294 flac_block_size = size;
295 }
296
297 int blockSize() {return flac_block_size; }
298
299 void setCompressionLevel(int level){
301 }
302
304
307
309 const char *mime() override { return "audio/flac"; }
310
312 virtual void setAudioInfo(AudioInfo from) override {
313 cfg = from;
314 cfg.logInfo();
315 }
316
318 virtual bool begin() override {
319 TRACED();
320 if (p_encoder==nullptr){
322 if (p_encoder==nullptr){
323 LOGE("FLAC__stream_encoder_new");
324 return false;
325 }
326 }
327
328 is_open = false;
329
335
336 // setup stream
338 if (is_ogg){
339 status = FLAC__stream_encoder_init_ogg_stream(p_encoder, nullptr, write_callback, nullptr, nullptr, nullptr, this);
340 } else {
341 status = FLAC__stream_encoder_init_stream(p_encoder, write_callback, nullptr, nullptr, nullptr, this);
342 }
344 LOGE("ERROR: initializing decoder: %s", FLAC__StreamEncoderInitStatusString[status]);
347 }
348 return false;
349 }
350 is_open = true;
351 return true;
352 }
353
355 bool begin(Print &out) {
356 p_print = &out;
357 return begin();
358 }
359
361 void end() override {
362 TRACED();
363 if (p_encoder != nullptr) {
365 p_encoder = nullptr;
366 is_open = false;
367 }
368 }
369
371 virtual size_t write(const uint8_t *data, size_t len) override {
372 if (!is_open || p_print == nullptr) return 0;
373 LOGD("write: %zu", len);
374 size_t result = 0;
375 int samples=0;
376 int frames=0;
377 int32_t *data32=nullptr;
378 switch(cfg.bits_per_sample){
379 case 16:
380 samples = len / sizeof(int16_t);
381 frames = samples / cfg.channels;
382 writeBuffer((int16_t*)data, samples);
383 data32 = buffer.data();
384 break;
385
386 case 24:
387 case 32:
388 samples = len / sizeof(int32_t);
389 frames = samples / cfg.channels;
390 data32 = (int32_t*) data;
391 break;
392
393 default:
394 LOGE("bits_per_sample not supported: %d", (int) cfg.bits_per_sample);
395 break;
396 }
397
398 if (frames>0){
400 result = len;
401 } else {
402 LOGE("FLAC__stream_encoder_process_interleaved");
403 }
404 }
405
406 return result;
407 }
408
409 operator bool() override { return is_open; }
410
411 bool isOpen() { return is_open; }
412
413 protected:
416 Print *p_print = nullptr;
418 bool is_open = false;
419 bool is_ogg = false;
420 int flac_block_size = 512; // small value to minimize allocated memory
422
425 if (self->p_print!=nullptr){
426 size_t written = self->p_print->write((uint8_t*)buffer, bytes);
427 if (written!=bytes){
428 LOGE("write_callback %zu -> %zu", bytes, written);
430 }
431 }
433 }
434
435 void writeBuffer(int16_t * data, size_t samples) {
436 buffer.resize(samples);
437 for (int j=0;j<samples;j++){
438 buffer[j] = data[j];
439 }
440 }
441};
442
443} // namespace audio_tools
444
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define FLAC_READ_TIMEOUT_MS
Definition CodecFLAC.h:17
Encoding of PCM data.
Definition AudioCodecsBase.h:97
void notifyAudioChange(AudioInfo info)
Definition AudioTypes.h:178
Decoder for FLAC. Depends on https://github.com/pschatzmann/arduino-libflac. We support an efficient ...
Definition CodecFLAC.h:36
uint64_t read_timeout_ms
Definition CodecFLAC.h:156
void setOgg(bool isOgg)
Definition CodecFLAC.h:49
uint64_t time_last_read
Definition CodecFLAC.h:155
void setTimeout(uint64_t readTimeout=10000)
Definition CodecFLAC.h:46
FLAC__StreamDecoder * decoder
Definition CodecFLAC.h:153
bool is_active
Definition CodecFLAC.h:149
void setMD5(bool flag)
Activate/deactivate md5 checking: call this before calling begin()
Definition CodecFLAC.h:137
AudioInfo info
Definition CodecFLAC.h:152
bool is_md5_checing
Definition CodecFLAC.h:151
size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream.
Definition CodecFLAC.h:169
bool isEof(int bytes)
We return eof when we were subsequently getting 0 bytes for the timeout period.
Definition CodecFLAC.h:193
bool isOgg() const
returns true of the stream is ogg
Definition CodecFLAC.h:142
bool begin()
Starts the processing.
Definition CodecFLAC.h:61
static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte result_buffer[], size_t *bytes, void *client_data)
Callback which reads from stream.
Definition CodecFLAC.h:174
bool copy()
Stream Interface: Process a single frame - only relevant when input stream has been defined.
Definition CodecFLAC.h:119
AudioInfo audioInfo()
Provides the audio information for the current stream.
Definition CodecFLAC.h:53
FLAC__StreamDecoderInitStatus init_status
Definition CodecFLAC.h:154
~FLACDecoder()
Destructor - calls end();.
Definition CodecFLAC.h:44
bool is_ogg
Definition CodecFLAC.h:150
void end()
Releases the reserved memory.
Definition CodecFLAC.h:99
const char * mime() override
Provides "audio/flac" or "audio/ogg".
Definition CodecFLAC.h:145
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
Output decoded result to final output stream.
Definition CodecFLAC.h:207
void flush()
Process all data in the buffer.
Definition CodecFLAC.h:110
static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
Error callback.
Definition CodecFLAC.h:163
FLACDecoder(bool isOgg=false)
Default Constructor.
Definition CodecFLAC.h:39
bool isInputFromStream()
Check if input is directly from stream - instead of writes.
Definition CodecFLAC.h:160
FLACEncoder.
Definition CodecFLAC.h:277
virtual size_t write(const uint8_t *data, size_t len) override
Writes FLAC Packet.
Definition CodecFLAC.h:371
bool is_open
Definition CodecFLAC.h:418
void setOutput(Print &out_stream) override
Defines the output Stream.
Definition CodecFLAC.h:306
AudioInfo cfg
Definition CodecFLAC.h:414
void setOgg(bool isOgg)
Definition CodecFLAC.h:287
~FLACEncoder()
Destructor - calls end();.
Definition CodecFLAC.h:285
int blockSize()
Definition CodecFLAC.h:297
bool isOpen()
Definition CodecFLAC.h:411
static FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
Definition CodecFLAC.h:423
virtual bool begin() override
starts the processing using the actual AudioInfo
Definition CodecFLAC.h:318
int flac_compression_level
Definition CodecFLAC.h:421
FLAC__StreamEncoder * p_encoder
Definition CodecFLAC.h:417
void end() override
stops the processing
Definition CodecFLAC.h:361
bool begin(Print &out)
starts the processing
Definition CodecFLAC.h:355
Vector< FLAC__int32 > buffer
Definition CodecFLAC.h:415
int compressionLevel()
Definition CodecFLAC.h:303
FLACEncoder(bool isOgg=false)
Default Constructor.
Definition CodecFLAC.h:280
void writeBuffer(int16_t *data, size_t samples)
Definition CodecFLAC.h:435
bool is_ogg
Definition CodecFLAC.h:419
const char * mime() override
Provides "audio/pcm".
Definition CodecFLAC.h:309
void setBlockSize(int size)
Definition CodecFLAC.h:293
void setCompressionLevel(int level)
Definition CodecFLAC.h:299
bool isOgg()
Definition CodecFLAC.h:291
virtual void setAudioInfo(AudioInfo from) override
We update the audio information which will be used in the begin method.
Definition CodecFLAC.h:312
Print * p_print
Definition CodecFLAC.h:416
int flac_block_size
Definition CodecFLAC.h:420
Definition NoArduino.h:62
virtual size_t write(const uint8_t *data, size_t len)
Definition NoArduino.h:126
virtual size_t readBytes(uint8_t *data, size_t len)
Definition NoArduino.h:147
A Streaming Decoder where we provide both the input and output as streams.
Definition StreamingDecoder.h:29
Stream * p_input
Input stream for encoded audio data.
Definition StreamingDecoder.h:169
Print * p_print
Output stream for decoded PCM data.
Definition StreamingDecoder.h:168
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(int newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:316
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
void delay(unsigned long ms)
Definition Time.h:23
uint32_t millis()
Returns the milliseconds since the start.
Definition Time.h:12
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:55
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:57
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:59
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:61
virtual void logInfo(const char *source="")
Definition AudioTypes.h:125