arduino-audio-tools
Loading...
Searching...
No Matches
CodecDSF.h
Go to the documentation of this file.
19#pragma once
20#pragma GCC optimize("O3")
21
25
26namespace audio_tools {
27
32struct DSFMetadata : public AudioInfo {
33 DSFMetadata() = default;
34 DSFMetadata(int rate) { sample_rate = rate; }
42 float duration_sec = 0;
46 float filter_cutoff = 0.45f;
50 int output_buffer_size = 2 * 1024;
52 bool is_raw = false;
53};
54
57 char id[4]; // "DSD "
58 uint64_t chunkSize; // 28
59 uint64_t fileSize; // total file size
60 uint64_t metadataOffset; // offset to "ID3 " chunk (0 if none)
61};
62
65 char id[4]; // "fmt "
66 uint64_t chunkSize; // 52
68 uint32_t formatID; // 0
69 uint32_t channelType; // e.g., 2 for stereo
70 uint32_t channelNum; // number of channels
71 uint32_t samplingFrequency; // e.g., 2822400
73 uint64_t sampleCount; // total samples per channel
74 uint32_t blockSizePerChannel; // e.g., 4096
75 uint32_t reserved; // 0
76};
77
80 char id[4]; // "data"
81 uint64_t chunkSize; // size of DSD data
82};
83
93class DSFDecoder : public AudioDecoder {
94 public:
95 DSFDecoder() = default;
96 DSFDecoder(DSFMetadata metaData) { setMetaData(metaData); };
97
98 AudioInfo audioInfo() override { return meta; }
99
100 void setAudioInfo(AudioInfo from) override {
101 TRACED();
103 meta.copyFrom(from);
104 if (isHeaderAvailable()) {
105 int buffer_size = getOutputBufferSize();
106 pcmBuffer.resize(buffer_size);
107
110 for (int ch = 0; ch < meta.channels; ch++) {
112 }
113
114 setupFilters();
116 }
117 }
118
119 bool begin() {
120 TRACED();
121 headerParsed = false;
122 blockPos = 0;
123 decimationStep = 64;
124 isActive = true;
125 return true;
126 }
127
128 void end() override { isActive = false; }
129
130 const DSFMetadata getMetadata() { return meta; }
131
132 void setMetaData(DSFMetadata metaData) {
133 meta = metaData;
135 }
136
138 void setInfoCallback(void (*callback)(const DSFFormat& fmt)) {
139 infoCallback = callback;
140 }
141
143
144 operator bool() { return isActive; }
145
146 size_t write(const uint8_t* data, size_t len) {
147 LOGD("write: %u", (unsigned)len);
148 size_t i = 0;
149
150 i += processHeader(data, len);
151
152 if (headerParsed && i < len) {
153 i += processDSDData(data, len, i);
154 }
155
156 return len;
157 }
158
159 protected:
160 bool headerParsed = false;
161 bool isActive = false;
163 void (*infoCallback)(const DSFFormat& fmt) = nullptr;
164
169
171
173 int frame_size = meta.bits_per_sample / 8 * meta.channels;
174 if (meta.bits_per_sample == 24) frame_size = 4 * meta.channels;
175 int buffer_size = frame_size;
176 if (meta.output_buffer_size > buffer_size)
177 buffer_size = meta.output_buffer_size;
178 return buffer_size;
179 }
180
181 size_t processHeader(const uint8_t* data, size_t len) {
182 if (headerParsed) return 0;
183 LOGI("processHeader: %u", (unsigned)len);
184
185 if (memcmp(data, "DSD ", 4) != 0) {
186 LOGE("Invalid DSF header magic");
187 return 0;
188 }
189
190 int dataPos = findTag("data", data, len);
191 int fmtPos = findTag("fmt ", data, len);
192 if (dataPos < 0 || fmtPos < 0) {
193 LOGE("DSF header not found in data (fmt: %d, data: %d)", fmtPos, dataPos);
194 return 0;
195 }
196
197 parseFMT(data + fmtPos, len - fmtPos);
198 parseData(data + dataPos, len - dataPos);
199 headerParsed = true;
200
201 if (infoCallback) {
202 infoCallback(*reinterpret_cast<const DSFFormat*>(data + fmtPos));
203 }
204
205 if (!meta.is_raw) {
207 }
208
209 return dataPos + sizeof(DSFDataHeader);
210 }
211
212 size_t processDSDData(const uint8_t* data, size_t len, size_t startPos) {
213 LOGD("processDSDData: %u (%u)", (unsigned)len, (unsigned)startPos);
214
215 if (meta.is_raw) {
216 size_t rawLen = len - startPos;
218 return rawLen;
219 }
220
221 size_t totalProcessed = 0;
222 size_t pos = startPos;
223
224 while (pos < len) {
225 size_t buffered = bufferDSDData(data, len, pos);
226 if (buffered == 0) break;
227 pos += buffered;
228 totalProcessed += buffered;
230 }
231
232 return totalProcessed;
233 }
234
235 size_t bufferDSDData(const uint8_t* data, size_t len, size_t startPos) {
236 size_t consumed = 0;
238
239 for (size_t i = startPos; i < len; i++) {
241 if (ch >= meta.channels) {
242 blockPos = 0;
243 ch = 0;
244 }
245 if (channelDsdBuffers[ch].availableForWrite() <= 0) break;
246 channelDsdBuffers[ch].write(data[i]);
247 consumed++;
248 blockPos++;
249 if (blockPos >= blockSetSize) blockPos = 0;
250 }
251 return consumed;
252 }
253
256 int stages = getFilterStages();
257
259 for (int ch = 0; ch < meta.channels; ch++) {
260 int ones = 0;
261 for (int b = 0; b < bytesPerDecimation; b++) {
265 }
266
267 float pcm = 2.0f * ones / decimationStep - 1.0f;
268
269 for (int s = 0; s < stages; s++) {
270 pcm = channelFilters[ch * stages + s].process(pcm);
271 }
272
273 writePCMSample(clip(pcm));
274 }
275
276 if (pcmBuffer.isFull()) {
277 size_t frameSize = pcmBuffer.available();
278 writeBlocking(getOutput(), (uint8_t*)pcmBuffer.data(), frameSize);
280 }
281 }
282
283 // Flush remaining PCM samples
284 if (pcmBuffer.available() > 0) {
288 }
289
290 // Compact linear buffers so write space is reclaimed
291 for (int ch = 0; ch < meta.channels; ch++) {
292 channelDsdBuffers[ch].trim();
293 }
294 }
295
297 for (int ch = 0; ch < meta.channels; ch++) {
298 if (channelDsdBuffers[ch].available() < bytesNeeded) return false;
299 }
300 return true;
301 }
302
304 v = (v & 0x55) + ((v >> 1) & 0x55);
305 v = (v & 0x33) + ((v >> 2) & 0x33);
306 return (v & 0x0F) + ((v >> 4) & 0x0F);
307 }
308
309 float clip(float value) {
310 if (value > 1.0f) return 1.0f;
311 if (value < -1.0f) return -1.0f;
312 return value;
313 }
314
317 if (stages < 0) stages = 0;
318 if (stages > 3) stages = 3;
319 return stages;
320 }
321
323 TRACEI();
324 int stages = getFilterStages();
325 if (stages == 0 || meta.sample_rate <= 0 || meta.channels <= 0) return;
326
329
330 // Butterworth Q values for maximally-flat passband
331 static const float butterworthQ[][3] = {
332 {0.7071f, 0, 0},
333 {0.5412f, 1.3066f, 0},
334 {0.5176f, 0.7071f, 1.9319f},
335 };
336
337 for (int ch = 0; ch < meta.channels; ch++) {
338 for (int s = 0; s < stages; s++) {
339 float q = butterworthQ[stages - 1][s];
341 }
342 }
343 }
344
346 TRACEI();
347 if (meta.sample_rate == 0 || meta.dsd_sample_rate == 0) {
348 LOGE("Invalid sample rates: DSD=%u, PCM=%u",
349 (unsigned)meta.dsd_sample_rate, (unsigned)meta.sample_rate);
350 return;
351 }
352
354 if (decimationStep < 64) {
355 LOGW("Decimation step %u too low, setting to 64",
356 (unsigned)decimationStep);
357 decimationStep = 64;
358 }
359 if (decimationStep > 512) {
360 LOGW("Decimation step %u too high, setting to 512",
361 (unsigned)decimationStep);
362 decimationStep = 512;
363 }
364
365 decimationStep = (decimationStep / 8) * 8;
366 if (decimationStep < 64) decimationStep = 64;
367
368 LOGI("Decimation step set to %u for DSD rate %u and target PCM rate %u",
369 (unsigned)decimationStep, (unsigned)meta.dsd_sample_rate,
370 (unsigned)meta.sample_rate);
371 }
372
374 switch (meta.bits_per_sample) {
375 case 8: {
376 int8_t buffer8 = static_cast<int8_t>(filteredValue * 127.0f);
378 break;
379 }
380 case 16: {
381 int16_t buffer16 = static_cast<int16_t>(filteredValue * 32767.0f);
383 break;
384 }
385 case 24: {
386 int24_t buffer24 = static_cast<int24_t>(filteredValue * 8388607.0f);
387 pcmBuffer.writeArray((uint8_t*)&buffer24, sizeof(int24_t));
388 break;
389 }
390 case 32: {
391 int32_t buffer32 = static_cast<int32_t>(filteredValue * 2147483647.0f);
393 break;
394 }
395 default:
396 LOGE("Unsupported bits per sample: %d", meta.bits_per_sample);
397 break;
398 }
399 }
400
401 int findTag(const char* tag, const uint8_t* data, size_t len) {
402 int taglen = strlen(tag);
403 for (size_t j = 0; j + taglen <= len; j++) {
404 if (memcmp(tag, data + j, taglen) == 0) {
405 return j;
406 }
407 }
408 return -1;
409 }
410
411 bool parseFMT(const uint8_t* data, size_t len) {
412 TRACEI();
413 if (len < sizeof(DSFFormat)) {
414 LOGE("FMT section too short to parse DSF format header");
415 return false;
416 }
417 DSFFormat* fmt = (DSFFormat*)data;
418 meta.channels = fmt->channelNum;
419 if (meta.channels == 0) meta.channels = fmt->channelType;
420 meta.dsd_sample_rate = fmt->samplingFrequency;
421 meta.block_size_per_channel = fmt->blockSizePerChannel;
423
424 if (meta.channels == 0 || meta.channels > 8) {
425 LOGE("Invalid channel count: %u (must be 1-8)", (unsigned)meta.channels);
426 return false;
427 }
428
429 LOGI("channels: %u, DSD sample rate: %u, block size: %u",
430 (unsigned)meta.channels, (unsigned)meta.dsd_sample_rate,
431 (unsigned)meta.block_size_per_channel);
432 return true;
433 }
434
435 bool parseData(const uint8_t* data, size_t len) {
436 TRACEI();
437 if (len < sizeof(DSFDataHeader)) {
438 LOGE("Data section too short to parse DSF data header");
439 return false;
440 }
441 DSFDataHeader* header = (DSFDataHeader*)data;
442 meta.dsd_data_bytes = header->chunkSize;
443
450 return true;
451 }
452};
453
463class DSFEncoder : public AudioEncoder {
464 public:
465 DSFEncoder() = default;
466 DSFEncoder(DSFMetadata metaData) { setMetaData(metaData); }
467
468 const char* mime() override { return "audio/dsf"; }
469
470 void setOutput(Print& out) override { p_print = &out; }
471
472 void setAudioInfo(AudioInfo from) override {
474 meta.copyFrom(from);
475 }
476
477 void setMetaData(DSFMetadata metaData) {
478 meta = metaData;
480 }
481
482 const DSFMetadata getMetadata() { return meta; }
483
484 bool begin() override {
485 TRACED();
487
490
492 for (int ch = 0; ch < meta.channels; ch++) {
494 }
495
496 chState.resize(meta.channels);
497 for (int ch = 0; ch < meta.channels; ch++) {
499 }
500
501 totalDsdBytes = 0;
502 headerWritten = false;
503 isOpen = true;
504 return true;
505 }
506
507 void end() override {
508 if (!isOpen) return;
510 isOpen = false;
511 }
512
513 size_t write(const uint8_t* data, size_t len) override {
514 if (!isOpen || p_print == nullptr) return 0;
515
516 if (!headerWritten) {
518 headerWritten = true;
519 }
520
521 int bytesPerSample = meta.bits_per_sample / 8;
522 if (meta.bits_per_sample == 24) bytesPerSample = 4;
523 int frameSize = bytesPerSample * meta.channels;
524 if (frameSize == 0) return 0;
525
526 size_t pos = 0;
527 while (pos + frameSize <= len) {
528 for (int ch = 0; ch < meta.channels; ch++) {
529 float sample = readPCMSample(data + pos + ch * bytesPerSample);
530 convertSampleToDSD(ch, sample);
531 }
532 pos += frameSize;
533
534 if (allBlocksFull()) {
536 }
537 }
538
539 return pos;
540 }
541
542 operator bool() override { return isOpen; }
543
544 protected:
546 float dsError1 = 0;
547 float dsError2 = 0;
548 float prevSample = 0;
550 int bitPos = 0;
551 };
552
554 Print* p_print = nullptr;
559 bool headerWritten = false;
560 bool isOpen = false;
561
562 float readPCMSample(const uint8_t* ptr) {
563 switch (meta.bits_per_sample) {
564 case 8:
565 return *reinterpret_cast<const int8_t*>(ptr) / 127.0f;
566 case 16: {
567 int16_t v;
568 memcpy(&v, ptr, sizeof(int16_t));
569 return v / 32767.0f;
570 }
571 case 24: {
572 int24_t v;
573 memcpy(&v, ptr, sizeof(int24_t));
574 return static_cast<float>(static_cast<int32_t>(v)) / 8388607.0f;
575 }
576 case 32: {
577 int32_t v;
578 memcpy(&v, ptr, sizeof(int32_t));
579 return v / 2147483647.0f;
580 }
581 default:
582 return 0.0f;
583 }
584 }
585
586 void convertSampleToDSD(int ch, float currentSample) {
587 float prevSample = chState[ch].prevSample;
588
589 for (uint32_t i = 0; i < oversamplingRatio; i++) {
590 // Linear interpolation between previous and current PCM sample
591 float t = (float)i / oversamplingRatio;
592 float input = prevSample + t * (currentSample - prevSample);
593 input *= 0.5f;
594
595 // 2nd order error-feedback delta-sigma: NTF = (1 - z^-1)^2
596 float shaped = input + 2.0f * chState[ch].dsError1 - chState[ch].dsError2;
597 int bit = (shaped >= 0.0f) ? 1 : 0;
598 float feedback = bit ? 1.0f : -1.0f;
599 float quantError = shaped - feedback;
600
601 if (quantError > 4.0f) quantError = 4.0f;
602 if (quantError < -4.0f) quantError = -4.0f;
603
604 chState[ch].dsError2 = chState[ch].dsError1;
605 chState[ch].dsError1 = quantError;
606
607 // LSB first for DSF format
608 if (bit) {
609 chState[ch].currentByte |= (1 << chState[ch].bitPos);
610 }
611 chState[ch].bitPos++;
612
613 if (chState[ch].bitPos >= 8) {
614 channelBlocks[ch].write(chState[ch].currentByte);
615 chState[ch].currentByte = 0;
616 chState[ch].bitPos = 0;
617 }
618 }
619
620 chState[ch].prevSample = currentSample;
621 }
622
624 for (int ch = 0; ch < meta.channels; ch++) {
625 if (!channelBlocks[ch].isFull()) return false;
626 }
627 return true;
628 }
629
631 for (int ch = 0; ch < meta.channels; ch++) {
633 channelBlocks[ch].available());
634 totalDsdBytes += channelBlocks[ch].available();
635 channelBlocks[ch].reset();
636 }
637 }
638
640 bool hasData = false;
641 for (int ch = 0; ch < meta.channels; ch++) {
642 if (channelBlocks[ch].available() > 0 || chState[ch].bitPos > 0) {
643 hasData = true;
644 break;
645 }
646 }
647 if (!hasData) return;
648
649 for (int ch = 0; ch < meta.channels; ch++) {
650 if (chState[ch].bitPos > 0) {
651 channelBlocks[ch].write(chState[ch].currentByte);
652 chState[ch].currentByte = 0;
653 chState[ch].bitPos = 0;
654 }
655 }
656
657 // Pad to full block size with DSD silence (alternating bit pattern)
658 for (int ch = 0; ch < meta.channels; ch++) {
659 while (!channelBlocks[ch].isFull()) {
660 channelBlocks[ch].write(0x69);
661 }
662 }
664 }
665
668 bool streaming = (dsdDataBytes == 0);
670 sizeof(DSDPrefix) + sizeof(DSFFormat) + sizeof(DSFDataHeader);
671
672 DSDPrefix prefix;
673 memcpy(prefix.id, "DSD ", 4);
674 prefix.chunkSize = sizeof(DSDPrefix);
675 prefix.fileSize = streaming ? 0 : (headerTotal + dsdDataBytes);
676 prefix.metadataOffset = 0;
677
679 memcpy(fmt.id, "fmt ", 4);
680 fmt.chunkSize = sizeof(DSFFormat);
681 fmt.formatVersion = 1;
682 fmt.formatID = 0;
683 fmt.channelType = meta.channels;
684 fmt.channelNum = meta.channels;
685 fmt.samplingFrequency = meta.dsd_sample_rate;
686 fmt.bitsPerSample = 1;
687 fmt.sampleCount = streaming ? 0 : (dsdDataBytes * 8 / meta.channels);
688 fmt.blockSizePerChannel = meta.block_size_per_channel;
689 fmt.reserved = 0;
690
692 memcpy(dataHdr.id, "data", 4);
693 dataHdr.chunkSize = streaming ? 0 : (sizeof(DSFDataHeader) + dsdDataBytes);
694
695 p_print->write((uint8_t*)&prefix, sizeof(prefix));
696 p_print->write((uint8_t*)&fmt, sizeof(fmt));
697 p_print->write((uint8_t*)&dataHdr, sizeof(dataHdr));
698 }
699};
700
701} // namespace audio_tools
#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
Definition Arduino.h:56
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
Print * getOutput()
Definition AudioCodecsBase.h:64
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition AudioCodecsBase.h:28
Encoding of PCM data.
Definition AudioCodecsBase.h:97
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition AudioCodecsBase.h:106
void writeBlocking(Print *out, uint8_t *data, size_t len)
Definition AudioTypes.h:219
Decodes DSF files containing DSD audio and converts to PCM.
Definition CodecDSF.h:93
uint32_t blockPos
Definition CodecDSF.h:162
bool isHeaderAvailable()
Definition CodecDSF.h:142
void setMetaData(DSFMetadata metaData)
Definition CodecDSF.h:132
bool headerParsed
Definition CodecDSF.h:160
void(* infoCallback)(const DSFFormat &fmt)
Definition CodecDSF.h:163
int getFilterStages()
Definition CodecDSF.h:315
DSFMetadata meta
Definition CodecDSF.h:170
void convertDSDToPCM()
Definition CodecDSF.h:254
int getOutputBufferSize()
Definition CodecDSF.h:172
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition CodecDSF.h:100
Vector< SingleBuffer< uint8_t > > channelDsdBuffers
Definition CodecDSF.h:166
bool begin()
Definition CodecDSF.h:119
size_t processDSDData(const uint8_t *data, size_t len, size_t startPos)
Definition CodecDSF.h:212
void end() override
Definition CodecDSF.h:128
const DSFMetadata getMetadata()
Definition CodecDSF.h:130
float clip(float value)
Definition CodecDSF.h:309
int popcount8(uint8_t v)
Definition CodecDSF.h:303
DSFDecoder(DSFMetadata metaData)
Definition CodecDSF.h:96
void setupDecimationStep()
Definition CodecDSF.h:345
bool allChannelsHaveData(int bytesNeeded)
Definition CodecDSF.h:296
SingleBuffer< uint8_t > pcmBuffer
Definition CodecDSF.h:165
bool isActive
Definition CodecDSF.h:161
bool parseData(const uint8_t *data, size_t len)
Definition CodecDSF.h:435
int findTag(const char *tag, const uint8_t *data, size_t len)
Definition CodecDSF.h:401
uint32_t decimationStep
Definition CodecDSF.h:168
Vector< LowPassFilter< float > > channelFilters
Definition CodecDSF.h:167
size_t bufferDSDData(const uint8_t *data, size_t len, size_t startPos)
Definition CodecDSF.h:235
void writePCMSample(float filteredValue)
Definition CodecDSF.h:373
bool parseFMT(const uint8_t *data, size_t len)
Definition CodecDSF.h:411
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition CodecDSF.h:98
size_t processHeader(const uint8_t *data, size_t len)
Definition CodecDSF.h:181
void setInfoCallback(void(*callback)(const DSFFormat &fmt))
Register a callback that receives the raw DSFFormat header after parsing.
Definition CodecDSF.h:138
void setupFilters()
Definition CodecDSF.h:322
size_t write(const uint8_t *data, size_t len)
Definition CodecDSF.h:146
DSF (DSD Stream File) format encoder.
Definition CodecDSF.h:463
void setOutput(Print &out) override
Default output assignment (encoders may override to store Print reference)
Definition CodecDSF.h:470
Vector< ChannelModState > chState
Definition CodecDSF.h:556
uint32_t oversamplingRatio
Definition CodecDSF.h:557
void setMetaData(DSFMetadata metaData)
Definition CodecDSF.h:477
DSFMetadata meta
Definition CodecDSF.h:553
void flushPartialBlocks()
Definition CodecDSF.h:639
void convertSampleToDSD(int ch, float currentSample)
Definition CodecDSF.h:586
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition CodecDSF.h:472
bool headerWritten
Definition CodecDSF.h:559
void end() override
Definition CodecDSF.h:507
const DSFMetadata getMetadata()
Definition CodecDSF.h:482
size_t write(const uint8_t *data, size_t len) override
Definition CodecDSF.h:513
bool isOpen
Definition CodecDSF.h:560
float readPCMSample(const uint8_t *ptr)
Definition CodecDSF.h:562
bool allBlocksFull()
Definition CodecDSF.h:623
uint64_t totalDsdBytes
Definition CodecDSF.h:558
const char * mime() override
Provides the mime type of the encoded result.
Definition CodecDSF.h:468
void writeBlockSet()
Definition CodecDSF.h:630
DSFEncoder(DSFMetadata metaData)
Definition CodecDSF.h:466
bool begin() override
Definition CodecDSF.h:484
Print * p_print
Definition CodecDSF.h:554
Vector< SingleBuffer< uint8_t > > channelBlocks
Definition CodecDSF.h:555
void writeDSFHeader()
Definition CodecDSF.h:666
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:184
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:218
int available() override
provides the number of entries that are available to read
Definition Buffers.h:245
bool isFull() override
checks if the buffer is full
Definition Buffers.h:252
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:213
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
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition Int24_4bytes_t.h:22
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
int24_4bytes_t int24_t
Definition int24_t.h:12
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
void copyFrom(AudioInfo info)
Same as set.
Definition AudioTypes.h:101
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
float prevSample
Definition CodecDSF.h:548
uint8_t currentByte
Definition CodecDSF.h:549
float dsError2
Definition CodecDSF.h:547
float dsError1
Definition CodecDSF.h:546
int bitPos
Definition CodecDSF.h:550
Metadata structure for DSF (DSD Stream File) format.
Definition CodecDSF.h:32
uint64_t dsd_data_bytes
Total size of DSD data in bytes (0 for streaming mode)
Definition CodecDSF.h:38
bool is_raw
When true, output de-interleaved DSD bitstream instead of converting to PCM.
Definition CodecDSF.h:52
int output_buffer_size
PCM output buffer size in bytes (must be >= one frame)
Definition CodecDSF.h:50
uint32_t dsd_sample_rate
DSD sample rate in Hz (e.g. 2822400 for DSD64, 5644800 for DSD128)
Definition CodecDSF.h:36
uint32_t block_size_per_channel
DSF block size per channel in bytes (from file header, typically 4096)
Definition CodecDSF.h:44
int filter_stages
Number of cascaded Butterworth biquad filter stages (1-3), 0 to disable filtering.
Definition CodecDSF.h:48
uint64_t pcm_frames
Estimated number of PCM frames after DSD-to-PCM conversion.
Definition CodecDSF.h:40
float filter_cutoff
Anti-aliasing filter cutoff as fraction of sample_rate (~0.45 = 90% of Nyquist at 44....
Definition CodecDSF.h:46
DSFMetadata(int rate)
Definition CodecDSF.h:34
float duration_sec
Approximate audio duration in seconds.
Definition CodecDSF.h:42
enum VBanDataTypeList __attribute__