arduino-audio-tools
CodecGGWave.h
Go to the documentation of this file.
1 
11 #pragma once
12 
13 #include "AudioTools/AudioCodecs/AudioEncoded.h"
14 #include "AudioTools/CoreAudio/Buffers.h"
15 #include "AudioTools/CoreAudio/AudioEffects/SoundGenerator.h"
16 #include <ggwave.h>
17 
18 #define GGWAVE_DEFAULT_SAMPLE_RATE 48000
19 #define GGWAVE_DEFAULT_PAYLOAD_LEN 16
20 #define GGWAVE_DEFAULT_SAMPLES_PER_FRAME 256
21 #define GGWAVE_DEFAULT_BYTES_PER_FRAME GGWAVE_DEFAULT_SAMPLES_PER_FRAME*GGWAVE_DEFAULT_PAYLOAD_LEN
22 #define GGWAVE_DEFAULT_PROTOCOL GGWAVE_PROTOCOL_AUDIBLE_FAST
23 #define GGWAVE_DEFAULT_SAMPLE_BYTESIZE 2
24 
25 //GGWAVE_PROTOCOL_DT_FAST
26 
27 namespace audio_tools {
28 
36 class GGWaveDecoder : public AudioDecoder {
37 public:
38  GGWaveDecoder() {
39  info.sample_rate = GGWAVE_DEFAULT_SAMPLE_RATE;
40  }
41 
42  GGWaveDecoder(Print &out_stream) : GGWaveDecoder() { TRACED(); pt_print=&out_stream; }
43 
44  virtual void setOutput(Print &out_stream) {pt_print=&out_stream;}
45 
46  AudioInfo audioInfo() { return info; }
47 
48  void setAudioInfo(AudioInfo ai) { info = ai; }
49 
52  template <int N>
53  void setProtocols(ggwave_ProtocolId protocolsArray[N]){
54  for (int j=0;j<N;j++){
55  protocols.push_back(protocolsArray[j]);
56  }
57  }
58 
59  void setSamplesFormatInput(ggwave_SampleFormat fmt){
60  samples_format_input = fmt;
61  }
62 
63  void setSamplesFromatOutput(ggwave_SampleFormat fmt) {
64  samples_format_output = fmt;
65  }
66 
67  void setSamplesPerFrame(int samples){
68  samples_per_frame = samples;
69  }
70 
71  void setPayloadLen(int len){
72  playload_len = len;
73  }
74 
75  void setSampleByteSize(int size){
76  sample_byte_size = size;
77  }
78 
79  void begin() {
80  if (pt_print==nullptr){
81  LOGE("final destination not defined");
82  return;
83  }
84 
85  receive_buffer.resize(samples_per_frame*sample_byte_size);
86  ggwave.setLogFile(nullptr);
87 
88  auto p = GGWave::getDefaultParameters();
89  p.payloadLength = playload_len;
90  p.sampleRateInp = info.sample_rate;
91  p.sampleRateOut = info.sample_rate;
92  p.sampleRate = info.sample_rate;
93  p.samplesPerFrame = samples_per_frame;
94  p.sampleFormatInp = samples_format_input;
95  p.sampleFormatOut = samples_format_output;
96  p.operatingMode = GGWAVE_OPERATING_MODE_RX | GGWAVE_OPERATING_MODE_USE_DSS ;
97 
98 
99  // Remove the ones that you don't need to reduce memory usage
100  GGWave::Protocols::tx().disableAll();
101  GGWave::Protocols::rx().disableAll();
102 
103  // activate additional protocols
104  GGWave::Protocols::rx().toggle(GGWAVE_DEFAULT_PROTOCOL, true);
105  for (auto protocol: protocols){
106  GGWave::Protocols::rx().toggle(protocol, true);
107  }
108 
109  // Initialize the "ggwave" instance:
110  active = true;
111  if (!ggwave.prepare(p, true)){
112  active = false;
113  LOGE("prepare failed");
114  }
115  }
116 
117 
118  void end() {
119  ggwave.rxStopReceiving();
120  active = false;
121  }
122 
123  size_t write(const uint8_t *data, size_t len) {
124  if (!active) return 0;
125  uint8_t *p_byte = (uint8_t *)data;
126  for (int j=0;j<len;j++){
127  receive_buffer.write(p_byte[j]);
128  if (receive_buffer.availableForWrite()==0){
129  decode();
130  }
131  }
132  return len;
133  }
134 
135  operator bool() { return active; }
136 
137  // The result is encoded data
138  virtual bool isResultPCM() { return false;}
139 
140 protected:
141  Print *pt_print=nullptr;
142  AudioInfo info;
143  GGWave ggwave;
144  GGWave::TxRxData data;
145  SingleBuffer<uint8_t> receive_buffer{0};
146  Vector<ggwave_ProtocolId> protocols;
147  ggwave_SampleFormat samples_format_input = GGWAVE_SAMPLE_FORMAT_I16;
148  ggwave_SampleFormat samples_format_output = GGWAVE_SAMPLE_FORMAT_U8;
149  int samples_per_frame = 0; //GGWAVE_DEFAULT_SAMPLES_PER_FRAME;
150  int playload_len = GGWAVE_DEFAULT_PAYLOAD_LEN;
151  int sample_byte_size = GGWAVE_DEFAULT_SAMPLE_BYTESIZE;
152  bool active = false;
153 
154  void decode() {
155  if (receive_buffer.available()>0){
156  if (ggwave.decode(receive_buffer.address(), receive_buffer.available()/(info.bits_per_sample/8))) {
157  // Check if we have successfully decoded any data:
158  int nr = ggwave.rxTakeData(data);
159  if (nr > 0) {
160  pt_print->write((uint8_t*) &data[0], nr);
161  }
162  } else {
163  LOGW("decoding error");
164  }
165  receive_buffer.reset();
166  }
167  }
168 };
169 
177 class GGWaveEncoder : public AudioEncoder {
178 public:
179  GGWaveEncoder() {
180  info.sample_rate = GGWAVE_DEFAULT_SAMPLE_RATE;
181  }
182 
183  GGWaveEncoder(Print &out_stream) : GGWaveEncoder() {
184  TRACED();
185  pt_print=&out_stream;
186  }
187 
188  void setOutput(Print &out_stream) {pt_print=&out_stream;}
189 
190  void setSamplesFormatInput(ggwave_SampleFormat fmt){
191  samples_format_input = fmt;
192  }
193 
194  void setSamplesFromatOutput(ggwave_SampleFormat fmt) {
195  samples_format_output = fmt;
196  }
197 
198  void setSamplesPerFrame(int samples){
199  samples_per_frame = samples;
200  }
201 
202  void setPayloadLen(int len){
203  playload_len = len;
204  }
205 
206  void setProtocol(ggwave_ProtocolId protocol){
207  protocolId = protocol;
208  }
209 
210  void setSampleByteSize(int size){
211  sample_byte_size = size;
212  }
213 
214  void begin() {
215  TRACEI();
216  ggwave.setLogFile(nullptr);
217  if (pt_print==nullptr){
218  LOGE("final destination not defined");
219  return;
220  }
221  sine_wave.begin(info.channels, info.sample_rate, 0);
222 
223  auto parameters = GGWave::getDefaultParameters();
224  parameters.payloadLength = playload_len;
225  parameters.sampleRateInp = info.sample_rate;
226  parameters.sampleRateOut = info.sample_rate;
227  parameters.sampleRate = info.sample_rate;
228  parameters.samplesPerFrame = samples_per_frame;
229  parameters.sampleFormatInp = samples_format_input;
230  parameters.sampleFormatOut = samples_format_output;
231  parameters.operatingMode = GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_USE_DSS;
232 
233  // Remove the ones that you don't need to reduce memory usage
234  GGWave::Protocols::tx().only(protocolId);
235 
236  // Sometimes, the speaker might not be able to produce frequencies in the Mono-tone range of 1-2 kHz.
237  // In such cases, you can shift the base frequency up by changing the "freqStart" parameter of the protocol.
238  // Make sure that in the receiver (for example, the "Waver" app) the base frequency is shifted by the same amount.
239  // Here we shift the frequency by +48 bins. Each bin is equal to 48000/1024 = 46.875 Hz.
240  // So the base frequency is shifted by +2250 Hz.
241  //GGWave::Protocols::tx()[protocolId].freqStart += 48;
242 
243  ggwave.prepare(parameters);
244  active = true;
245  }
246 
247  void end() {
248  TRACEI();
249  active = false;
250  }
251 
252  size_t write(const uint8_t *data, size_t len) {
253  if (!active) return 0;
254 
255  if (!ggwave.init(len, (const char*)data, protocolId)){
256  LOGE("init faild");
257  return 0;
258  }
259  size_t bytes = ggwave.encode();
260  LOGI("write %d", bytes);
261  //int written = pt_print->write((uint8_t*)ggwave.txWaveform(), bytes);
262 
263  const auto &protocol = GGWave::Protocols::tx()[protocolId];
264  const auto tones = ggwave.txTones();
265  const auto duration_ms = protocol.txDuration_ms(ggwave.samplesPerFrame(), ggwave.sampleRateOut());
266  for (auto & curTone : tones) {
267  const auto freq_hz = (protocol.freqStart + curTone)*ggwave.hzPerSample();
268  play(freq_hz, duration_ms);
269  }
270 
271  silence(info.sample_rate / 2); // 500 ms
272  return len;
273  }
274 
275  operator bool(){
276  return active;
277  }
278 
279  virtual const char *mime() {
280  return "audio/pcm";
281  }
282 
283 protected:
284  Print *pt_print=nullptr;
285  GGWave ggwave;
286  ggwave_ProtocolId protocolId = GGWAVE_DEFAULT_PROTOCOL;
287  int samples_per_frame = GGWAVE_DEFAULT_SAMPLES_PER_FRAME;
288  ggwave_SampleFormat samples_format_input = GGWAVE_SAMPLE_FORMAT_I16;
289  ggwave_SampleFormat samples_format_output = GGWAVE_SAMPLE_FORMAT_U8;
290  int playload_len = GGWAVE_DEFAULT_PAYLOAD_LEN;
291  int volume = GGWave::kDefaultVolume;
292  int sample_byte_size = GGWAVE_DEFAULT_SAMPLE_BYTESIZE;
293  bool active = false;
294  //SineFromTable<int16_t> sine_wave;
295  FastSineGenerator<int16_t> sine_wave;
296 
297  virtual void play(int freq, int ms){
298  // adjust amplitude by pitch bcause high values are too loud
299  int amplitude = 10000; // / (freq/1000);
300  sine_wave.setAmplitude(amplitude);
301  sine_wave.setFrequency(freq);
302  uint64_t end = millis()+ms;
303  while(millis()<end){
304  int16_t sample = sine_wave.readSample();
305  for (int ch=0;ch<info.channels;ch++){
306  pt_print->write((uint8_t*)&sample,2);
307  }
308  }
309  }
310 
311  virtual void silence(int samples){
312  // adjust amplitude by pitch bcause high values are too loud
313  int16_t sample = 0;
314  for (int ch=0;ch<info.channels;ch++){
315  pt_print->write((uint8_t*)&sample,2);
316  }
317  }
318 
319 };
320 
321 }
Docoding of encoded audio into PCM data.
Definition: AudioCodecsBase.h:16
Encoding of PCM data.
Definition: AudioCodecsBase.h:84
virtual T readSample() override
Provides a single sample.
Definition: SoundGenerator.h:240
GGWaveDecoder: Translates audio into text Codec using https://github.com/ggerganov/ggwave-arduino.
Definition: CodecGGWave.h:36
void setProtocols(ggwave_ProtocolId protocolsArray[N])
Activate multiple protocols.
Definition: CodecGGWave.h:53
virtual bool isResultPCM()
Returns true to indicate that the decoding result is PCM data.
Definition: CodecGGWave.h:138
virtual void setOutput(Print &out_stream)
Defines where the decoded result is written to.
Definition: CodecGGWave.h:44
AudioInfo audioInfo()
provides the actual input AudioInfo
Definition: CodecGGWave.h:46
void setAudioInfo(AudioInfo ai)
for most decoders this is not needed
Definition: CodecGGWave.h:48
GGWaveEncoder: Translates text into audio Codec using https://github.com/ggerganov/ggwave-arduino.
Definition: CodecGGWave.h:177
virtual const char * mime()
Provides the mime type of the encoded result.
Definition: CodecGGWave.h:279
Definition: NoArduino.h:58
void setFrequency(float frequency) override
Defines the frequency - after the processing has been started.
Definition: SoundGenerator.h:191
T * address() override
Provides address to beginning of the buffer.
Definition: Buffers.h:249
bool write(T sample) override
write add an entry to the buffer
Definition: Buffers.h:194
int available() override
provides the number of entries that are available to read
Definition: Buffers.h:219
int availableForWrite() override
provides the number of entries that are available to write
Definition: Buffers.h:224
void reset() override
clears the buffer
Definition: Buffers.h:254
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:868
uint32_t millis()
Returns the milliseconds since the start.
Definition: Time.h:12
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:52
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