arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
CodecCodec2.h
Go to the documentation of this file.
1
18#pragma once
19
20#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
21#include "codec2.h"
22
23
24namespace audio_tools {
25
27int getCodec2Mode(int bits_per_second) {
28 switch (bits_per_second) {
29 case 3200:
30 return CODEC2_MODE_3200;
31 case 2400:
32 return CODEC2_MODE_2400;
33 case 1600:
34 return CODEC2_MODE_1600;
35 case 1400:
36 return CODEC2_MODE_1400;
37 case 1300:
38 return CODEC2_MODE_1300;
39 case 1200:
40 return CODEC2_MODE_1200;
41 case 700:
42 return CODEC2_MODE_700C;
43 case 450:
44 return CODEC2_MODE_450;
45 default:
46 LOGE(
47 "Unsupported sample rate: use 3200, 2400, 1600, 1400, 1300, 1200, "
48 "700 or 450");
49 return -1;
50 }
51}
52
62 public:
63 Codec2Decoder(int bps = 3200) {
64 info.sample_rate = 8000;
65 info.channels = 1;
66 info.bits_per_sample = 16;
68 }
71 virtual void setBitsPerSecond(int bps) { bits_per_second = bps; }
72
73 int bitsPerSecond() { return bits_per_second; }
74
75 virtual bool begin() {
76 TRACEI();
77
78 int mode = getCodec2Mode(bits_per_second);
79 if (mode == -1) {
80 LOGE("invalid bits_per_second")
81 return false;
82 }
83 if (info.channels != 1) {
84 LOGE("Only 1 channel supported")
85 return false;
86 }
87 if (info.bits_per_sample != 16) {
88 LOGE("Only 16 bps are supported")
89 return false;
90 }
91 if (info.sample_rate != 8000) {
92 LOGW("Sample rate should be 8000: %d", info.sample_rate);
93 }
94
95 p_codec2 = codec2_create(mode);
96 if (p_codec2 == nullptr) {
97 LOGE("codec2_create");
98 return false;
99 }
100
101 result_buffer.resize(bytesCompressed());
102 input_buffer.resize(bytesCompressed() );
103
104 assert(input_buffer.size()>0);
105 assert(result_buffer.size()>0);
106
107 notifyAudioChange(info);
108 LOGI("bytesCompressed:%d", bytesCompressed());
109 LOGI("bytesUncompressed:%d", bytesUncompressed());
110 is_active = true;
111 return true;
112 }
113
114 int bytesCompressed() {
115 return p_codec2 != nullptr ? codec2_bytes_per_frame(p_codec2) : 0;
116 }
117
118 int bytesUncompressed() {
119 return p_codec2 != nullptr
120 ? codec2_samples_per_frame(p_codec2) * sizeof(int16_t)
121 : 0;
122 }
123
124
125 virtual void end() {
126 TRACEI();
127 codec2_destroy(p_codec2);
128 is_active = false;
129 }
130
131 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
132
133 operator bool() { return is_active; }
134
135 size_t write(const uint8_t *data, size_t len) override {
136 LOGD("write: %d", len);
137 if (!is_active) {
138 LOGE("inactive");
139 return 0;
140 }
141
142 uint8_t *p_byte = (uint8_t *)data;
143 for (int j = 0; j < len; j++) {
144 processByte(p_byte[j]);
145 }
146
147 return len;
148 }
149
150 protected:
151 Print *p_print = nullptr;
152 struct CODEC2 *p_codec2;
153 bool is_active = false;
154 Vector<uint8_t> input_buffer;
155 Vector<uint8_t> result_buffer;
156 int input_pos = 0;
157 int bits_per_second = 0;
158
160 void processByte(uint8_t byte) {
161 // add byte to buffer
162 input_buffer[input_pos++] = byte;
163
164 // decode if buffer is full
165 if (input_pos >= input_buffer.size()) {
166 codec2_decode(p_codec2, (short*)result_buffer.data(), input_buffer.data());
167 int written = p_print->write((uint8_t *)result_buffer.data(), result_buffer.size());
168 if (written != result_buffer.size()){
169 LOGE("write: %d written: %d", result_buffer.size(), written);
170 } else {
171 LOGD("write: %d written: %d", result_buffer.size(), written);
172 }
173 delay(2);
174 input_pos = 0;
175 }
176 }
177};
178
188 public:
189 Codec2Encoder(int bps = 3200) {
190 info.sample_rate = 8000;
191 info.channels = 1;
192 info.bits_per_sample = 16;
193 setBitsPerSecond(bps);
194 }
195
198 virtual void setBitsPerSecond(int bps) { bits_per_second = bps; }
199
200 int bitsPerSecond() { return bits_per_second; }
201
202 int bytesCompressed() {
203 return p_codec2 != nullptr ? codec2_bytes_per_frame(p_codec2) : 0;
204 }
205
206 int bytesUncompressed() {
207 return p_codec2 != nullptr
208 ? codec2_samples_per_frame(p_codec2) * sizeof(int16_t)
209 : 0;
210 }
211
212 bool begin() {
213 TRACEI();
214
215 int mode = getCodec2Mode(bits_per_second);
216 if (mode == -1) {
217 LOGE("invalid bits_per_second")
218 return false;
219 }
220 if (info.channels != 1) {
221 LOGE("Only 1 channel supported")
222 return false;
223 }
224 if (info.bits_per_sample != 16) {
225 LOGE("Only 16 bps are supported")
226 return false;
227 }
228 if (info.sample_rate != 8000) {
229 LOGW("Sample rate should be 8000: %d", info.sample_rate);
230 }
231
232 p_codec2 = codec2_create(mode);
233 if (p_codec2 == nullptr) {
234 LOGE("codec2_create");
235 return false;
236 }
237
238 input_buffer.resize(bytesCompressed());
239 result_buffer.resize(bytesUncompressed());
240 assert(input_buffer.size()>0);
241 assert(result_buffer.size()>0);
242 LOGI("bytesCompressed:%d", bytesCompressed());
243 LOGI("bytesUncompressed:%d", bytesUncompressed());
244 is_active = true;
245 return true;
246 }
247
248 virtual void end() {
249 TRACEI();
250 codec2_destroy(p_codec2);
251 is_active = false;
252 }
253
254 virtual const char *mime() { return "audio/codec2"; }
255
256 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
257
258 operator bool() { return is_active; }
259
260 size_t write(const uint8_t *in_ptr, size_t in_size) override {
261 LOGD("write: %d", in_size);
262 if (!is_active) {
263 LOGE("inactive");
264 return 0;
265 }
266 // encode bytes
267 uint8_t *p_byte = (uint8_t *)in_ptr;
268 for (int j = 0; j < in_size; j++) {
269 processByte(p_byte[j]);
270 }
271 return in_size;
272 }
273
274 protected:
275 Print *p_print = nullptr;
276 struct CODEC2 *p_codec2 = nullptr;
277 bool is_active = false;
278 int buffer_pos = 0;
279 Vector<uint8_t> input_buffer;
280 Vector<uint8_t> result_buffer;
281 int bits_per_second = 0;
282
283 // add byte to decoding buffer and decode if buffer is full
284 void processByte(uint8_t byte) {
285 input_buffer[buffer_pos++] = byte;
286 if (buffer_pos >= input_buffer.size()) {
287 // encode
288 codec2_encode(p_codec2, result_buffer.data(),
289 (short*)input_buffer.data());
290 int written = p_print->write(result_buffer.data(), result_buffer.size());
291 if(written!=result_buffer.size()){
292 LOGE("write: %d written: %d", result_buffer.size(), written);
293 } else {
294 LOGD("write: %d written: %d", result_buffer.size(), written);
295 }
296 buffer_pos = 0;
297 }
298 }
299};
300
301} // namespace audio_tools
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
Encoding of PCM data.
Definition AudioCodecsBase.h:90
Decoder for Codec2. Depends on https://github.com/pschatzmann/arduino-libcodec2.
Definition CodecCodec2.h:61
virtual void setOutput(Print &out_stream)
Defines where the decoded result is written to.
Definition CodecCodec2.h:131
virtual void setBitsPerSecond(int bps)
Definition CodecCodec2.h:71
void processByte(uint8_t byte)
Build decoding buffer and decode when frame is full.
Definition CodecCodec2.h:160
Encoder for Codec2 - Depends on https://github.com/pschatzmann/arduino-libcodec2.
Definition CodecCodec2.h:187
virtual void setBitsPerSecond(int bps)
Definition CodecCodec2.h:198
virtual const char * mime()
Provides the mime type of the encoded result.
Definition CodecCodec2.h:254
Definition NoArduino.h:62
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
int getCodec2Mode(int bits_per_second)
Convert bits per sample to Codec2 mode.
Definition CodecCodec2.h:27
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