arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
CodecADPCM.h
1#pragma once
2#include "ADPCM.h" // https://github.com/pschatzmann/adpcm
3#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4
5namespace audio_tools {
6
15 public:
16 ADPCMDecoder(AVCodecID id, int blockSize = ADAPCM_DEFAULT_BLOCK_SIZE) {
17 if (id == AV_CODEC_ID_ADPCM_IMA_AMV) {
18 info.sample_rate = 22050;
19 info.channels = 1;
20 info.bits_per_sample = 16;
21 }
22 p_decoder = adpcm_ffmpeg::ADPCMDecoderFactory::create(id);
23 if (p_decoder != nullptr) {
24 p_decoder->setCodecID(id);
25 p_decoder->setBlockSize(blockSize);
26 } else {
27 LOGE("Decoder not implemented");
28 }
29 }
30
31 // defines the block size
32 void setBlockSize(int blockSize) override {
33 if (p_decoder == nullptr) return;
34 p_decoder->setBlockSize(blockSize);
35 }
36
39 int blockSize() {
40 if (p_decoder == nullptr) return 0;
41 return p_decoder->blockSize();
42 }
43
46 int frameSize() {
47 if (p_decoder == nullptr) return 0;
48 return p_decoder->frameSize() * 2;
49 }
50
51 bool begin() override {
52 TRACEI();
53 if (p_decoder == nullptr) return false;
54 if (is_started) return true;
55 current_byte = 0;
56 LOGI("sample_rate: %d, channels: %d", info.sample_rate, info.channels);
57 p_decoder->begin(info.sample_rate, info.channels);
58 LOGI("frameSize: %d", (int)frameSize());
59 LOGI("blockSize: %d", (int)blockSize());
60 block_size = p_decoder->blockSize();
61 assert(block_size > 0);
62 assert(p_decoder->frameSize() > 0);
63 adpcm_block.resize(block_size);
64
65 notifyAudioChange(info);
66 is_started = true;
67 return true;
68 }
69
70 void end() override {
71 TRACEI();
72 if (p_decoder != nullptr) p_decoder->end();
73 adpcm_block.resize(0);
74 is_started = false;
75 }
76
77 virtual void setOutput(Print &out_stream) override { p_print = &out_stream; }
78
79 virtual size_t write(const uint8_t *data, size_t len) override {
80 TRACED();
81
82 uint8_t *input_buffer8 = (uint8_t *)data;
83 LOGD("write: %d", (int)len);
84 for (int j = 0; j < len; j++) {
85 decode(input_buffer8[j]);
86 }
87 return len;
88 }
89
90 void flush() {
91 if (p_decoder != nullptr) p_decoder->flush();
92 }
93
94 operator bool() override { return is_started; }
95
96 protected:
97 adpcm_ffmpeg::ADPCMDecoder *p_decoder = nullptr;
98 Vector<uint8_t> adpcm_block;
99 Print *p_print = nullptr;
100 int current_byte = 0;
101 int block_size = 0;
102 bool is_started = false;
103
104 virtual bool decode(uint8_t byte) {
105 if (p_decoder == nullptr) return false;
106 adpcm_block[current_byte++] = byte;
107
108 if (current_byte >= block_size) {
109 TRACED();
110 adpcm_ffmpeg::AVFrame &frame =
111 p_decoder->decode(&adpcm_block[0], block_size);
112 // print the result
113 int16_t *data = (int16_t *)frame.data[0];
114 size_t byte_count = frame.nb_samples * sizeof(int16_t) * info.channels;
115 size_t written = p_print->write((uint8_t *)data, byte_count);
116 if (written != byte_count) {
117 LOGE("decode %d -> %d -> %d", block_size, (int)byte_count,
118 (int)written);
119 } else {
120 LOGD("decode %d -> %d -> %d", block_size, (int)byte_count,
121 (int)written);
122 }
123
124 // restart from array begin
125 current_byte = 0;
126 }
127 return true;
128 }
129};
130
139 public:
140 ADPCMEncoder(AVCodecID id, int blockSize = ADAPCM_DEFAULT_BLOCK_SIZE) {
141 if (id == AV_CODEC_ID_ADPCM_IMA_AMV) {
142 info.sample_rate = 22050;
143 info.channels = 1;
144 info.bits_per_sample = 16;
145 }
146 p_encoder = adpcm_ffmpeg::ADPCMEncoderFactory::create(id);
147 if (p_encoder != nullptr) {
148 p_encoder->setCodecID(id);
149 p_encoder->setBlockSize(blockSize);
150 } else {
151 LOGE("Encoder not implemented");
152 }
153 }
154
157 int blockSize() override {
158 if (p_encoder == nullptr) return 0;
159 return p_encoder->blockSize();
160 }
161
164 int frameSize() {
165 if (p_encoder == nullptr) return 0;
166 return p_encoder->frameSize() * 2;
167 }
168
169 bool begin() override {
170 TRACEI();
171 if (p_encoder == nullptr) return false;
172 if (is_started) return true;
173 LOGI("sample_rate: %d, channels: %d", info.sample_rate, info.channels);
174 p_encoder->begin(info.sample_rate, info.channels);
175 LOGI("frameSize: %d", (int)frameSize());
176 LOGI("blockSize: %d", (int)blockSize());
177 assert(info.sample_rate != 0);
178 assert(p_encoder->frameSize() != 0);
179 total_samples = p_encoder->frameSize() * info.channels;
180 pcm_block.resize(total_samples);
181 current_sample = 0;
182
183 is_started = true;
184 return true;
185 }
186
187 void end() override {
188 TRACEI();
189 pcm_block.resize(0);
190 if (p_encoder == nullptr) return;
191 p_encoder->end();
192 is_started = false;
193 }
194
195 const char *mime() override { return "audio/adpcm"; }
196
197 void setOutput(Print &out_stream) override { p_print = &out_stream; }
198
199 operator bool() override { return is_started; }
200
201 size_t write(const uint8_t *data, size_t len) override {
202 LOGD("write: %d", (int)len);
203 int16_t *data16 = (int16_t *)data;
204 for (int j = 0; j < len / 2; j++) {
205 encode(data16[j]);
206 }
207 return len;
208 }
209
210 protected:
211 adpcm_ffmpeg::ADPCMEncoder *p_encoder = nullptr;
212 Vector<int16_t> pcm_block;
213 Print *p_print = nullptr;
214 bool is_started = false;
215 int current_sample = 0;
216 int total_samples = 0;
217
218 virtual bool encode(int16_t sample) {
219 if (p_encoder == nullptr) return false;
220 pcm_block[current_sample++] = sample;
221 if (current_sample >= total_samples) {
222 TRACED();
223 adpcm_ffmpeg::AVPacket &packet =
224 p_encoder->encode(&pcm_block[0], total_samples);
225 if (packet.size > 0) {
226 size_t written = p_print->write(packet.data, packet.size);
227 if (written != packet.size) {
228 LOGE("encode %d->%d->%d", 2 * total_samples, (int)packet.size,
229 (int)written);
230 } else {
231 LOGD("encode %d->%d->%d", 2 * total_samples, (int)packet.size,
232 (int)written);
233 }
234 }
235 // restart from array begin
236 current_sample = 0;
237 }
238 return true;
239 }
240};
241
242} // namespace audio_tools
Decoder for ADPCM. Depends on https://github.com/pschatzmann/adpcm.
Definition CodecADPCM.h:14
int frameSize()
Definition CodecADPCM.h:46
int blockSize()
Definition CodecADPCM.h:39
virtual void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition CodecADPCM.h:77
Encoder for ADPCM - Depends on https://github.com/pschatzmann/adpcm>
Definition CodecADPCM.h:138
int frameSize()
Definition CodecADPCM.h:164
const char * mime() override
Provides the mime type of the encoded result.
Definition CodecADPCM.h:195
int blockSize() override
Definition CodecADPCM.h:157
Definition AudioCodecsBase.h:106
Definition AudioCodecsBase.h:111
Definition NoArduino.h:62
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59