Skip to content

Commit b27229a

Browse files
committed
WAVDecoder 8 bit support
1 parent 6273bea commit b27229a

File tree

1 file changed

+44
-36
lines changed

1 file changed

+44
-36
lines changed

src/AudioTools/AudioCodecs/CodecWAV.h

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ class WAVDecoder : public AudioDecoder {
304304
TRACED();
305305
header.clear();
306306
setupEncodedAudio();
307+
byte_buffer.reset();
307308
buffer24.reset();
308309
isFirst = true;
309310
active = true;
@@ -312,6 +313,7 @@ class WAVDecoder : public AudioDecoder {
312313

313314
void end() override {
314315
TRACED();
316+
byte_buffer.reset();
315317
buffer24.reset();
316318
active = false;
317319
}
@@ -326,6 +328,11 @@ class WAVDecoder : public AudioDecoder {
326328
info.bits_per_sample == 8) {
327329
info.bits_per_sample = 16;
328330
}
331+
// 32 bits gives better result
332+
if (convert24 && info.format == AudioFormat::PCM &&
333+
info.bits_per_sample == 24) {
334+
info.bits_per_sample = 32;
335+
}
329336
return info;
330337
}
331338

@@ -350,6 +357,16 @@ class WAVDecoder : public AudioDecoder {
350357

351358
virtual operator bool() override { return active; }
352359

360+
/// Convert 8 bit to 16 bit PCM data
361+
void setConvert8Bit(bool enable) {
362+
convert8to16 = enable;
363+
}
364+
365+
/// Convert 24 bit (3 byte) to 32 bit (4 byte) PCM data
366+
void setConvert24Bit(bool enable) {
367+
convert24 = enable;
368+
}
369+
353370
protected:
354371
WAVHeader header;
355372
bool isFirst = true;
@@ -358,15 +375,17 @@ class WAVDecoder : public AudioDecoder {
358375
AudioFormat decoder_format = AudioFormat::PCM;
359376
AudioDecoderExt *p_decoder = nullptr;
360377
EncodedAudioOutput dec_out;
361-
SingleBuffer<uint8_t> buffer24;
378+
SingleBuffer<uint8_t> byte_buffer{0};
379+
SingleBuffer<int32_t> buffer24{0};
362380
bool convert8to16 = true; // Optional conversion flag
381+
bool convert24 = true; // Optional conversion flag
363382

364383
Print &out() { return p_decoder == nullptr ? *p_print : dec_out; }
365384

366385
virtual size_t write_out(const uint8_t *in_ptr, size_t in_size) {
367386
// check if we need to convert int24 data from 3 bytes to 4 bytes
368387
size_t result = 0;
369-
if (header.audioInfo().format == AudioFormat::PCM &&
388+
if (convert24 && header.audioInfo().format == AudioFormat::PCM &&
370389
header.audioInfo().bits_per_sample == 24 && sizeof(int24_t) == 4) {
371390
write_out_24(in_ptr, in_size);
372391
result = in_size;
@@ -392,51 +411,40 @@ class WAVDecoder : public AudioDecoder {
392411
for (size_t i = 0; i < current_batch; ++i) {
393412
out_buf[i] = ((int16_t)in_ptr[offset + i] - 128) << 8;
394413
}
395-
size_t written =
396-
out().write((uint8_t *)out_buf, current_batch * sizeof(int16_t));
397-
total_written += written / sizeof(int16_t);
414+
writeDataT<int16_t>(&out(), out_buf, current_batch);
398415
offset += current_batch;
399416
samples_remaining -= current_batch;
400417
}
401-
return total_written / 2;
418+
return in_size;
402419
}
403420

404-
// convert int24 to int32
421+
// convert 3 byte int24 to 4 byte int32
405422
size_t write_out_24(const uint8_t *in_ptr, size_t in_size) {
406-
// make sure we can store a frame of 24bit (3bytes)
407-
AudioInfo &info = header.audioInfo();
408-
// in_size might be not a multiple of 3, so we use a buffer for a single
409-
// frame
410-
buffer24.resize(info.channels * 3);
411-
int result = 0;
412-
int32_t frame[info.channels];
413-
uint8_t val24[3] = {0};
414-
415-
// add all bytes to buffer
416-
for (int j = 0; j < in_size; j++) {
417-
buffer24.write(in_ptr[j]);
418-
// if buffer is full convert and output
419-
if (buffer24.availableForWrite() == 0) {
420-
for (int ch = 0; ch < info.channels; ch++) {
421-
buffer24.readArray((uint8_t *)&val24[0], 3);
422-
frame[ch] = interpret24bitAsInt32(val24);
423-
// LOGW("%d", frame[ch]);
423+
// store 1 sample
424+
const size_t batch_size = 256;
425+
buffer24.resize(batch_size);
426+
byte_buffer.resize(3);
427+
428+
for (size_t i = 0; i < in_size; i++) {
429+
// Add byte to buffer
430+
byte_buffer.write(in_ptr[i]);
431+
432+
// Process complete sample when buffer is full
433+
if (byte_buffer.isFull()) {
434+
int24_3bytes_t sample24{byte_buffer.data()};
435+
int32_t converted_sample = sample24.scale32();
436+
buffer24.write(converted_sample);
437+
if (buffer24.isFull()) {
438+
writeDataT<int32_t>(&out(), buffer24.data(), buffer24.available());
439+
buffer24.reset();
424440
}
425-
assert(buffer24.available() == 0);
426-
buffer24.reset();
427-
size_t written = out().write((uint8_t *)frame, sizeof(frame));
428-
assert(written == sizeof(frame));
429-
result += written;
441+
byte_buffer.reset();
430442
}
431443
}
432-
return result;
444+
445+
return in_size;
433446
}
434447

435-
int32_t interpret24bitAsInt32(uint8_t *byteArray) {
436-
return ((static_cast<int32_t>(byteArray[2]) << 24) |
437-
(static_cast<int32_t>(byteArray[1]) << 16) |
438-
(static_cast<int32_t>(byteArray[0]) << 8));
439-
}
440448

441449
/// Decodes the header data: Returns the start pos of the data
442450
int decodeHeader(uint8_t *in_ptr, size_t in_size) {

0 commit comments

Comments
 (0)