arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
CodecGSM.h
Go to the documentation of this file.
1
9#pragma once
10
11#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
12#include "gsm.h"
13
14
15namespace audio_tools {
16
26class GSMDecoder : public AudioDecoder {
27 public:
28 GSMDecoder() {
29 info.sample_rate = 8000;
30 info.channels = 1;
31 }
32
33 virtual bool begin() {
34 TRACEI();
35 // 160 13-bit samples
36 result_buffer.resize(160 * sizeof(int16_t));
37 // gsm_frame of 33 bytes
38 input_buffer.resize(33);
39
40 v_gsm = gsm_create();
41 notifyAudioChange(info);
42 is_active = true;
43 return true;
44 }
45
46 virtual void end() {
47 TRACEI();
48 gsm_destroy(v_gsm);
49 is_active = false;
50 }
51
52 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
53
54 operator bool() { return is_active; }
55
56 virtual size_t write(const uint8_t *data, size_t len) {
57 LOGD("write: %d", len);
58 if (!is_active) {
59 LOGE("inactive");
60 return 0;
61 }
62
63 for (int j = 0; j < len; j++) {
64 processByte(data[j]);
65 }
66
67 return len;
68 }
69
70 protected:
71 Print *p_print = nullptr;
72 gsm v_gsm;
73 bool is_active = false;
74 Vector<uint8_t> input_buffer;
75 Vector<uint8_t> result_buffer;
76 int input_pos = 0;
77
79 void processByte(uint8_t byte) {
80 // add byte to buffer
81 input_buffer[input_pos++] = byte;
82
83 // decode if buffer is full
84 if (input_pos >= input_buffer.size()) {
85 if (gsm_decode(v_gsm, input_buffer.data(), (gsm_signal*)result_buffer.data())!=0){
86 LOGE("gsm_decode");
87 }
88
89 //fromBigEndian(result_buffer);
90 // scale to 13 to 16-bit samples
91 scale(result_buffer);
92
93 p_print->write(result_buffer.data(), result_buffer.size());
94 input_pos = 0;
95 }
96 }
97
98 void scale(Vector<uint8_t> &vector){
99 int16_t *pt16 = (int16_t *)vector.data();
100 for (int j = 0; j < vector.size() / 2; j++) {
101 if (abs(pt16[j])<=4095){
102 pt16[j] = pt16[j] * 8;
103 } else if(pt16[j]<0){
104 pt16[j] = -32767;
105 } else if(pt16[j]>0){
106 pt16[j] = 32767;
107 }
108 }
109 }
110
111 void fromBigEndian(Vector<uint8_t> &vector){
112 int size = vector.size() / 2;
113 int16_t *data16 = (int16_t*) vector.data();
114 for (int i=0; i<size; i++){
115 data16[i] = ntohs(data16[i]);
116 }
117 }
118
119
120};
121
131class GSMEncoder : public AudioEncoder {
132 public:
133 GSMEncoder(bool scaling=true) {
134 info.sample_rate = 8000;
135 info.channels = 1;
136 scaling_active = scaling;
137 }
138
139 bool begin() {
140 TRACEI();
141
142 if (info.sample_rate != 8000) {
143 LOGW("Sample rate is supposed to be 8000 - it was %d", info.sample_rate);
144 }
145 if (info.channels != 1) {
146 LOGW("channels is supposed to be 1 - it was %d", info.channels);
147 }
148
149 v_gsm = gsm_create();
150 // 160 13-bit samples
151 input_buffer.resize(160 * sizeof(int16_t));
152 // gsm_frame of 33 bytes
153 result_buffer.resize(33);
154 is_active = true;
155 return true;
156 }
157
158 virtual void end() {
159 TRACEI();
160 gsm_destroy(v_gsm);
161 is_active = false;
162 }
163
164 virtual const char *mime() { return "audio/gsm"; }
165
166 virtual void setOutput(Print &out_stream) { p_print = &out_stream; }
167
168 operator bool() { return is_active; }
169
170 virtual size_t write(const uint8_t *data, size_t len) {
171 LOGD("write: %d", len);
172 if (!is_active) {
173 LOGE("inactive");
174 return 0;
175 }
176 // encode bytes
177 for (int j = 0; j < len; j++) {
178 processByte(data[j]);
179 }
180 return len;
181 }
182
183 protected:
184 Print *p_print = nullptr;
185 gsm v_gsm;
186 bool is_active = false;
187 int buffer_pos = 0;
188 bool scaling_active;
189 Vector<uint8_t> input_buffer;
190 Vector<uint8_t> result_buffer;
191
192 // add byte to decoding buffer and decode if buffer is full
193 void processByte(uint8_t byte) {
194 input_buffer[buffer_pos++] = byte;
195 if (buffer_pos >= input_buffer.size()) {
196 scaleValues(input_buffer);
197 // toBigEndian(input_buffer);
198 // encode
199 gsm_encode(v_gsm, (gsm_signal*)input_buffer.data(), result_buffer.data());
200 size_t written = p_print->write(result_buffer.data(), result_buffer.size());
201 assert(written == result_buffer.size());
202 buffer_pos = 0;
203 }
204 }
205
206 void toBigEndian(Vector<uint8_t> &vector){
207 int size = vector.size() / 2;
208 int16_t *data16 = (int16_t*) vector.data();
209 for (int i=0; i<size; i++){
210 data16[i] = htons(data16[i]);
211 }
212 }
213
214 void scaleValues(Vector<uint8_t> &vector) {
215 int16_t *pt16 = (int16_t *)vector.data();
216 int size = vector.size() / 2;
217 if (scaling_active){
218 // scale to 16 to 13-bit samples
219 for (int j = 0; j < size; j++) {
220 pt16[j] = pt16[j] / 8;
221 }
222 } else {
223 // clip value to 13-bits
224 for (int j = 0; j < size; j++) {
225 if ( pt16[j]>4095){
226 pt16[j] = 4095;
227 }
228 if ( pt16[j]<-4095){
229 pt16[j] = -4095;
230 }
231 }
232 }
233 }
234};
235
236} // namespace audio_tools
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
Encoding of PCM data.
Definition AudioCodecsBase.h:90
Decoder for GSM. Depends on https://github.com/pschatzmann/arduino-libgsm. Inspired by gsmdec....
Definition CodecGSM.h:26
virtual void setOutput(Print &out_stream)
Defines where the decoded result is written to.
Definition CodecGSM.h:52
void processByte(uint8_t byte)
Build decoding buffer and decode when frame is full.
Definition CodecGSM.h:79
Encoder for GSM - Depends on https://github.com/pschatzmann/arduino-libgsm. Inspired by gsmenc....
Definition CodecGSM.h:131
virtual const char * mime()
Provides the mime type of the encoded result.
Definition CodecGSM.h:164
Definition NoArduino.h:62
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
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