arduino-audio-tools
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 
15 namespace audio_tools {
16 
26 class 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 
131 class 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
Docoding of encoded audio into PCM data.
Definition: AudioCodecsBase.h:16
Encoding of PCM data.
Definition: AudioCodecsBase.h:84
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:58
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:868
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