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