TinyModem
Header-only software audio modem library
Loading...
Searching...
No Matches
GGWave.h
Go to the documentation of this file.
1#pragma once
2
3#include <ctype.h>
4#include <math.h>
5#include <stdint.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "AudioTools.h"
10#include "ReedSolomon.h"
11
12namespace tinymodem {
13
29
40 const char* mode;
47
49 int tones() const { return 2 * bytes_per_tx; }
50};
51
55
74struct GGWaveConfig : public audio_tools::AudioInfo {
76 sample_rate = 48000;
77 channels = 1;
78 bits_per_sample = 16;
79 }
80
82 static constexpr int BASE_FRAME = 1024;
83 static constexpr int BASE_RATE = 48000;
85 static constexpr int MAX_PAYLOAD = 140;
87 static constexpr int MARKER_FRAMES = 16;
89 static constexpr int MARKER_TONES = 16;
91 static constexpr int LENGTH_BYTES = 3;
92
96 float volume = 1.0f;
98 bool dss = false;
100 bool rx_any_speed = true;
103 float marker_threshold = 3.0f;
105 bool rx_one = false;
107 uint8_t channel = 0;
109 float rx_noise = 0.0f;
110
112 bool setMode(const char* mode) {
113 const GGWaveProtocol* p = findMode(mode);
114 if (p == nullptr) return false;
115 protocol = p->id;
116 return true;
117 }
118
120 static bool isMode(const char* mode) { return findMode(mode) != nullptr; }
121
125 return p != nullptr ? *p : protocols()[1];
126 }
127
129 static int protocolCount() { return 9; }
130
132 static const GGWaveProtocol* protocols() {
133 static const GGWaveProtocol table[] = {
134 {GGWAVE_AUDIBLE_NORMAL, "ggwave-normal", 40, 9, 3},
135 {GGWAVE_AUDIBLE_FAST, "ggwave-fast", 40, 6, 3},
136 {GGWAVE_AUDIBLE_FASTEST, "ggwave-fastest", 40, 3, 3},
137 {GGWAVE_ULTRASOUND_NORMAL, "ggwave-u-normal", 320, 9, 3},
138 {GGWAVE_ULTRASOUND_FAST, "ggwave-u-fast", 320, 6, 3},
139 {GGWAVE_ULTRASOUND_FASTEST, "ggwave-u-fastest", 320, 3, 3},
140 {GGWAVE_DT_NORMAL, "ggwave-dt-normal", 24, 9, 1},
141 {GGWAVE_DT_FAST, "ggwave-dt-fast", 24, 6, 1},
142 {GGWAVE_DT_FASTEST, "ggwave-dt-fastest", 24, 3, 1},
143 };
144 return table;
145 }
146
148 static const GGWaveProtocol* findProtocol(int id) {
149 if (id < 0 || id >= protocolCount()) return nullptr;
150 return &protocols()[id];
151 }
152
154 int frameSize() const {
155 return (int)((int64_t)sample_rate * BASE_FRAME / BASE_RATE);
156 }
157
159 float binFrequency(int bin) const {
160 return (float)bin * sample_rate / frameSize();
161 }
162
164 static int eccBytes(int len) {
165 return len < 4 ? 2 : (2 * (len / 5) > 4 ? 2 * (len / 5) : 4);
166 }
167
169 static int encodedBytes(int len) { return LENGTH_BYTES + len + eccBytes(len); }
170
172 int dataSymbols(int len) const {
173 int bpt = protocolInfo().bytes_per_tx;
174 return (encodedBytes(len) + bpt - 1) / bpt;
175 }
176
178 size_t messageSamples(int len) const {
179 int frames = 2 * MARKER_FRAMES +
181 return (size_t)frames * frameSize();
182 }
183
185 float symbolRate() const {
186 return (float)sample_rate / (frameSize() * protocolInfo().frames_per_tx);
187 }
188
190 float bitRate() const { return symbolRate() * 8 * protocolInfo().bytes_per_tx; }
191
193 bool isValid() const {
194 if (findProtocol(protocol) == nullptr) {
195 LOGE("ggwave: invalid protocol: %d", protocol);
196 return false;
197 }
198 int n = frameSize();
199 if ((int64_t)n * BASE_RATE != (int64_t)sample_rate * BASE_FRAME ||
200 n % 4 != 0) {
201 LOGE("ggwave: the sample rate %d is not supported (e.g. use 48000)",
202 (int)sample_rate);
203 return false;
204 }
205 const GGWaveProtocol& p = protocolInfo();
206 int top = p.freq_start + 16 * p.tones();
207 if (2 * top >= n) {
208 LOGE("ggwave: the sample rate %d is too low for %s", (int)sample_rate,
209 p.mode);
210 return false;
211 }
212 if (marker_threshold < 1.0f) {
213 LOGE("ggwave: marker_threshold must be >= 1");
214 return false;
215 }
216 return true;
217 }
218
220 static uint8_t dssMagic(int i) {
221 static const uint8_t magic[64] = {
222 0x96, 0x9f, 0xb4, 0xaf, 0x1b, 0x91, 0xde, 0xc5, 0x45, 0x75, 0xe8,
223 0x2e, 0x0f, 0x32, 0x4a, 0x5f, 0xb4, 0x56, 0x95, 0xcb, 0x7f, 0x6a,
224 0x54, 0x6a, 0x48, 0xf2, 0x0b, 0x7b, 0xcd, 0xfb, 0x93, 0x6d, 0x3c,
225 0x77, 0x5e, 0xc3, 0x33, 0x47, 0xc0, 0xf1, 0x71, 0x32, 0x33, 0x27,
226 0x35, 0x68, 0x47, 0x1f, 0x4e, 0xac, 0x23, 0x42, 0x5f, 0x00, 0x37,
227 0xa4, 0x50, 0x6d, 0x48, 0x24, 0x91, 0x7c, 0xa1, 0x4e,
228 };
229 return magic[i % 64];
230 }
231
232 protected:
233 static const GGWaveProtocol* findMode(const char* mode) {
234 if (mode == nullptr) return nullptr;
235 if (equals(mode, "ggwave")) return &protocols()[1];
236 for (int j = 0; j < protocolCount(); j++)
237 if (equals(mode, protocols()[j].mode)) return &protocols()[j];
238 return nullptr;
239 }
240
241 static bool equals(const char* a, const char* b) {
242 while (*a && *b) {
243 if (tolower(*a) != tolower(*b)) return false;
244 a++;
245 b++;
246 }
247 return *a == *b;
248 }
249};
250
251} // namespace tinymodem
Reed-Solomon code over GF(256) with the polynomial 0x11d and lengths which are defined at runtime....
Definition ReedSolomon.h:18
TinyModem: software audio modems and packets with error correction.
Definition AX25.h:11
GGWaveProtocolId
Protocol ids of ggwave: the values are identical to ggwave's ggwave_ProtocolId. The mono-tone protoco...
Definition GGWave.h:18
@ GGWAVE_DT_FAST
Definition GGWave.h:26
@ GGWAVE_AUDIBLE_FAST
Definition GGWave.h:20
@ GGWAVE_DT_FASTEST
Definition GGWave.h:27
@ GGWAVE_AUDIBLE_FASTEST
Definition GGWave.h:21
@ GGWAVE_DT_NORMAL
Definition GGWave.h:25
@ GGWAVE_ULTRASOUND_FAST
Definition GGWave.h:23
@ GGWAVE_ULTRASOUND_FASTEST
Definition GGWave.h:24
@ GGWAVE_AUDIBLE_NORMAL
Definition GGWave.h:19
@ GGWAVE_ULTRASOUND_NORMAL
Definition GGWave.h:22
RSCodec GGWaveRS
Definition GGWave.h:54
static uint8_t dssMagic(int i)
Value of the ggwave DSS sequence for the indicated payload byte.
Definition GGWave.h:220
static bool equals(const char *a, const char *b)
Definition GGWave.h:241
float symbolRate() const
Data symbols per second.
Definition GGWave.h:185
const GGWaveProtocol & protocolInfo() const
Provides the selected protocol.
Definition GGWave.h:123
static bool isMode(const char *mode)
true if the mode is a ggwave mode
Definition GGWave.h:120
int frameSize() const
Samples per frame: the tones are multiples of sample_rate / frameSize().
Definition GGWave.h:154
float bitRate() const
Payload bits per second (without markers and error correction).
Definition GGWave.h:190
static constexpr int MARKER_TONES
number of tones of a marker
Definition GGWave.h:89
static constexpr int MARKER_FRAMES
number of frames of the start and end marker
Definition GGWave.h:87
static int encodedBytes(int len)
Total number of encoded bytes of a message (length, payload, parity).
Definition GGWave.h:169
bool dss
XOR the payload with the ggwave DSS sequence (ggwave option -d).
Definition GGWave.h:98
bool isValid() const
Checks the configuration: returns false (and logs the reason) if invalid.
Definition GGWave.h:193
static const GGWaveProtocol * findMode(const char *mode)
Definition GGWave.h:233
GGWaveConfig()
Definition GGWave.h:75
static constexpr int BASE_FRAME
samples per frame (DFT size) at 48000 Hz
Definition GGWave.h:82
bool rx_one
receiver: stop after the first message
Definition GGWave.h:105
bool rx_any_speed
receiver: accept the normal, fast and fastest variant of the protocol
Definition GGWave.h:100
static constexpr int BASE_RATE
Definition GGWave.h:83
size_t messageSamples(int len) const
Number of samples of a message with len bytes.
Definition GGWave.h:178
float volume
transmit amplitude (0.0 - 1.0)
Definition GGWave.h:96
static const GGWaveProtocol * findProtocol(int id)
Provides the protocol with the indicated id (or nullptr).
Definition GGWave.h:148
float marker_threshold
Definition GGWave.h:103
static constexpr int LENGTH_BYTES
bytes of the Reed-Solomon coded length at the start of a message
Definition GGWave.h:91
GGWaveProtocolId protocol
ggwave protocol (see setMode())
Definition GGWave.h:94
static const GGWaveProtocol * protocols()
Provides the supported protocols.
Definition GGWave.h:132
uint8_t channel
receiver: input channel which is used for the decoding
Definition GGWave.h:107
static int eccBytes(int len)
Number of Reed-Solomon parity bytes for a payload of len bytes.
Definition GGWave.h:164
float binFrequency(int bin) const
Frequency of the indicated FFT bin in Hz.
Definition GGWave.h:159
bool setMode(const char *mode)
Selects the protocol by mode name: returns false if invalid.
Definition GGWave.h:112
static int protocolCount()
Number of supported protocols.
Definition GGWave.h:129
float rx_noise
receiver: (testing only) amplitude of added uniform noise
Definition GGWave.h:109
static constexpr int MAX_PAYLOAD
max payload of a message (variable length format)
Definition GGWave.h:85
int dataSymbols(int len) const
Number of data symbols of a message with len bytes.
Definition GGWave.h:172
Transmission protocol of ggwave (https://github.com/ggerganov/ggwave): the ids and parameters are ide...
Definition GGWave.h:36
const char * mode
TinyModem mode name.
Definition GGWave.h:40
int tones() const
number of simultaneous tones in a data symbol
Definition GGWave.h:49
GGWaveProtocolId id
ggwave protocol id
Definition GGWave.h:38
int frames_per_tx
number of frames per transmitted chunk (symbol)
Definition GGWave.h:44
int freq_start
FFT bin of the lowest tone.
Definition GGWave.h:42
int bytes_per_tx
number of bytes per chunk: 2 tones per byte
Definition GGWave.h:46