arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
CodecALAC.h
1
2#pragma once
3
4#include "ALAC.h" // https://github.com/pschatzmann/codec-alac
5#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
6
7namespace audio_tools {
8
11 public:
12 void setChannels(int inNumChannels) {
13 int size = (inNumChannels > 2)
14 ? sizeof(ALACSpecificConfig) + kChannelAtomSize +
15 sizeof(ALACAudioChannelLayout)
16 : sizeof(ALACSpecificConfig);
17 vector.resize(size);
18 }
19
20 uint32_t size() { return vector.size(); }
21 uint8_t* data() { return vector.data(); }
22
23 protected:
24 Vector<uint8_t> vector;
25};
26
39class DecoderALAC : public AudioDecoder {
40 public:
42 DecoderALAC(int frameSize = kALACDefaultFrameSize) {
43 // this is used when setCodecConfig() is not called with encoder info
45 //setDefaultConfig();
46 }
47
48 // define ALACSpecificConfig
49 bool setCodecConfig(ALACSpecificConfig config) {
50 return setCodecConfig((uint8_t*)&config, sizeof(config));
51 }
52
55 size_t result = setCodecConfig(cfg.data(), cfg.size());
56 is_init = true;
57 return result;
58 }
59
61 bool setCodecConfig(const uint8_t* data, size_t len) override {
62 LOGI("DecoderALAC::setCodecConfig: %d", (int)len);
63 // Call Init() to set up the decoder
64 int32_t rc = dec.Init((void*)data, len);
65 if (rc != 0) {
66 LOGE("Init failed");
67 return false;
68 }
69 LOGI("ALAC Decoder Setup - SR: %d, Channels: %d, Bits: %d, Frame Size: %d",
70 (int)dec.mConfig.sampleRate, (int)dec.mConfig.numChannels,
71 (int)dec.mConfig.bitDepth, (int)dec.mConfig.frameLength);
72 AudioInfo tmp;
73 tmp.bits_per_sample = dec.mConfig.bitDepth;
74 tmp.channels = dec.mConfig.numChannels;
75 tmp.sample_rate = dec.mConfig.sampleRate;
76 setAudioInfo(tmp);
77 is_init = true;
78 return true;
79 }
80
82 void setAudioInfo(AudioInfo from) override {
84 dec.mConfig.sampleRate = from.sample_rate;
85 dec.mConfig.numChannels = from.channels;
86 dec.mConfig.bitDepth = from.bits_per_sample;
87 }
88
89
91 size_t write(const uint8_t* encodedFrame, size_t encodedLen) override {
92 LOGD("DecoderALAC::write: %d", (int)encodedLen);
93 // Make sure we have a config: we can't do this in begin because the setConfig()
94 // might be called after begin()
95 if (!is_init) setDefaultConfig();
96
97 // Make sure we have the output buffer set up
98 if (result_buffer.size() != outputBufferSize()) {
99 result_buffer.resize(outputBufferSize());
100 }
101
102 // Init bit buffer
103 BitBufferInit(&bits, (uint8_t*)encodedFrame, encodedLen);
104
105 // Decode
106 uint32_t outNumSamples = 0;
107 int32_t status =
108 dec.Decode(&bits, result_buffer.data(), dec.mConfig.frameLength,
109 dec.mConfig.numChannels, &outNumSamples);
110
111 if (status != 0) {
112 LOGE("Decode failed with error: %d", status);
113 return 0;
114 }
115
116 // Process result
117 size_t outputSize =
118 outNumSamples * dec.mConfig.numChannels * dec.mConfig.bitDepth / 8;
119 LOGI("DecoderALAC::write-pcm: %d", (int)outputSize);
120
121 // Output the result in chunks of 1k
122 int open = outputSize;
123 int processed = 0;
124 while (open > 0) {
125 int writeSize = MIN(1024, open);
126 size_t written =
127 p_print->write(result_buffer.data() + processed, writeSize);
128 if (writeSize != written) {
129 LOGE("write error: %d -> %d", (int)outputSize, (int)written);
130 }
131 open -= written;
132 processed += written;
133 }
134 return encodedLen;
135 }
136
137 operator bool() { return true; }
138
141 void setFrameSize(int frames) { dec.mConfig.frameLength = frames; }
142
144 int frameSize() { return dec.mConfig.frameLength; }
145
146 protected:
147 ALACDecoder dec;
148 Vector<uint8_t> result_buffer;
149 bool is_init = false;
150 struct BitBuffer bits;
151
152 void setDefaultConfig() {
153 // LOGW("Setting up default ALAC config")
154 AudioInfo info = audioInfo();
155 ALACSpecificConfig tmp;
156 // Essential parameters for ALAC compression
157 tmp.frameLength = frameSize();
158 tmp.compatibleVersion = 0;
159 tmp.bitDepth = info.bits_per_sample;
160 tmp.pb = 40; // Rice parameter limit
161 tmp.mb = 10; // Maximum prefix length for Rice coding
162 tmp.kb = 14; // History multiplier
163 tmp.numChannels = info.channels;
164 tmp.maxRun = 255; // Maximum run length supported
165 tmp.avgBitRate = 0;
166
167 tmp.sampleRate = info.sample_rate;
168
169 // Calculate max frame bytes - must account for:
170 // 1. Uncompressed frame size
171 // 2. ALAC frame headers
172 // 3. Potential compression inefficiency
173 uint32_t bytesPerSample = info.bits_per_sample / 8;
174 uint32_t uncompressedFrameSize =
175 frameSize() * info.channels * bytesPerSample;
176
177 // Add safety margins:
178 // - ALAC header (~50 bytes)
179 // - Worst case compression overhead (50%)
180 // - Alignment padding (64 bytes)
181 tmp.maxFrameBytes =
182 uncompressedFrameSize + (uncompressedFrameSize / 2) + 64 + 50;
183
185 setCodecConfig(tmp);
186 }
187
190 return dec.mConfig.frameLength * dec.mConfig.numChannels *
191 dec.mConfig.bitDepth / 8;
192 }
193
195 void convertToNetworkFormat(ALACSpecificConfig& config) {
196 config.frameLength = Swap32NtoB(config.frameLength);
197 config.maxRun = Swap16NtoB((uint16_t)config.maxRun);
198 config.maxFrameBytes = Swap32NtoB(config.maxFrameBytes);
199 config.avgBitRate = Swap32NtoB(config.avgBitRate);
200 config.sampleRate = Swap32NtoB(config.sampleRate);
201 }
202};
203
211class EncoderALAC : public AudioEncoder {
212 public:
214 EncoderALAC(int frameSize = kALACDefaultFrameSize) {
216 }
217 void setOutput(Print& out_stream) override { p_print = &out_stream; };
218
219 bool begin() override {
220 if (p_print == nullptr) {
221 LOGE("No output stream set");
222 return false;
223 }
224 // define input format
225 input_format = getInputFormat();
226 out_format = getOutputFormat();
227
228 // Setup Encoder
229 enc.SetFrameSize(frame_size);
230 int rc = enc.InitializeEncoder(out_format);
231
232 // Calculate exact buffer sizes based on frame settings
233 uint32_t bytesPerSample = info.bits_per_sample / 8;
234 uint32_t inputBufferSize = frame_size * info.channels * bytesPerSample;
235 // Calculate output buffer size
236 uint32_t outputBufferSize = inputBufferSize * 2; // Ensure enough space
237
238 LOGI(
239 "ALAC Encoder: frame_size=%d, inputBuf=%d, outputBuf=%d, channels=%d, "
240 "bits=%d",
241 frame_size, inputBufferSize, outputBufferSize, info.channels,
242 info.bits_per_sample);
243
244 in_buffer.resize(inputBufferSize);
245 out_buffer.resize(outputBufferSize);
246 is_started = rc == 0;
247 return is_started;
248 }
249
250 void end() override {
251 enc.Finish();
252 is_started = false;
253 }
254
256 size_t write(const uint8_t* data, size_t len) override {
257 if (!is_started) return 0;
258 LOGD("EncoderALAC::write: %d", (int)len);
259 for (int j = 0; j < len; j++) {
260 in_buffer.write(data[j]);
261 if (in_buffer.isFull()) {
262 // provide available encoded data length
263 int32_t ioNumBytes = in_buffer.size();
264 int rc = enc.Encode(input_format, out_format, (uint8_t*)in_buffer.data(),
265 out_buffer.data(), &ioNumBytes);
266 // Output encoded data
267 size_t written = p_print->write(out_buffer.data(), ioNumBytes);
268 if (ioNumBytes != written) {
269 LOGE("write error: %d -> %d", (int)ioNumBytes, (int)written);
270 }
271 in_buffer.reset();
272 }
273 }
274 return len;
275 }
276
278 ALACSpecificConfig config() {
279 enc.GetConfig(cfg);
280 return cfg;
281 }
282
285 bin.setChannels(info.channels);
286 uint32_t size = bin.size();
287 enc.GetMagicCookie(bin.data(), &size);
288 return bin;
289 }
290
292 operator bool() { return is_started && p_print != nullptr; }
293
295 const char* mime() override { return "audio/alac"; }
296
298 void setFastMode(bool fast) {
299 enc.SetFastMode(fast);
300 }
301
303 void setFrameSize(int frames) {
304 if (is_started) {
305 LOGE("Can't change frame size on started encoder")
306 return;
307 }
308 frame_size = frames;
309 }
310
312 int frameSize() { return frame_size; }
313
314 protected:
315 int frame_size = kALACDefaultFrameSize;
316 ALACEncoder enc;
317 SingleBuffer<uint8_t> in_buffer;
318 Vector<uint8_t> out_buffer;
319 AudioFormatDescription input_format;
320 AudioFormatDescription out_format;
321 ALACSpecificConfig cfg;
323 Print* p_print = nullptr;
324 bool is_started = false;
325
326 AudioFormatDescription getInputFormat() {
327 AudioFormatDescription result;
328 memset(&result, 0, sizeof(AudioFormatDescription));
329 result.mSampleRate = info.sample_rate;
330 result.mFormatID = kALACFormatLinearPCM;
331 result.mFormatFlags =
332 kALACFormatFlagIsSignedInteger |
333 kALACFormatFlagIsPacked; // Native endian, signed integer
334 result.mBytesPerPacket = info.channels * (info.bits_per_sample / 8);
335 result.mFramesPerPacket = 1;
336 result.mBytesPerFrame = info.channels * (info.bits_per_sample / 8);
337 result.mChannelsPerFrame = info.channels;
338 result.mBitsPerChannel = info.bits_per_sample;
339
340 return result;
341 }
342
343 AudioFormatDescription getOutputFormat() {
344 AudioFormatDescription result;
345 memset(&result, 0, sizeof(AudioFormatDescription));
346 result.mSampleRate = info.sample_rate;
347 result.mFormatID = kALACCodecFormat;
348 result.mFormatFlags = getOutputFormatFlags(info.bits_per_sample); // or 0 ?
349 result.mBytesPerPacket = 0; // Variable for compressed format
350 result.mFramesPerPacket = frame_size; // Common ALAC frame size
351 result.mBytesPerFrame = 0; // Variable for compressed format
352 result.mChannelsPerFrame = info.channels;
353 result.mBitsPerChannel = info.bits_per_sample;
354 return result;
355 }
356
357 // Adapted from CoreAudioTypes.h
358 enum {
359 kFormatFlag_16BitSourceData = 1,
360 kFormatFlag_20BitSourceData = 2,
361 kFormatFlag_24BitSourceData = 3,
362 kFormatFlag_32BitSourceData = 4
363 };
364
365 uint32_t getOutputFormatFlags(uint32_t bits) {
366 switch (bits) {
367 case 16:
368 return kFormatFlag_16BitSourceData;
369 case 20:
370 return kFormatFlag_20BitSourceData;
371 case 24:
372 return kFormatFlag_24BitSourceData;
373 case 32:
374 return kFormatFlag_32BitSourceData;
375 break;
376 default:
377 LOGE("Unsupported bit depth: %d", bits);
378 return 0;
379 }
380 }
381};
382
383} // namespace audio_tools
Magic Cookie.
Definition CodecALAC.h:10
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition AudioCodecsBase.h:28
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition AudioCodecsBase.h:25
Encoding of PCM data.
Definition AudioCodecsBase.h:96
ALAC (Apple Lossless Audio Codec) decoder. This class depends on https://github.com/pschatzmann/codec...
Definition CodecALAC.h:39
size_t write(const uint8_t *encodedFrame, size_t encodedLen) override
we expect the write is called for a complete frame!
Definition CodecALAC.h:91
int frameSize()
Provides the actual frame size.
Definition CodecALAC.h:144
bool setCodecConfig(const uint8_t *data, size_t len) override
write Magic Cookie (ALACSpecificConfig)
Definition CodecALAC.h:61
void convertToNetworkFormat(ALACSpecificConfig &config)
Convert to big endian so that we can use it in Init()
Definition CodecALAC.h:195
int outputBufferSize()
Calculate the output buffer size based on the current configuration.
Definition CodecALAC.h:189
void setAudioInfo(AudioInfo from) override
Update the global decoder info.
Definition CodecALAC.h:82
DecoderALAC(int frameSize=kALACDefaultFrameSize)
Default constructor: you can define your own optimized frame size.
Definition CodecALAC.h:42
bool setCodecConfig(ALACBinaryConfig cfg)
write Magic Cookie (ALACSpecificConfig)
Definition CodecALAC.h:54
void setFrameSize(int frames)
Definition CodecALAC.h:141
ALAC (Apple Lossless Audio Codec) encoder. This class is responsible for encoding audio data into ALA...
Definition CodecALAC.h:211
int frameSize()
Determins the actually defined number of frames.
Definition CodecALAC.h:312
ALACSpecificConfig config()
Provide the configuration of the encoder.
Definition CodecALAC.h:278
EncoderALAC(int frameSize=kALACDefaultFrameSize)
Default constructor: you can define your own optimized frame size.
Definition CodecALAC.h:214
size_t write(const uint8_t *data, size_t len) override
Encode the audio samples into ALAC format.
Definition CodecALAC.h:256
void setFastMode(bool fast)
Defines if the encoder should use fast mode.
Definition CodecALAC.h:298
const char * mime() override
Mime type: returns audio/alac.
Definition CodecALAC.h:295
ALACBinaryConfig & binaryConfig()
Provide the magic coookie for the decoder.
Definition CodecALAC.h:284
void setFrameSize(int frames)
Defines the frame size for the decoder: default is 4096 frames.
Definition CodecALAC.h:303
Definition NoArduino.h:62
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:202
bool isFull() override
checks if the buffer is full
Definition Buffers.h:236
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:292
T * data()
Provides address of actual data.
Definition Buffers.h:271
void reset() override
clears the buffer
Definition Buffers.h:273
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
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