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() = default;
17
18 ADPCMDecoder(AVCodecID id, int blockSize = ADAPCM_DEFAULT_BLOCK_SIZE) {
19 setBlockSize(blockSize);
20 setId(id);
21 }
22
25 if (p_decoder) delete p_decoder;
26 }
27
28 // (re) defines the codec id: set the block size first
29 void setId(AVCodecID id) {
30 codec_id = id;
31 if (p_decoder != nullptr) {
33 }
34 }
35
36 // defines the block size (= size of encoded frame)
37 void setBlockSize(int blockSize) override {
38 block_size = blockSize;
39 if (p_decoder == nullptr) return;
40 p_decoder->setBlockSize(blockSize);
41 }
42
45 int blockSize() {
46 if (p_decoder == nullptr) return block_size;
47 return p_decoder->blockSize();
48 }
49
52 int frameSize() {
53 if (p_decoder == nullptr) return 0;
54 return p_decoder->frameSize() * 2;
55 }
56
57 bool begin() override {
58 TRACEI();
59 if (p_decoder == nullptr) {
61 }
62 if (is_started) return true;
63 current_byte = 0;
64 LOGI("sample_rate: %d, channels: %d", info.sample_rate, info.channels);
65 p_decoder->begin(info.sample_rate, info.channels);
66 LOGI("frameSize: %d", (int)frameSize());
67 LOGI("blockSize: %d", (int)blockSize());
68 block_size = p_decoder->blockSize();
69 assert(block_size > 0);
70 assert(p_decoder->frameSize() > 0);
71 adpcm_block.resize(block_size);
72
73 notifyAudioChange(info);
74 is_started = true;
75 return true;
76 }
77
78 void end() override {
79 TRACEI();
80 if (p_decoder != nullptr) p_decoder->end();
81 adpcm_block.resize(0);
82 is_started = false;
83 }
84
85 virtual void setOutput(Print &out_stream) override { p_print = &out_stream; }
86
87 virtual size_t write(const uint8_t *data, size_t len) override {
88 TRACED();
89
90 uint8_t *input_buffer8 = (uint8_t *)data;
91 LOGD("write: %d", (int)len);
92 for (int j = 0; j < len; j++) {
93 decode(input_buffer8[j]);
94 }
95 return len;
96 }
97
98 void flush() {
99 if (p_decoder != nullptr) p_decoder->flush();
100 }
101
102 operator bool() override { return is_started; }
103
104 protected:
105 adpcm_ffmpeg::ADPCMDecoder *p_decoder = nullptr;
106 Vector<uint8_t> adpcm_block;
107 Print *p_print = nullptr;
108 int current_byte = 0;
109 int block_size = ADAPCM_DEFAULT_BLOCK_SIZE;
110 AVCodecID codec_id = AV_CODEC_ID_ADPCM_MS;
111 bool is_started = false;
112
113 virtual bool decode(uint8_t byte) {
114 if (p_decoder == nullptr) return false;
115 adpcm_block[current_byte++] = byte;
116
117 if (current_byte >= block_size) {
118 TRACED();
119 adpcm_ffmpeg::AVFrame &frame =
120 p_decoder->decode(&adpcm_block[0], block_size);
121 // print the result
122 int16_t *data = (int16_t *)frame.data[0];
123 size_t byte_count = frame.nb_samples * sizeof(int16_t) * info.channels;
124 size_t written = p_print->write((uint8_t *)data, byte_count);
125 if (written != byte_count) {
126 LOGE("decode %d -> %d -> %d", block_size, (int)byte_count,
127 (int)written);
128 } else {
129 LOGD("decode %d -> %d -> %d", block_size, (int)byte_count,
130 (int)written);
131 }
132
133 // restart from array begin
134 current_byte = 0;
135 }
136 return true;
137 }
138
141 // delete the old decoder
142 if (p_decoder != nullptr) {
143 p_decoder->end();
144 delete p_decoder;
145 p_decoder = nullptr;
146 }
147
148 if (codec_id == AV_CODEC_ID_ADPCM_IMA_AMV) {
149 info.sample_rate = 22050;
150 info.channels = 1;
151 info.bits_per_sample = 16;
152 }
153 p_decoder = adpcm_ffmpeg::ADPCMDecoderFactory::create(codec_id);
154 if (p_decoder != nullptr) {
155 p_decoder->setCodecID(codec_id);
156 p_decoder->setBlockSize(block_size);
157 } else {
158 LOGE("Decoder not implemented");
159 }
160 }
161};
162
171 public:
172 ADPCMEncoder() = default;
173
174 ADPCMEncoder(AVCodecID id, int blockSize = ADAPCM_DEFAULT_BLOCK_SIZE) {
175 setId(id);
177 }
178
181 if (p_encoder != nullptr) delete p_encoder;
182 }
183
185 void setId(AVCodecID id) {
186 codec_id = id;
187 if (p_encoder != nullptr) {
189 }
190 }
191
194 block_size = blockSize;
195 if (p_encoder == nullptr) return;
196 p_encoder->setBlockSize(blockSize);
197 }
198
201 int blockSize() override {
202 if (p_encoder == nullptr) return 0;
203 return p_encoder->blockSize();
204 }
205
208 int frameSize() {
209 if (p_encoder == nullptr) return 0;
210 return p_encoder->frameSize() * 2;
211 }
212
213 bool begin() override {
214 TRACEI();
215 if (p_encoder == nullptr) {
217 };
218 if (is_started) return true;
219 LOGI("sample_rate: %d, channels: %d", info.sample_rate, info.channels);
220 p_encoder->begin(info.sample_rate, info.channels);
221 LOGI("frameSize: %d", (int)frameSize());
222 LOGI("blockSize: %d", (int)blockSize());
223 assert(info.sample_rate != 0);
224 assert(p_encoder->frameSize() != 0);
225 total_samples = p_encoder->frameSize() * info.channels;
226 pcm_block.resize(total_samples);
227 current_sample = 0;
228
229 is_started = true;
230 return true;
231 }
232
233 void end() override {
234 TRACEI();
235 pcm_block.resize(0);
236 if (p_encoder == nullptr) return;
237 p_encoder->end();
238 is_started = false;
239 }
240
241 const char *mime() override { return "audio/adpcm"; }
242
243 void setOutput(Print &out_stream) override { p_print = &out_stream; }
244
245 operator bool() override { return is_started; }
246
247 size_t write(const uint8_t *data, size_t len) override {
248 LOGD("write: %d", (int)len);
249 int16_t *data16 = (int16_t *)data;
250 for (int j = 0; j < len / 2; j++) {
251 encode(data16[j]);
252 }
253 return len;
254 }
255
256 protected:
257 AVCodecID codec_id = AV_CODEC_ID_ADPCM_MS;
258 adpcm_ffmpeg::ADPCMEncoder *p_encoder = nullptr;
259 Vector<int16_t> pcm_block;
260 Print *p_print = nullptr;
261 bool is_started = false;
262 int current_sample = 0;
263 int total_samples = 0;
264 int current_id = -1;
265 int block_size = ADAPCM_DEFAULT_BLOCK_SIZE;
266
267 virtual bool encode(int16_t sample) {
268 if (p_encoder == nullptr) return false;
269 pcm_block[current_sample++] = sample;
270 if (current_sample >= total_samples) {
271 TRACED();
272 adpcm_ffmpeg::AVPacket &packet =
273 p_encoder->encode(&pcm_block[0], total_samples);
274 if (packet.size > 0) {
275 size_t written = p_print->write(packet.data, packet.size);
276 if (written != packet.size) {
277 LOGE("encode %d->%d->%d", 2 * total_samples, (int)packet.size,
278 (int)written);
279 } else {
280 LOGD("encode %d->%d->%d", 2 * total_samples, (int)packet.size,
281 (int)written);
282 }
283 }
284 // restart from array begin
285 current_sample = 0;
286 }
287 return true;
288 }
289
292 // delete the old encoder
293 if (p_encoder != nullptr) {
294 p_encoder->end();
295 delete p_encoder;
296 p_encoder = nullptr;
297 }
298
299 if (codec_id == AV_CODEC_ID_ADPCM_IMA_AMV) {
300 info.sample_rate = 22050;
301 info.channels = 1;
302 info.bits_per_sample = 16;
303 }
304 p_encoder = adpcm_ffmpeg::ADPCMEncoderFactory::create(codec_id);
305 if (p_encoder != nullptr) {
306 p_encoder->setCodecID(codec_id);
307 p_encoder->setBlockSize(block_size);
308 } else {
309 LOGE("Encoder not implemented");
310 }
311 }
312};
313
314} // namespace audio_tools
Decoder for ADPCM. Depends on https://github.com/pschatzmann/adpcm.
Definition CodecADPCM.h:14
int frameSize()
Definition CodecADPCM.h:52
int blockSize()
Definition CodecADPCM.h:45
~ADPCMDecoder()
Destructor.
Definition CodecADPCM.h:24
virtual void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition CodecADPCM.h:85
void setImplementation()
change the decoder implementation
Definition CodecADPCM.h:140
Encoder for ADPCM - Depends on https://github.com/pschatzmann/adpcm>
Definition CodecADPCM.h:170
int frameSize()
Definition CodecADPCM.h:208
void setBlockSize(int blockSize)
(re) defines the block size
Definition CodecADPCM.h:193
bool setImplementation()
change the encoder implementation
Definition CodecADPCM.h:291
~ADPCMEncoder()
Destructor.
Definition CodecADPCM.h:180
void setId(AVCodecID id)
(re) defines the codec id
Definition CodecADPCM.h:185
const char * mime() override
Provides the mime type of the encoded result.
Definition CodecADPCM.h:241
int blockSize() override
Definition CodecADPCM.h:201
Definition AudioCodecsBase.h:112
int id
custom id to be used by application
Definition AudioCodecsBase.h:62
Definition AudioCodecsBase.h:117
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