dspx 1.2.4 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -78
- package/binding.gyp +10 -0
- package/dist/FilterBankDesign.d.ts +233 -0
- package/dist/FilterBankDesign.d.ts.map +1 -0
- package/dist/FilterBankDesign.js +247 -0
- package/dist/FilterBankDesign.js.map +1 -0
- package/dist/advanced-dsp.d.ts +6 -6
- package/dist/advanced-dsp.d.ts.map +1 -1
- package/dist/advanced-dsp.js +35 -12
- package/dist/advanced-dsp.js.map +1 -1
- package/dist/backends.d.ts +0 -103
- package/dist/backends.d.ts.map +1 -1
- package/dist/backends.js +0 -217
- package/dist/backends.js.map +1 -1
- package/dist/bindings.d.ts +270 -17
- package/dist/bindings.d.ts.map +1 -1
- package/dist/bindings.js +566 -43
- package/dist/bindings.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +67 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +38 -8
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +84 -26
- package/dist/utils.js.map +1 -1
- package/package.json +1 -2
- package/prebuilds/win32-x64/dspx.node +0 -0
- package/scripts/add-dispose-to-tests.js +145 -0
- package/src/native/DspPipeline.cc +699 -126
- package/src/native/DspPipeline.h +13 -0
- package/src/native/FilterBankDesignBindings.cc +241 -0
- package/src/native/IDspStage.h +24 -0
- package/src/native/UtilityBindings.cc +130 -0
- package/src/native/adapters/AmplifyStage.h +148 -0
- package/src/native/adapters/ClipDetectionStage.h +15 -4
- package/src/native/adapters/ConvolutionStage.h +101 -0
- package/src/native/adapters/CumulativeMovingAverageStage.h +264 -0
- package/src/native/adapters/DecimatorStage.h +80 -0
- package/src/native/adapters/DifferentiatorStage.h +13 -0
- package/src/native/adapters/ExponentialMovingAverageStage.h +290 -0
- package/src/native/adapters/FilterBankStage.cc +336 -0
- package/src/native/adapters/FilterBankStage.h +170 -0
- package/src/native/adapters/FilterStage.cc +122 -0
- package/src/native/adapters/FilterStage.h +4 -0
- package/src/native/adapters/HilbertEnvelopeStage.h +55 -0
- package/src/native/adapters/IntegratorStage.h +15 -0
- package/src/native/adapters/InterpolatorStage.h +51 -0
- package/src/native/adapters/LinearRegressionStage.h +40 -0
- package/src/native/adapters/LmsStage.h +63 -0
- package/src/native/adapters/MeanAbsoluteValueStage.h +76 -0
- package/src/native/adapters/MovingAverageStage.h +119 -0
- package/src/native/adapters/PeakDetectionStage.h +53 -0
- package/src/native/adapters/RectifyStage.h +14 -0
- package/src/native/adapters/ResamplerStage.h +67 -0
- package/src/native/adapters/RlsStage.h +76 -0
- package/src/native/adapters/RmsStage.h +72 -0
- package/src/native/adapters/SnrStage.h +45 -0
- package/src/native/adapters/SquareStage.h +78 -0
- package/src/native/adapters/SscStage.h +65 -0
- package/src/native/adapters/StftStage.h +62 -0
- package/src/native/adapters/VarianceStage.h +59 -0
- package/src/native/adapters/WampStage.h +59 -0
- package/src/native/adapters/WaveformLengthStage.h +51 -0
- package/src/native/adapters/ZScoreNormalizeStage.h +64 -0
- package/src/native/core/CumulativeMovingAverageFilter.h +123 -0
- package/src/native/core/ExponentialMovingAverageFilter.h +129 -0
- package/src/native/core/FilterBankDesign.h +266 -0
- package/src/native/core/Policies.h +124 -0
- package/src/native/utils/CircularBufferArray.cc +2 -1
- package/src/native/utils/SimdOps.h +67 -0
- package/src/native/utils/Toon.h +195 -0
|
@@ -244,6 +244,107 @@ namespace dsp::adapters
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
void serializeToon(dsp::toon::Serializer &s) const override
|
|
248
|
+
{
|
|
249
|
+
s.startObject();
|
|
250
|
+
|
|
251
|
+
s.writeString("mode");
|
|
252
|
+
s.writeString((m_mode == ConvolutionMode::Moving) ? "moving" : "batch");
|
|
253
|
+
|
|
254
|
+
s.writeString("method");
|
|
255
|
+
std::string methodStr;
|
|
256
|
+
switch (m_method)
|
|
257
|
+
{
|
|
258
|
+
case ConvolutionMethod::Auto:
|
|
259
|
+
methodStr = "auto";
|
|
260
|
+
break;
|
|
261
|
+
case ConvolutionMethod::Direct:
|
|
262
|
+
methodStr = "direct";
|
|
263
|
+
break;
|
|
264
|
+
case ConvolutionMethod::FFT:
|
|
265
|
+
methodStr = "fft";
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
s.writeString(methodStr);
|
|
269
|
+
|
|
270
|
+
s.writeString("kernel");
|
|
271
|
+
s.writeFloatArray(m_kernel);
|
|
272
|
+
|
|
273
|
+
if (m_mode == ConvolutionMode::Moving && m_actualMethod == ConvolutionMethod::Direct)
|
|
274
|
+
{
|
|
275
|
+
s.writeString("channels");
|
|
276
|
+
s.startArray();
|
|
277
|
+
|
|
278
|
+
for (const auto &filter : m_filters)
|
|
279
|
+
{
|
|
280
|
+
s.startObject();
|
|
281
|
+
auto filterState = filter.getState();
|
|
282
|
+
const auto &bufferData = filterState.first;
|
|
283
|
+
|
|
284
|
+
s.writeString("buffer");
|
|
285
|
+
s.writeFloatArray(bufferData);
|
|
286
|
+
s.endObject();
|
|
287
|
+
}
|
|
288
|
+
s.endArray();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
s.endObject();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
void deserializeToon(dsp::toon::Deserializer &d) override
|
|
295
|
+
{
|
|
296
|
+
d.consumeToken(dsp::toon::T_OBJECT_START);
|
|
297
|
+
|
|
298
|
+
std::string key = d.readString(); // "mode"
|
|
299
|
+
std::string modeStr = d.readString();
|
|
300
|
+
ConvolutionMode newMode = (modeStr == "moving") ? ConvolutionMode::Moving : ConvolutionMode::Batch;
|
|
301
|
+
if (newMode != m_mode)
|
|
302
|
+
{
|
|
303
|
+
throw std::runtime_error("Convolution mode mismatch during TOON deserialization");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
key = d.readString(); // "method"
|
|
307
|
+
d.readString(); // Skip method validation
|
|
308
|
+
|
|
309
|
+
key = d.readString(); // "kernel"
|
|
310
|
+
std::vector<float> kernel = d.readFloatArray();
|
|
311
|
+
if (kernel.size() != m_kernel.size())
|
|
312
|
+
{
|
|
313
|
+
throw std::runtime_error("Convolution kernel size mismatch during TOON deserialization");
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (modeStr == "moving" && m_actualMethod == ConvolutionMethod::Direct)
|
|
317
|
+
{
|
|
318
|
+
key = d.readString(); // "channels"
|
|
319
|
+
d.consumeToken(dsp::toon::T_ARRAY_START);
|
|
320
|
+
|
|
321
|
+
m_filters.clear();
|
|
322
|
+
|
|
323
|
+
while (d.peekToken() != dsp::toon::T_ARRAY_END)
|
|
324
|
+
{
|
|
325
|
+
d.consumeToken(dsp::toon::T_OBJECT_START);
|
|
326
|
+
|
|
327
|
+
d.readString(); // "buffer"
|
|
328
|
+
std::vector<float> bufferData = d.readFloatArray();
|
|
329
|
+
|
|
330
|
+
// Create policy with kernel
|
|
331
|
+
utils::ConvolutionPolicy<float> policy(m_kernel);
|
|
332
|
+
m_filters.emplace_back(m_kernel.size(), std::move(policy));
|
|
333
|
+
|
|
334
|
+
// Restore state
|
|
335
|
+
typename utils::ConvolutionPolicy<float>::EmptyState policyState;
|
|
336
|
+
m_filters.back().setState(bufferData, policyState);
|
|
337
|
+
|
|
338
|
+
d.consumeToken(dsp::toon::T_OBJECT_END);
|
|
339
|
+
}
|
|
340
|
+
d.consumeToken(dsp::toon::T_ARRAY_END);
|
|
341
|
+
|
|
342
|
+
m_is_initialized = true;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
d.consumeToken(dsp::toon::T_OBJECT_END);
|
|
346
|
+
}
|
|
347
|
+
|
|
247
348
|
private:
|
|
248
349
|
std::vector<float> m_kernel;
|
|
249
350
|
ConvolutionMode m_mode;
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "../IDspStage.h"
|
|
4
|
+
#include "../core/CumulativeMovingAverageFilter.h"
|
|
5
|
+
#include "../utils/SimdOps.h"
|
|
6
|
+
#include <vector>
|
|
7
|
+
#include <stdexcept>
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
namespace dsp::adapters
|
|
11
|
+
{
|
|
12
|
+
enum class CmaMode
|
|
13
|
+
{
|
|
14
|
+
Batch,
|
|
15
|
+
Moving
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
class CumulativeMovingAverageStage : public IDspStage
|
|
19
|
+
{
|
|
20
|
+
public:
|
|
21
|
+
/**
|
|
22
|
+
* @brief Constructs a new Cumulative Moving Average Stage.
|
|
23
|
+
* @param mode The averaging mode (Batch or Moving).
|
|
24
|
+
*/
|
|
25
|
+
explicit CumulativeMovingAverageStage(CmaMode mode)
|
|
26
|
+
: m_mode(mode)
|
|
27
|
+
{
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Return the type identifier for this stage
|
|
31
|
+
const char *getType() const override
|
|
32
|
+
{
|
|
33
|
+
return "cumulativeMovingAverage";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// This is the implementation of the interface method
|
|
37
|
+
void process(float *buffer, size_t numSamples, int numChannels, const float *timestamps = nullptr) override
|
|
38
|
+
{
|
|
39
|
+
if (m_mode == CmaMode::Batch)
|
|
40
|
+
{
|
|
41
|
+
processBatch(buffer, numSamples, numChannels);
|
|
42
|
+
}
|
|
43
|
+
else // CmaMode::Moving
|
|
44
|
+
{
|
|
45
|
+
processMoving(buffer, numSamples, numChannels);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Serialize the stage's state to a Napi::Object
|
|
50
|
+
Napi::Object serializeState(Napi::Env env) const override
|
|
51
|
+
{
|
|
52
|
+
Napi::Object state = Napi::Object::New(env);
|
|
53
|
+
std::string modeStr = (m_mode == CmaMode::Moving) ? "moving" : "batch";
|
|
54
|
+
state.Set("mode", modeStr);
|
|
55
|
+
|
|
56
|
+
if (m_mode == CmaMode::Moving)
|
|
57
|
+
{
|
|
58
|
+
state.Set("numChannels", static_cast<uint32_t>(m_filters.size()));
|
|
59
|
+
|
|
60
|
+
// Serialize each channel's filter state
|
|
61
|
+
Napi::Array channelsArray = Napi::Array::New(env, m_filters.size());
|
|
62
|
+
for (size_t i = 0; i < m_filters.size(); ++i)
|
|
63
|
+
{
|
|
64
|
+
Napi::Object channelState = Napi::Object::New(env);
|
|
65
|
+
|
|
66
|
+
// Get the filter's internal state
|
|
67
|
+
auto [sum, count] = m_filters[i].getState();
|
|
68
|
+
|
|
69
|
+
channelState.Set("sum", Napi::Number::New(env, sum));
|
|
70
|
+
channelState.Set("count", Napi::Number::New(env, static_cast<uint32_t>(count)));
|
|
71
|
+
|
|
72
|
+
channelsArray.Set(static_cast<uint32_t>(i), channelState);
|
|
73
|
+
}
|
|
74
|
+
state.Set("channels", channelsArray);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return state;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Deserialize and restore the stage's state
|
|
81
|
+
void deserializeState(const Napi::Object &state) override
|
|
82
|
+
{
|
|
83
|
+
std::string modeStr = state.Get("mode").As<Napi::String>().Utf8Value();
|
|
84
|
+
CmaMode newMode = (modeStr == "moving") ? CmaMode::Moving : CmaMode::Batch;
|
|
85
|
+
|
|
86
|
+
if (newMode != m_mode)
|
|
87
|
+
{
|
|
88
|
+
throw std::runtime_error("CumulativeMovingAverage mode mismatch during deserialization");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (m_mode == CmaMode::Moving)
|
|
92
|
+
{
|
|
93
|
+
// Get number of channels
|
|
94
|
+
uint32_t numChannels = state.Get("channels").As<Napi::Array>().Length();
|
|
95
|
+
|
|
96
|
+
// Recreate filters
|
|
97
|
+
m_filters.clear();
|
|
98
|
+
for (uint32_t i = 0; i < numChannels; ++i)
|
|
99
|
+
{
|
|
100
|
+
m_filters.emplace_back();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Restore each channel's state
|
|
104
|
+
Napi::Array channelsArray = state.Get("channels").As<Napi::Array>();
|
|
105
|
+
for (uint32_t i = 0; i < numChannels; ++i)
|
|
106
|
+
{
|
|
107
|
+
Napi::Object channelState = channelsArray.Get(i).As<Napi::Object>();
|
|
108
|
+
|
|
109
|
+
float sum = channelState.Get("sum").As<Napi::Number>().FloatValue();
|
|
110
|
+
size_t count = channelState.Get("count").As<Napi::Number>().Uint32Value();
|
|
111
|
+
|
|
112
|
+
// Restore the filter's state
|
|
113
|
+
m_filters[i].setState(sum, count);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Reset all filters to initial state
|
|
119
|
+
void reset() override
|
|
120
|
+
{
|
|
121
|
+
for (auto &filter : m_filters)
|
|
122
|
+
{
|
|
123
|
+
filter.clear();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// TOON Binary Serialization
|
|
128
|
+
void serializeToon(dsp::toon::Serializer &serializer) const override
|
|
129
|
+
{
|
|
130
|
+
serializer.startObject();
|
|
131
|
+
|
|
132
|
+
// 1. Mode
|
|
133
|
+
serializer.writeString("mode");
|
|
134
|
+
serializer.writeString((m_mode == CmaMode::Moving) ? "moving" : "batch");
|
|
135
|
+
|
|
136
|
+
if (m_mode == CmaMode::Moving)
|
|
137
|
+
{
|
|
138
|
+
// 2. Channels
|
|
139
|
+
serializer.writeString("channels");
|
|
140
|
+
serializer.startArray();
|
|
141
|
+
|
|
142
|
+
for (const auto &filter : m_filters)
|
|
143
|
+
{
|
|
144
|
+
auto [sum, count] = filter.getState();
|
|
145
|
+
|
|
146
|
+
serializer.startObject();
|
|
147
|
+
|
|
148
|
+
serializer.writeString("sum");
|
|
149
|
+
serializer.writeFloat(sum);
|
|
150
|
+
|
|
151
|
+
serializer.writeString("count");
|
|
152
|
+
serializer.writeInt32(static_cast<int32_t>(count));
|
|
153
|
+
|
|
154
|
+
serializer.endObject();
|
|
155
|
+
}
|
|
156
|
+
serializer.endArray();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
serializer.endObject();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// TOON Binary Deserialization
|
|
163
|
+
void deserializeToon(dsp::toon::Deserializer &deserializer) override
|
|
164
|
+
{
|
|
165
|
+
deserializer.consumeToken(dsp::toon::T_OBJECT_START);
|
|
166
|
+
|
|
167
|
+
// 1. Mode
|
|
168
|
+
std::string key = deserializer.readString(); // "mode"
|
|
169
|
+
std::string modeStr = deserializer.readString();
|
|
170
|
+
|
|
171
|
+
CmaMode newMode = (modeStr == "moving") ? CmaMode::Moving : CmaMode::Batch;
|
|
172
|
+
if (newMode != m_mode)
|
|
173
|
+
{
|
|
174
|
+
throw std::runtime_error("CumulativeMovingAverage mode mismatch during TOON deserialization");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (modeStr == "moving")
|
|
178
|
+
{
|
|
179
|
+
// 2. Channels
|
|
180
|
+
key = deserializer.readString(); // "channels"
|
|
181
|
+
deserializer.consumeToken(dsp::toon::T_ARRAY_START);
|
|
182
|
+
|
|
183
|
+
m_filters.clear();
|
|
184
|
+
|
|
185
|
+
while (deserializer.peekToken() != dsp::toon::T_ARRAY_END)
|
|
186
|
+
{
|
|
187
|
+
deserializer.consumeToken(dsp::toon::T_OBJECT_START);
|
|
188
|
+
|
|
189
|
+
// Sum
|
|
190
|
+
deserializer.readString(); // "sum"
|
|
191
|
+
float sum = deserializer.readFloat();
|
|
192
|
+
|
|
193
|
+
// Count
|
|
194
|
+
deserializer.readString(); // "count"
|
|
195
|
+
int32_t count = deserializer.readInt32();
|
|
196
|
+
|
|
197
|
+
// Reconstruct filter
|
|
198
|
+
m_filters.emplace_back();
|
|
199
|
+
m_filters.back().setState(sum, static_cast<size_t>(count));
|
|
200
|
+
|
|
201
|
+
deserializer.consumeToken(dsp::toon::T_OBJECT_END);
|
|
202
|
+
}
|
|
203
|
+
deserializer.consumeToken(dsp::toon::T_ARRAY_END);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
deserializer.consumeToken(dsp::toon::T_OBJECT_END);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private:
|
|
210
|
+
/**
|
|
211
|
+
* @brief Batch mode: Compute cumulative moving average over entire buffer per channel.
|
|
212
|
+
* Each sample in the channel is replaced by the cumulative average up to that point.
|
|
213
|
+
*/
|
|
214
|
+
void processBatch(float *buffer, size_t numSamples, int numChannels)
|
|
215
|
+
{
|
|
216
|
+
// Process each channel independently
|
|
217
|
+
for (int c = 0; c < numChannels; ++c)
|
|
218
|
+
{
|
|
219
|
+
float sum = 0.0f;
|
|
220
|
+
size_t count = 0;
|
|
221
|
+
|
|
222
|
+
// Process all samples for this channel
|
|
223
|
+
for (size_t i = c; i < numSamples; i += numChannels)
|
|
224
|
+
{
|
|
225
|
+
sum += buffer[i];
|
|
226
|
+
count++;
|
|
227
|
+
// CMA = sum / count
|
|
228
|
+
buffer[i] = sum / static_cast<float>(count);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @brief Moving mode: Statefully process samples using CMA filters with continuity.
|
|
235
|
+
* @param buffer The interleaved audio buffer.
|
|
236
|
+
* @param numSamples The total number of samples.
|
|
237
|
+
* @param numChannels The number of channels.
|
|
238
|
+
*/
|
|
239
|
+
void processMoving(float *buffer, size_t numSamples, int numChannels)
|
|
240
|
+
{
|
|
241
|
+
// Lazily initialize our filters, one for each channel
|
|
242
|
+
if (m_filters.size() != static_cast<size_t>(numChannels))
|
|
243
|
+
{
|
|
244
|
+
m_filters.clear();
|
|
245
|
+
for (int i = 0; i < numChannels; ++i)
|
|
246
|
+
{
|
|
247
|
+
m_filters.emplace_back();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Process the buffer sample by sample, de-interleaving
|
|
252
|
+
for (size_t i = 0; i < numSamples; ++i)
|
|
253
|
+
{
|
|
254
|
+
int channel = i % numChannels;
|
|
255
|
+
buffer[i] = m_filters[channel].addSample(buffer[i]);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
CmaMode m_mode;
|
|
260
|
+
// Separate filter instance for each channel's state
|
|
261
|
+
std::vector<dsp::core::CumulativeMovingAverageFilter<float>> m_filters;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
} // namespace dsp::adapters
|
|
@@ -215,6 +215,86 @@ namespace dsp
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
void serializeToon(dsp::toon::Serializer &s) const override
|
|
219
|
+
{
|
|
220
|
+
s.startObject();
|
|
221
|
+
|
|
222
|
+
s.writeString("factor");
|
|
223
|
+
s.writeInt32(decimationFactor_);
|
|
224
|
+
|
|
225
|
+
s.writeString("order");
|
|
226
|
+
s.writeInt32(filterOrder_);
|
|
227
|
+
|
|
228
|
+
s.writeString("sampleRate");
|
|
229
|
+
s.writeDouble(sampleRate_);
|
|
230
|
+
|
|
231
|
+
s.writeString("phaseIndex");
|
|
232
|
+
s.writeInt32(phaseIndex_);
|
|
233
|
+
|
|
234
|
+
s.writeString("numChannels");
|
|
235
|
+
s.writeInt32(numChannels_);
|
|
236
|
+
|
|
237
|
+
s.writeString("stateBuffer");
|
|
238
|
+
s.writeFloatArray(stateBuffer_);
|
|
239
|
+
|
|
240
|
+
s.writeString("stateIndices");
|
|
241
|
+
s.startArray();
|
|
242
|
+
for (size_t idx : stateIndices_)
|
|
243
|
+
{
|
|
244
|
+
s.writeInt32(static_cast<int32_t>(idx));
|
|
245
|
+
}
|
|
246
|
+
s.endArray();
|
|
247
|
+
|
|
248
|
+
s.endObject();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
void deserializeToon(dsp::toon::Deserializer &d) override
|
|
252
|
+
{
|
|
253
|
+
d.consumeToken(dsp::toon::T_OBJECT_START);
|
|
254
|
+
|
|
255
|
+
std::string key = d.readString(); // "factor"
|
|
256
|
+
int factor = d.readInt32();
|
|
257
|
+
if (factor != decimationFactor_)
|
|
258
|
+
{
|
|
259
|
+
throw std::runtime_error("Decimator factor mismatch during TOON deserialization");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
key = d.readString(); // "order"
|
|
263
|
+
int order = d.readInt32();
|
|
264
|
+
if (order != filterOrder_)
|
|
265
|
+
{
|
|
266
|
+
throw std::runtime_error("Decimator order mismatch during TOON deserialization");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
key = d.readString(); // "sampleRate"
|
|
270
|
+
d.readDouble(); // Skip sampleRate
|
|
271
|
+
|
|
272
|
+
key = d.readString(); // "phaseIndex"
|
|
273
|
+
phaseIndex_ = d.readInt32();
|
|
274
|
+
|
|
275
|
+
key = d.readString(); // "numChannels"
|
|
276
|
+
int numCh = d.readInt32();
|
|
277
|
+
|
|
278
|
+
if (numCh != numChannels_)
|
|
279
|
+
{
|
|
280
|
+
initializeStateBuffers(numCh);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
key = d.readString(); // "stateBuffer"
|
|
284
|
+
stateBuffer_ = d.readFloatArray();
|
|
285
|
+
|
|
286
|
+
key = d.readString(); // "stateIndices"
|
|
287
|
+
d.consumeToken(dsp::toon::T_ARRAY_START);
|
|
288
|
+
stateIndices_.clear();
|
|
289
|
+
while (d.peekToken() != dsp::toon::T_ARRAY_END)
|
|
290
|
+
{
|
|
291
|
+
stateIndices_.push_back(static_cast<size_t>(d.readInt32()));
|
|
292
|
+
}
|
|
293
|
+
d.consumeToken(dsp::toon::T_ARRAY_END);
|
|
294
|
+
|
|
295
|
+
d.consumeToken(dsp::toon::T_OBJECT_END);
|
|
296
|
+
}
|
|
297
|
+
|
|
218
298
|
/**
|
|
219
299
|
* Get decimation factor
|
|
220
300
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include "../IDspStage.h"
|
|
4
|
+
#include "../utils/Toon.h"
|
|
4
5
|
#include <stdexcept>
|
|
5
6
|
#include <string>
|
|
6
7
|
#include <vector>
|
|
@@ -92,6 +93,18 @@ namespace dsp::adapters
|
|
|
92
93
|
std::fill(m_prev_sample.begin(), m_prev_sample.end(), 0.0f);
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
void serializeToon(dsp::toon::Serializer &s) const override
|
|
97
|
+
{
|
|
98
|
+
s.writeInt32(m_num_channels);
|
|
99
|
+
s.writeFloatArray(m_prev_sample);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void deserializeToon(dsp::toon::Deserializer &d) override
|
|
103
|
+
{
|
|
104
|
+
m_num_channels = d.readInt32();
|
|
105
|
+
m_prev_sample = d.readFloatArray();
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
bool isResizing() const override { return false; }
|
|
96
109
|
|
|
97
110
|
private:
|