TinyModem
Header-only software audio modem library
Loading...
Searching...
No Matches
DSPUtils.h
Go to the documentation of this file.
1#pragma once
2
3#include <math.h>
4#include <stdint.h>
5
6#include "AudioTools.h"
7
8namespace tinymodem {
9
16 public:
19 void begin(float in_rate, float out_rate, float cutoff = 0.45f) {
20 this->cutoff = cutoff;
21 ratio = base_ratio = in_rate / out_rate;
22 bypass = fabsf(ratio - 1.0f) < 1e-6f;
23 float low_rate = in_rate < out_rate ? in_rate : out_rate;
24 // kernel in input samples
25 half_width = HALF_WIDTH * in_rate / low_rate;
26 kernel_scale = low_rate / in_rate;
27 int len = (int)ceilf(2 * half_width) + 2;
28 history.resize(len);
29 history_q.resize(len);
30 for (int j = 0; j <= TABLE; j++) {
31 // u in units of the lower rate: 0 to HALF_WIDTH
32 float u = (float)HALF_WIDTH * j / TABLE;
33 float x = 2.0f * cutoff * u;
34 float sinc = j == 0 ? 1.0f : sinf((float)M_PI * x) / ((float)M_PI * x);
35 float window = 0.5f + 0.5f * cosf((float)M_PI * u / HALF_WIDTH);
36 table[j] = 2.0f * cutoff * sinc * window;
37 }
38 reset();
39 }
40
41 void reset() {
42 for (size_t j = 0; j < history.size(); j++) history[j] = history_q[j] = 0;
43 count = 0;
44 next = 0;
45 }
46
49 void setRateFactor(double factor) {
50 if (!bypass) ratio = base_ratio / factor;
51 }
52
54 template <class F>
55 void write(float x, F out) {
56 if (bypass) {
57 out(x);
58 return;
59 }
60 int len = history.size();
61 history[count % len] = x;
62 count++;
63 // the output at position next needs the inputs up to next + half_width
64 while (next + half_width < count - 1) {
65 int first = (int)ceilf(next - half_width);
66 int last = (int)floorf(next + half_width);
67 float sum = 0;
68 for (int n = first; n <= last; n++) {
69 if (n < 0) continue;
70 sum += history[n % len] * kernel(fabsf(n - next) * kernel_scale);
71 }
72 out(sum * kernel_scale);
73 next += ratio;
74 }
75 }
76
79 template <class F>
80 void writeComplex(float re, float im, F out) {
81 if (bypass) {
82 out(re, im);
83 return;
84 }
85 int len = history.size();
86 history[count % len] = re;
87 history_q[count % len] = im;
88 count++;
89 while (next + half_width < count - 1) {
90 int first = (int)ceilf(next - half_width);
91 int last = (int)floorf(next + half_width);
92 float sum_re = 0, sum_im = 0;
93 for (int n = first; n <= last; n++) {
94 if (n < 0) continue;
95 float k = kernel(fabsf(n - next) * kernel_scale);
96 sum_re += history[n % len] * k;
97 sum_im += history_q[n % len] * k;
98 }
99 out(sum_re * kernel_scale, sum_im * kernel_scale);
100 next += ratio;
101 }
102 }
103
104 protected:
105 static constexpr int HALF_WIDTH = 8;
106 static constexpr int TABLE = 512;
107 float table[TABLE + 2];
108 audio_tools::Vector<float> history, history_q;
109 double ratio = 1, base_ratio = 1;
110 float cutoff = 0.45f;
111 bool bypass = true;
113 float kernel_scale = 1;
114 int64_t count = 0;
115 double next = 0;
116
118 float kernel(float u) {
119 float pos = u * TABLE / HALF_WIDTH;
120 int idx = (int)pos;
121 if (idx >= TABLE) return 0;
122 float frac = pos - idx;
123 return table[idx] + frac * (table[idx + 1] - table[idx]);
124 }
125};
126
132 public:
133 bool begin(int size) {
134 if (size < 2 || (size & (size - 1)) != 0) return false;
135 len = size;
136 cos_table.resize(len / 2);
137 sin_table.resize(len / 2);
138 for (int j = 0; j < len / 2; j++) {
139 cos_table[j] = cos(2.0 * M_PI * j / len);
140 sin_table[j] = -sin(2.0 * M_PI * j / len);
141 }
142 return true;
143 }
144
146 void process(float* re, float* im) {
147 // bit reversal
148 for (int i = 1, j = 0; i < len; i++) {
149 int bit = len >> 1;
150 for (; j & bit; bit >>= 1) j ^= bit;
151 j ^= bit;
152 if (i < j) {
153 float t = re[i];
154 re[i] = re[j];
155 re[j] = t;
156 t = im[i];
157 im[i] = im[j];
158 im[j] = t;
159 }
160 }
161 for (int size = 2; size <= len; size *= 2) {
162 int half = size / 2;
163 int step = len / size;
164 for (int start = 0; start < len; start += size) {
165 for (int k = 0; k < half; k++) {
166 float c = cos_table[k * step], s = sin_table[k * step];
167 int a = start + k, b = a + half;
168 float tr = re[b] * c - im[b] * s;
169 float ti = re[b] * s + im[b] * c;
170 re[b] = re[a] - tr;
171 im[b] = im[a] - ti;
172 re[a] += tr;
173 im[a] += ti;
174 }
175 }
176 }
177 }
178
179 int size() const { return len; }
180
181 protected:
182 int len = 0;
183 audio_tools::Vector<float> cos_table, sin_table;
184};
185
186} // namespace tinymodem
Converts the sample rate of a signal with a windowed sinc low pass filter (by default the cut off is ...
Definition DSPUtils.h:15
double base_ratio
Definition DSPUtils.h:109
float kernel_scale
Definition DSPUtils.h:113
float cutoff
Definition DSPUtils.h:110
double next
Definition DSPUtils.h:115
float table[TABLE+2]
Definition DSPUtils.h:107
void begin(float in_rate, float out_rate, float cutoff=0.45f)
Definition DSPUtils.h:19
void reset()
Definition DSPUtils.h:41
audio_tools::Vector< float > history
Definition DSPUtils.h:108
void setRateFactor(double factor)
Definition DSPUtils.h:49
int64_t count
Definition DSPUtils.h:114
double ratio
Definition DSPUtils.h:109
static constexpr int TABLE
Definition DSPUtils.h:106
float half_width
Definition DSPUtils.h:112
audio_tools::Vector< float > history_q
Definition DSPUtils.h:108
float kernel(float u)
kernel at the distance u (in samples of the lower rate)
Definition DSPUtils.h:118
void write(float x, F out)
Adds an input sample and calls out(float) for each output sample.
Definition DSPUtils.h:55
void writeComplex(float re, float im, F out)
Definition DSPUtils.h:80
bool bypass
Definition DSPUtils.h:111
static constexpr int HALF_WIDTH
Definition DSPUtils.h:105
Radix 2 complex FFT with a precomputed twiddle table.
Definition DSPUtils.h:131
void process(float *re, float *im)
In place forward transform.
Definition DSPUtils.h:146
int size() const
Definition DSPUtils.h:179
bool begin(int size)
Definition DSPUtils.h:133
audio_tools::Vector< float > sin_table
Definition DSPUtils.h:183
int len
Definition DSPUtils.h:182
audio_tools::Vector< float > cos_table
Definition DSPUtils.h:183
TinyModem: software audio modems and packets with error correction.
Definition AX25.h:11