1 // Copyright 2014 Olivier Gillet.
2 //
3 // Author: Olivier Gillet (ol.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26
27
28 #include <cassert>
29 #include <cmath>
30 #include <cstdlib>
31 #include <cstring>
32 #include <vector>
33 #include <xmmintrin.h>
34
35 #include "stmlib/test/wav_writer.h"
36 #include "stmlib/utils/random.h"
37
38 #include "warps/dsp/modulator.h"
39 #include "warps/dsp/sample_rate_converter.h"
40 #include "warps/resources.h"
41
42 using namespace warps;
43 using namespace std;
44 using namespace stmlib;
45
46 const size_t kSampleRate = 96000;
47 const size_t kBlockSize = 96;
48
49 template<typename T>
TestSRCUp(const char * name)50 void TestSRCUp(const char* name) {
51 size_t ratio = 6;
52 WavWriter wav_writer(1, kSampleRate * ratio, 10);
53 wav_writer.Open(name);
54
55 T src_up;
56 src_up.Init();
57
58 float phase = 0.0f;
59 while (!wav_writer.done()) {
60 float samples_in[kBlockSize];
61 float samples_out[kBlockSize * ratio];
62 float instantenous_frequency = fmod(
63 4.0f * wav_writer.progress(),
64 0.5f);
65 for (size_t i = 0; i < kBlockSize; ++i) {
66 samples_in[i] = sinf(phase * 2 * M_PI);
67 phase += instantenous_frequency;
68 if (phase >= 1.0f) {
69 phase -= 1.0f;
70 }
71 }
72
73 src_up.Process(samples_in, samples_out, kBlockSize);
74 wav_writer.Write(samples_out, kBlockSize * ratio, 16067.0f);
75 }
76 }
77
TestSRC96To576To96()78 void TestSRC96To576To96() {
79 size_t ratio = 6;
80 WavWriter wav_writer(1, kSampleRate, 10);
81 wav_writer.Open("warps_src_96_576_96.wav");
82
83 SampleRateConverter<SRC_UP, 6, 48> src_up;
84 SampleRateConverter<SRC_DOWN, 6, 48> src_down;
85 src_up.Init();
86 src_down.Init();
87
88 float phase = 0.0f;
89 while (!wav_writer.done()) {
90 float samples_in[kBlockSize];
91 float samples_out[kBlockSize * ratio];
92 float instantenous_frequency = fmod(
93 2.0f * wav_writer.progress(),
94 0.5f);
95 for (size_t i = 0; i < kBlockSize; ++i) {
96 samples_in[i] = sinf(phase * 2 * M_PI);
97 phase += instantenous_frequency;
98 if (phase >= 1.0f) {
99 phase -= 1.0f;
100 }
101 }
102 src_up.Process(samples_in, samples_out, kBlockSize);
103 src_down.Process(samples_out, samples_in, kBlockSize * ratio);
104 wav_writer.Write(samples_in, kBlockSize, 32200.0f);
105 }
106 }
107
TestModulator()108 void TestModulator() {
109 FILE* fp_in = fopen("audio_samples/modulation_96k.wav", "rb");
110 WavWriter wav_writer(2, kSampleRate, 15);
111 wav_writer.Open("warps_modulator.wav");
112
113 fseek(fp_in, 48, SEEK_SET);
114
115 Modulator modulator;
116 modulator.Init(kSampleRate);
117
118 Parameters* p = modulator.mutable_parameters();
119
120 float phi = 0.0f;
121 float filtered_noise = 0.0f;
122
123 while (!wav_writer.done()) {
124 float triangle = wav_writer.triangle();
125 float square = 0.5f * SoftClip(32.0f * (triangle - 0.5f)) + 0.5f;
126 float noise = (Random::GetFloat() - 0.5f) / 128.0f;
127 filtered_noise += (noise - filtered_noise) * 0.1f;
128
129 p->carrier_shape = 1;
130 p->channel_drive[0] = 0.625f;
131 p->channel_drive[1] = 0.0f;
132 p->modulation_algorithm = 0.125f + 0.0f * square + 1.0f * filtered_noise;
133 p->modulation_parameter = 0.0f + 1.0f * triangle;
134 p->note = 48.0f + phi;
135
136 ShortFrame input[kBlockSize];
137 ShortFrame output[kBlockSize];
138
139 if (fread(
140 input,
141 sizeof(ShortFrame),
142 kBlockSize,
143 fp_in) != kBlockSize) {
144 break;
145 }
146
147 for (size_t i = 0; i < kBlockSize; ++i) {
148 input[i].r = input[i].l;
149 input[i].l = 0;
150 }
151 modulator.Process(input, output, kBlockSize);
152 wav_writer.WriteFrames((short*)(output), kBlockSize);
153 }
154 fclose(fp_in);
155 }
156
TestEasterEgg()157 void TestEasterEgg() {
158 FILE* fp_in = fopen("audio_samples/ericderr96.wav", "rb");
159
160 WavWriter wav_writer(2, kSampleRate, 15);
161 wav_writer.Open("warps_easter_egg.wav");
162
163 fseek(fp_in, 48, SEEK_SET);
164
165 Modulator modulator;
166 modulator.Init(kSampleRate);
167 modulator.set_feature_mode(FEATURE_MODE_CHEBYSCHEV);
168
169 Parameters* p = modulator.mutable_parameters();
170
171 float phi = 0.0f;
172 float filtered_noise = 0.0f;
173 while (!wav_writer.done()) {
174 uint16_t tri = (wav_writer.remaining_frames() / 8);
175 tri = tri > 32767 ? 65535 - tri : tri;
176 float triangle = 0.5f * SoftClip(8.0f * (tri / 32768.0f - 0.5f)) + 0.5f;
177 float square = 0.5f * SoftClip(32.0f * (tri / 32768.0f - 0.5f)) + 0.5f;
178 float noise = (Random::GetFloat() - 0.5f) / 128.0f;
179 filtered_noise += (noise - filtered_noise) * 0.1f;
180
181 p->raw_algorithm_pot = 1.0f + 0.0f * triangle + 0.0f * square;
182 p->raw_algorithm_cv = 0.0f;
183 p->raw_algorithm = 0.0f;// + 0.0f * triangle;// + 0.1f * filtered_noise;
184 p->modulation_algorithm = 0.3f;// + 1.0f * triangle;
185 p->carrier_shape = 0;
186 p->channel_drive[0] = 0.5f;
187 p->channel_drive[1] = 0.0f;
188 p->raw_level[0] = 0.6f;
189 p->raw_level[1] = 1.0f;
190 p->modulation_parameter = 1.0f;// + 0.05f * filtered_noise;
191 p->note = 48.0f + phi;
192
193 ShortFrame input[kBlockSize];
194 ShortFrame output[kBlockSize];
195
196 if (fread(
197 input,
198 sizeof(ShortFrame),
199 kBlockSize,
200 fp_in) != kBlockSize) {
201 break;
202 }
203
204 for (size_t i = 0; i < kBlockSize; ++i) {
205 input[i].r = input[i].r;
206 input[i].l = input[i].l;
207 }
208 modulator.Process(input, output, kBlockSize);
209 wav_writer.WriteFrames((short*)(output), kBlockSize);
210 }
211 fclose(fp_in);
212 }
213
TestOscillators()214 void TestOscillators() {
215 WavWriter wav_writer(2, kSampleRate, 15);
216 wav_writer.Open("warps_oscillator.wav");
217
218 Modulator modulator;
219 modulator.Init(kSampleRate);
220
221 Parameters* p = modulator.mutable_parameters();
222
223 p->carrier_shape = 1;
224 p->channel_drive[0] = 0.0f;
225 p->channel_drive[1] = 0.0f;
226 p->modulation_algorithm = 0.0f;
227 p->modulation_parameter = 0.0f;
228
229 ShortFrame input[kBlockSize];
230 ShortFrame zero;
231 zero.l = zero.r = 0.0f;
232 fill(&input[0], &input[kBlockSize], zero);
233
234 while (!wav_writer.done()) {
235 float triangle = wav_writer.triangle();
236 p->note = 20 + triangle * 0;
237
238 ShortFrame output[kBlockSize];
239 modulator.Process(input, output, kBlockSize);
240 wav_writer.WriteFrames((short*)(output), kBlockSize);
241 }
242 }
243
TestFilterBankReconstruction()244 void TestFilterBankReconstruction() {
245 FilterBank fb;
246 fb.Init(96000.0);
247
248 size_t num_blocks = 1000;
249 const size_t block_size = 96;
250
251 FILE* fp_out = fopen("warps_filterbank_ir_float32.bin", "wb");
252
253 float in[block_size];
254 float out[block_size];
255
256 for (size_t i = 0; i < num_blocks; ++i) {
257 fill(&in[0], &in[block_size], 0.0f);
258 if (i == 0) {
259 in[0] = 1.0f;
260 }
261 fb.Analyze(in, block_size);
262
263 for (int32_t j = 0; j < kNumBands; ++j) {
264 if (false) {
265 float* samples = fb.band(j).samples;
266 size_t size = block_size / fb.band(j).decimation_factor;
267 fill(&samples[0], &samples[size], 0.0f);
268 }
269 }
270
271 fb.Synthesize(out, block_size);
272 fwrite(out, sizeof(float), block_size, fp_out);
273 }
274 fclose(fp_out);
275
276 // The impulse response and frequency responses can be seen with the following
277 // python program:
278 //
279 // import numpy
280 // import pylab
281 //
282 // x = numpy.fromfile('warps_filterbank_ir_float32.bin', dtype=numpy.float32)
283 // pylab.subplot(211)
284 // pylab.plot(x[:500])
285 // pylab.subplot(212)
286 // xf = numpy.fft.rfft(x)
287 // N = len(xf)
288 // f = numpy.arange(0.0, N) / N * 48000
289 // pylab.semilogx(f, 20 * numpy.log10(numpy.abs(xf + 1e-8)))
290 // pylab.show()
291 }
292
TestSineTransition()293 void TestSineTransition() {
294 WavWriter wav_writer(2, kSampleRate, 15);
295 wav_writer.Open("warps_sine_transition.wav");
296
297 Modulator modulator;
298 modulator.Init(kSampleRate);
299
300 Parameters* p = modulator.mutable_parameters();
301
302 while (!wav_writer.done()) {
303 float triangle = wav_writer.triangle();
304 p->carrier_shape = 1;
305 p->channel_drive[0] = 0.0;
306 p->channel_drive[1] = 0.0f;
307 p->modulation_algorithm = 0.0f + 0.125f * triangle;
308 p->modulation_parameter = 0.0f;
309 p->note = 36.0f;
310
311 ShortFrame input[kBlockSize];
312 ShortFrame output[kBlockSize];
313
314 for (size_t i = 0; i < kBlockSize; ++i) {
315 input[i].r = 0;
316 input[i].l = 0;
317 }
318
319 modulator.Process(input, output, kBlockSize);
320 wav_writer.WriteFrames((short*)output, kBlockSize);
321 }
322 }
323
TestGain()324 void TestGain() {
325 WavWriter wav_writer(2, kSampleRate, 10);
326 wav_writer.Open("warps_gain.wav");
327
328 Modulator modulator;
329 modulator.Init(kSampleRate);
330
331 Parameters* p = modulator.mutable_parameters();
332
333 float phase = 0.0f;
334 while (!wav_writer.done()) {
335 float triangle = wav_writer.triangle();
336
337 p->carrier_shape = 0;
338 p->channel_drive[0] = triangle * 1.0f;
339 p->channel_drive[1] = 0.0f;
340 p->modulation_algorithm = 0.0f + 0.125f * 0.0f;
341 p->modulation_parameter = 0.0f;
342 p->note = 36.0f;
343
344 ShortFrame input[kBlockSize];
345 ShortFrame output[kBlockSize];
346
347 for (size_t i = 0; i < kBlockSize; ++i) {
348 input[i].l = 20480.0f * sinf(phase * 2 * M_PI);
349 input[i].r = 20480.0f * sinf(phase * 2 * M_PI);
350 phase += 220.0f / kSampleRate;
351 if (phase >= 1.0f) {
352 phase -= 1.0f;
353 }
354 }
355
356 modulator.Process(input, output, kBlockSize);
357 wav_writer.WriteFrames((short*)output, kBlockSize);
358 }
359 }
360
TestQuadratureOscillator()361 void TestQuadratureOscillator() {
362 WavWriter wav_writer(2, kSampleRate, 10);
363 wav_writer.Open("warps_quadrature.wav");
364 QuadratureOscillator q;
365 q.Init(kSampleRate);
366 while (!wav_writer.done()) {
367 float triangle = wav_writer.triangle();
368 float x[2];
369 q.Render(triangle, 100.8f, &x[0], &x[1], 1);
370 wav_writer.Write(x, 2, 32767.0f);
371 }
372 }
373
main(void)374 int main(void) {
375 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
376 //TestSRCUp<SampleRateConverter<SRC_UP, 6, 48> >("warps_src_up_fir_48.wav");
377 //TestSRC96To576To96();
378 // TestModulator();
379 TestEasterEgg();
380 //TestOscillators();
381 //TestFilterBankReconstruction();
382 //TestSineTransition();
383 //TestGain();
384 //TestQuadratureOscillator();
385 }
386