3#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4#include "AudioTools/AudioCodecs/AudioEncoded.h"
6#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
8#define READ_BUFFER_SIZE 512
9#define MAX_WAV_HEADER_LEN 200
30 bool is_streamed =
true;
31 bool is_valid =
false;
32 uint32_t data_length = 0;
33 uint32_t file_size = 0;
37static const char *wav_mime =
"audio/wav";
52 int write(uint8_t *data,
size_t data_len) {
58 LOGI(
"WAVHeader::begin: %u", (
unsigned)buffer.
available());
62 if (!setPos(
"RIFF"))
return false;
63 headerInfo.file_size = read_int32();
64 if (!setPos(
"WAVE"))
return false;
65 if (!setPos(
"fmt "))
return false;
66 int fmt_length = read_int32();
68 headerInfo.channels = read_int16();
69 headerInfo.sample_rate = read_int32();
70 headerInfo.byte_rate = read_int32();
71 headerInfo.block_align = read_int16();
72 headerInfo.bits_per_sample = read_int16();
73 if (!setPos(
"data"))
return false;
74 headerInfo.data_length = read_int32();
75 if (headerInfo.data_length == 0 || headerInfo.data_length >= 0x7fff0000) {
76 headerInfo.is_streamed =
true;
77 headerInfo.data_length = ~0;
88 return pos > 0 && buffer.
available() >= pos;
99 return pos > 0 ? pos + 8 : 0;
110 writeRiffHeader(buffer);
112 writeDataHeader(buffer);
134 for (
int j = 0; j < buffer.
available(); j++) {
135 char c = (char)buffer.
data()[j];
141 LOGI(
"Header: %s", msg);
149 bool setPos(
const char *
id) {
150 int id_len = strlen(
id);
151 int pos = indexOf(
id);
152 if (pos < 0)
return false;
153 data_pos = pos + id_len;
157 int indexOf(
const char *str) {
158 return StrView((
char *)buffer.
data(), MAX_WAV_HEADER_LEN,
163 uint32_t read_tag() {
165 tag = (tag << 8) | getChar();
166 tag = (tag << 8) | getChar();
167 tag = (tag << 8) | getChar();
168 tag = (tag << 8) | getChar();
172 uint32_t getChar32() {
return getChar(); }
174 uint32_t read_int32() {
176 value |= getChar32() << 0;
177 value |= getChar32() << 8;
178 value |= getChar32() << 16;
179 value |= getChar32() << 24;
183 uint16_t read_int16() {
185 value |= getChar() << 0;
186 value |= getChar() << 8;
192 for (i = 0; i < n; i++) getChar();
196 if (data_pos < buffer.size())
197 return buffer.
data()[data_pos++];
202 void seek(
long int offset,
int origin) {
203 if (origin == SEEK_SET) {
205 }
else if (origin == SEEK_CUR) {
210 size_t tell() {
return data_pos; }
212 bool eof() {
return data_pos >= buffer.size() - 1; }
215 LOGI(
"WAVHeader sound_pos: %d",
getDataPos());
216 LOGI(
"WAVHeader channels: %d ", headerInfo.
channels);
218 LOGI(
"WAVHeader sample_rate: %d ", (
int)headerInfo.
sample_rate);
219 LOGI(
"WAVHeader format: %d", (
int)headerInfo.format);
222 void writeRiffHeader(BaseBuffer<uint8_t> &buffer) {
223 buffer.writeArray((uint8_t *)
"RIFF", 4);
224 write32(buffer, headerInfo.file_size - 8);
225 buffer.writeArray((uint8_t *)
"WAVE", 4);
228 void writeFMT(BaseBuffer<uint8_t> &buffer) {
229 uint16_t fmt_len = 16;
230 buffer.writeArray((uint8_t *)
"fmt ", 4);
231 write32(buffer, fmt_len);
232 write16(buffer, (uint16_t)headerInfo.format);
233 write16(buffer, headerInfo.
channels);
235 write32(buffer, headerInfo.byte_rate);
236 write16(buffer, headerInfo.block_align);
240 void write32(BaseBuffer<uint8_t> &buffer, uint64_t value) {
241 buffer.writeArray((uint8_t *)&value, 4);
244 void write16(BaseBuffer<uint8_t> &buffer, uint16_t value) {
245 buffer.writeArray((uint8_t *)&value, 2);
248 void writeDataHeader(BaseBuffer<uint8_t> &buffer) {
249 buffer.writeArray((uint8_t *)
"data", 4);
250 write32(buffer, headerInfo.file_size);
251 int offset = headerInfo.offset;
253 uint8_t empty[offset];
254 memset(empty, 0, offset);
255 buffer.writeArray(empty, offset);
298 decoder_format = fmt;
326 const char *
mime() {
return wav_mime; }
334 if (convert8to16 && info.format == AudioFormat::PCM &&
339 if (convert24 && info.format == AudioFormat::PCM &&
347 virtual size_t write(
const uint8_t *data,
size_t len)
override {
354 if (data_start == 0)
return len;
356 result = data_start +
357 write_out((uint8_t *)data + data_start, len - data_start);
359 }
else if (isValid) {
360 result = write_out((uint8_t *)data, len);
367 virtual operator bool()
override {
return active; }
371 convert8to16 = enable;
388 SingleBuffer<int32_t> buffer24{0};
389 bool convert8to16 =
true;
390 bool convert24 =
true;
391 const size_t batch_size = 256;
393 Print &out() {
return p_decoder ==
nullptr ? *p_print : dec_out; }
395 virtual size_t write_out(
const uint8_t *in_ptr,
size_t in_size) {
398 if (convert24 && header.
audioInfo().format == AudioFormat::PCM &&
402 }
else if (convert8to16 && header.
audioInfo().format == AudioFormat::PCM &&
406 result = out().write(in_ptr, in_size);
413 size_t total_written = 0;
414 size_t samples_remaining = in_size;
416 int16_t out_buf[batch_size];
417 while (samples_remaining > 0) {
418 size_t current_batch =
419 samples_remaining > batch_size ? batch_size : samples_remaining;
420 for (
size_t i = 0; i < current_batch; ++i) {
421 out_buf[i] = ((int16_t)in_ptr[offset + i] - 128) << 8;
423 writeDataT<int16_t>(&out(), out_buf, current_batch);
424 offset += current_batch;
425 samples_remaining -= current_batch;
433 buffer24.
resize(batch_size);
436 for (
size_t i = 0; i < in_size; i++) {
438 byte_buffer.
write(in_ptr[i]);
441 if (byte_buffer.
isFull()) {
443 int32_t converted_sample = sample24.scale32();
444 buffer24.
write(converted_sample);
446 writeDataT<int32_t>(&out(), buffer24.
data(), buffer24.
available());
459 int result = in_size;
461 int written = header.
write(in_ptr, in_size);
463 LOGW(
"WAV header misses 'data' section in len: %d",
469 if (!header.
parse()) {
470 LOGE(
"WAV header parsing failed");
478 LOGI(
"WAV data_length: %u", (
unsigned)header.
audioInfo().data_length);
479 LOGI(
"WAV is_streamed: %d", header.
audioInfo().is_streamed);
480 LOGI(
"WAV is_valid: %s", header.
audioInfo().is_valid ?
"true" :
"false");
484 isValid = format == decoder_format;
487 if (p_decoder !=
nullptr) {
488 int block_size = header.
audioInfo().block_align;
489 p_decoder->setBlockSize(block_size);
494 notifyAudioChange(bi);
496 LOGE(
"WAV format not supported: %d", (
int)format);
501 void setupEncodedAudio() {
502 if (p_decoder !=
nullptr) {
503 assert(p_print !=
nullptr);
505 dec_out.setDecoder(p_decoder);
536 audioInfo.format = fmt;
547 const char *
mime()
override {
return wav_mime; }
552 info.format = AudioFormat::PCM;
556 info.is_streamed =
true;
557 info.is_valid =
true;
558 info.data_length = 0x7fff0000;
559 info.file_size = info.data_length + 36;
577 LOGI(
"sample_rate: %d", (
int)audioInfo.
sample_rate);
578 LOGI(
"channels: %d", audioInfo.
channels);
582 if (audioInfo.format == AudioFormat::PCM) {
583 audioInfo.block_align =
586 if (audioInfo.is_streamed || audioInfo.data_length == 0 ||
587 audioInfo.data_length >= 0x7fff0000) {
588 LOGI(
"is_streamed! because length is %u",
589 (
unsigned)audioInfo.data_length);
590 audioInfo.is_streamed =
true;
591 audioInfo.data_length = ~0;
593 size_limit = audioInfo.data_length;
594 LOGI(
"size_limit is %d", (
int)size_limit);
609 header_written =
false;
615 void end()
override { is_open =
false; }
618 virtual size_t write(
const uint8_t *data,
size_t len)
override {
620 LOGE(
"The WAVEncoder is not open - please call begin()");
624 if (p_print ==
nullptr) {
625 LOGE(
"No output stream was provided");
629 if (!header_written) {
630 LOGI(
"Writing Header");
633 audioInfo.file_size -= len;
634 header_written =
true;
638 Print *p_out = p_encoder ==
nullptr ? p_print : &enc_out;
640 if (audioInfo.is_streamed) {
641 result = p_out->write((uint8_t *)data, len);
642 }
else if (size_limit > 0) {
643 size_t write_size = min((
size_t)len, (
size_t)size_limit);
644 result = p_out->write((uint8_t *)data, write_size);
645 size_limit -= result;
647 if (size_limit <= 0) {
648 LOGI(
"The defined size was written - so we close the WAVEncoder now");
656 operator bool()
override {
return is_open; }
666 Print *p_print =
nullptr;
670 int64_t size_limit = 0;
671 bool header_written =
false;
672 volatile bool is_open =
false;
674 void setupEncodedAudio() {
675 if (p_encoder !=
nullptr) {
676 assert(p_print !=
nullptr);
678 enc_out.setEncoder(p_encoder);
682 audioInfo.block_align = p_encoder->blockSize();
AudioFormat
Audio format codes used by Microsoft e.g. in avi or wav files.
Definition AudioFormat.h:19