arduino-audio-tools
Loading...
Searching...
No Matches
CodecFLACFoxen.h
1#pragma once
2
3#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4#include "AudioTools/CoreAudio/Buffers.h"
5#include "foxen-flac.h"
6
7namespace audio_tools {
8
9#define FOXEN_IN_BUFFER_SIZE 1024 * 2
10#define FOXEN_OUT_BUFFER_SIZE 1024 * 4
11
22 public:
23 FLACDecoderFoxen() = default;
24
26 FLACDecoderFoxen(int maxBlockSize, int maxChannels,
27 bool convertTo16Bits = true, bool releaseOnEnd = false) {
28 is_convert_to_16 = convertTo16Bits;
29 max_block_size = maxBlockSize;
30 max_channels = maxChannels;
31 is_release_memory_on_end = releaseOnEnd;
32 };
33
35 ~FLACDecoderFoxen() { end(); }
36
37 bool begin() {
38 TRACEI();
39 is_active = false;
40 size_t foxen_size = fx_flac_size(max_block_size, max_channels);
41 foxen_data.resize(foxen_size);
42 flac = fx_flac_init(foxen_data.data(), max_block_size, max_channels);
43
44 if (flac != nullptr) {
45 is_active = true;
46 write_buffer.resize(in_buffer_size);
47 out.resize(out_buffer_size);
48 } else {
49 LOGE("not enough memory");
50 if (is_stop_on_error) stop();
51 }
52
53 return is_active;
54 }
55
56 void end() {
57 TRACEI();
58 flush();
59 if (flac != nullptr && is_release_memory_on_end) {
60 foxen_data.resize(0);
61 write_buffer.resize(0);
62 out.resize(0);
63 }
64 is_active = false;
65 }
66
67 size_t write(const uint8_t *data, size_t len) override {
68 LOGD("write: %d", len);
69 // no processing if not active
70 if (!is_active) return 0;
71
72 size_t result = write_buffer.writeArray(data, len);
73 LOGD("write_buffer availabe: %d", write_buffer.available());
74
75 while (write_buffer.available() > 0) {
76 if (!decode()) break;
77 }
78
79 // if the buffer is full we could not decode anything
80 if (write_buffer.available() == write_buffer.size()) {
81 LOGE("Decoder did not consume any data");
82 if (is_stop_on_error) stop();
83 }
84
85 LOGD("write: %d -> %d", len, result);
86 return result;
87 }
88
89 void flush() { decode(); }
90
91 operator bool() override { return is_active; }
92
94 void setInBufferSize(int size) { in_buffer_size = size; }
95
98 void setOutBufferSize(int size) { out_buffer_size = size; }
99
101 void setMaxBlockSize(int size) { max_block_size = size; }
102
104 void setMaxChannels(int ch) { max_channels = ch; }
105
107 void set32Bit(bool flag) { is_convert_to_16 = !flag; }
108
109 protected:
110 fx_flac_t *flac = nullptr;
111 SingleBuffer<uint8_t> write_buffer{0};
112 Vector<int32_t> out;
113 Vector<uint8_t> foxen_data{0};
114 bool is_active = false;
115 bool is_convert_to_16 = true;
116 bool is_stop_on_error = true;
117 bool is_release_memory_on_end = false;
118 int bits_eff = 0;
119 int max_block_size = 5 * 1024;
120 int max_channels = 2;
121 int in_buffer_size = FOXEN_IN_BUFFER_SIZE;
122 int out_buffer_size = FOXEN_OUT_BUFFER_SIZE;
123
124 bool decode() {
125 TRACED();
126 if (!is_active) return false;
127 uint32_t out_len = out.size();
128 uint32_t buf_len = write_buffer.available();
129 uint32_t buf_len_result = buf_len;
130 int rc = fx_flac_process(flac, write_buffer.data(), &buf_len_result,
131 out.data(), &out_len);
132 // assert(out_len <= FOXEN_OUT_BUFFER_SIZE);
133
134 switch (rc) {
135 case FLAC_END_OF_METADATA: {
136 processMetadata();
137 } break;
138
139 case FLAC_ERR: {
140 LOGE("FLAC decoder in error state!");
141 if (is_stop_on_error) stop();
142 } break;
143
144 default: {
145 if (out_len > 0) {
146 LOGD("Providing data: %d samples", out_len);
147 if (is_convert_to_16) {
148 write16BitData(out_len);
149 } else {
150 write32BitData(out_len);
151 }
152 }
153 } break;
154 }
155 LOGD("processed: %d bytes of %d -> %d samples", buf_len_result, buf_len,
156 out_len);
157 // removed processed bytes from buffer
158 write_buffer.clearArray(buf_len_result);
159 return buf_len_result > 0 || out_len > 0;
160 }
161
162 void write32BitData(int out_len) {
163 TRACED();
164 // write the result to the output destination
165 writeBlocking(p_print, (uint8_t *)out.data(), out_len * sizeof(int32_t));
166 }
167
168 void write16BitData(int out_len) {
169 TRACED();
170 // in place convert to 16 bits
171 int16_t *out16 = (int16_t *)out.data();
172 for (int j = 0; j < out_len; j++) {
173 out16[j] = out.data()[j] >> 16; // 65538;
174 }
175 // write the result to the output destination
176 LOGI("writeBlocking: %d", out_len * sizeof(int16_t));
177 writeBlocking(p_print, (uint8_t *)out.data(), out_len * sizeof(int16_t));
178 }
179
180 void processMetadata() {
181 bits_eff = fx_flac_get_streaminfo(flac, FLAC_KEY_SAMPLE_SIZE);
182 int info_blocksize = fx_flac_get_streaminfo(flac, FLAC_KEY_MAX_BLOCK_SIZE);
183
184 LOGI("bits: %d", bits_eff);
185 LOGI("blocksize: %d", info_blocksize);
186 // assert(bits_eff == 32);
187 info.sample_rate = fx_flac_get_streaminfo(flac, FLAC_KEY_SAMPLE_RATE);
188 info.channels = fx_flac_get_streaminfo(flac, FLAC_KEY_N_CHANNELS);
189 info.bits_per_sample = is_convert_to_16 ? 16 : bits_eff;
190 info.logInfo();
191 if (info.channels > max_channels) {
192 LOGE("max channels too low: %d -> %d", max_channels, info.channels);
193 if (is_stop_on_error) stop();
194 }
195 if (info_blocksize > max_block_size) {
196 LOGE("max channels too low: %d -> %d", max_block_size, info_blocksize);
197 if (is_stop_on_error) stop();
198 }
199 notifyAudioChange(info);
200 }
201};
202
203} // namespace audio_tools
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
Foxen FLAC Decoder using https://github.com/astoeckel/libfoxenflac Unlike FLACDecoder which is a stre...
Definition CodecFLACFoxen.h:21
FLACDecoderFoxen(int maxBlockSize, int maxChannels, bool convertTo16Bits=true, bool releaseOnEnd=false)
Default Constructor.
Definition CodecFLACFoxen.h:26
void set32Bit(bool flag)
Select between 16 and 32 bit output: the default is 16 bits.
Definition CodecFLACFoxen.h:107
void setMaxChannels(int ch)
Defines the maximum number of channels: drives the buffer allocation.
Definition CodecFLACFoxen.h:104
void setOutBufferSize(int size)
Definition CodecFLACFoxen.h:98
~FLACDecoderFoxen()
Destructor - calls end();.
Definition CodecFLACFoxen.h:35
void setMaxBlockSize(int size)
Defines the maximum FLAC blocksize: drives the buffer allocation.
Definition CodecFLACFoxen.h:101
void setInBufferSize(int size)
Defines the input buffer size (default is 2k)
Definition CodecFLACFoxen.h:94
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
int available() override
provides the number of entries that are available to read
Definition Buffers.h:229
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:301
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:197
T * data()
Provides address of actual data.
Definition Buffers.h:280
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:248
void stop()
Public generic methods.
Definition AudioRuntime.h:18
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59