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