1 // Copyright 2014 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.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/modulation_96k.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_easter_egg(true);
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->frequency_shift_pot = 0.85f + 0.0f * triangle + 0.0f * filtered_noise;
182 p->frequency_shift_cv = 0.0f;
183 p->carrier_shape = 1;
184 p->channel_drive[0] = 0.0f;
185 p->channel_drive[1] = 1.0f;
186 p->modulation_parameter = 0.0f + 0.0f * square;
187 p->note = 48.0f + phi;
188
189 ShortFrame input[kBlockSize];
190 ShortFrame output[kBlockSize];
191
192 if (fread(
193 input,
194 sizeof(ShortFrame),
195 kBlockSize,
196 fp_in) != kBlockSize) {
197 break;
198 }
199
200 for (size_t i = 0; i < kBlockSize; ++i) {
201 input[i].r = input[i].l;
202 input[i].l = 0;
203 }
204 modulator.Process(input, output, kBlockSize);
205 wav_writer.WriteFrames((short*)(output), kBlockSize);
206 }
207 fclose(fp_in);
208 }
209
TestOscillators()210 void TestOscillators() {
211 WavWriter wav_writer(2, kSampleRate, 15);
212 wav_writer.Open("warps_oscillator.wav");
213
214 Modulator modulator;
215 modulator.Init(kSampleRate);
216
217 Parameters* p = modulator.mutable_parameters();
218
219 p->carrier_shape = 3;
220 p->channel_drive[0] = 0.0f;
221 p->channel_drive[1] = 0.0f;
222 p->modulation_algorithm = 0.0f;
223 p->modulation_parameter = 0.0f;
224
225 ShortFrame input[kBlockSize];
226 ShortFrame zero;
227 zero.l = zero.r = 0.0f;
228 fill(&input[0], &input[kBlockSize], zero);
229
230 while (!wav_writer.done()) {
231 float triangle = wav_writer.triangle();
232 p->note = 20 + triangle * 0;
233
234 ShortFrame output[kBlockSize];
235 modulator.Process(input, output, kBlockSize);
236 wav_writer.WriteFrames((short*)(output), kBlockSize);
237 }
238 }
239
TestFilterBankReconstruction()240 void TestFilterBankReconstruction() {
241 FilterBank fb;
242 fb.Init(96000.0);
243
244 size_t num_blocks = 1000;
245 const size_t block_size = 96;
246
247 FILE* fp_out = fopen("warps_filterbank_ir_float32.bin", "wb");
248
249 float in[block_size];
250 float out[block_size];
251
252 for (size_t i = 0; i < num_blocks; ++i) {
253 fill(&in[0], &in[block_size], 0.0f);
254 if (i == 0) {
255 in[0] = 1.0f;
256 }
257 fb.Analyze(in, block_size);
258
259 for (int32_t j = 0; j < kNumBands; ++j) {
260 if (false) {
261 float* samples = fb.band(j).samples;
262 size_t size = block_size / fb.band(j).decimation_factor;
263 fill(&samples[0], &samples[size], 0.0f);
264 }
265 }
266
267 fb.Synthesize(out, block_size);
268 fwrite(out, sizeof(float), block_size, fp_out);
269 }
270 fclose(fp_out);
271
272 // The impulse response and frequency responses can be seen with the following
273 // python program:
274 //
275 // import numpy
276 // import pylab
277 //
278 // x = numpy.fromfile('warps_filterbank_ir_float32.bin', dtype=numpy.float32)
279 // pylab.subplot(211)
280 // pylab.plot(x[:500])
281 // pylab.subplot(212)
282 // xf = numpy.fft.rfft(x)
283 // N = len(xf)
284 // f = numpy.arange(0.0, N) / N * 48000
285 // pylab.semilogx(f, 20 * numpy.log10(numpy.abs(xf + 1e-8)))
286 // pylab.show()
287 }
288
TestSineTransition()289 void TestSineTransition() {
290 WavWriter wav_writer(2, kSampleRate, 15);
291 wav_writer.Open("warps_sine_transition.wav");
292
293 Modulator modulator;
294 modulator.Init(kSampleRate);
295
296 Parameters* p = modulator.mutable_parameters();
297
298 while (!wav_writer.done()) {
299 float triangle = wav_writer.triangle();
300 p->carrier_shape = 1;
301 p->channel_drive[0] = 0.0;
302 p->channel_drive[1] = 0.0f;
303 p->modulation_algorithm = 0.0f + 0.125f * triangle;
304 p->modulation_parameter = 0.0f;
305 p->note = 36.0f;
306
307 ShortFrame input[kBlockSize];
308 ShortFrame output[kBlockSize];
309
310 for (size_t i = 0; i < kBlockSize; ++i) {
311 input[i].r = 0;
312 input[i].l = 0;
313 }
314
315 modulator.Process(input, output, kBlockSize);
316 wav_writer.WriteFrames((short*)output, kBlockSize);
317 }
318 }
319
TestGain()320 void TestGain() {
321 WavWriter wav_writer(2, kSampleRate, 10);
322 wav_writer.Open("warps_gain.wav");
323
324 Modulator modulator;
325 modulator.Init(kSampleRate);
326
327 Parameters* p = modulator.mutable_parameters();
328
329 float phase = 0.0f;
330 while (!wav_writer.done()) {
331 float triangle = wav_writer.triangle();
332
333 p->carrier_shape = 0;
334 p->channel_drive[0] = triangle * 1.0f;
335 p->channel_drive[1] = 0.0f;
336 p->modulation_algorithm = 0.0f + 0.125f * 0.0f;
337 p->modulation_parameter = 0.0f;
338 p->note = 36.0f;
339
340 ShortFrame input[kBlockSize];
341 ShortFrame output[kBlockSize];
342
343 for (size_t i = 0; i < kBlockSize; ++i) {
344 input[i].l = 20480.0f * sinf(phase * 2 * M_PI);
345 input[i].r = 20480.0f * sinf(phase * 2 * M_PI);
346 phase += 220.0f / kSampleRate;
347 if (phase >= 1.0f) {
348 phase -= 1.0f;
349 }
350 }
351
352 modulator.Process(input, output, kBlockSize);
353 wav_writer.WriteFrames((short*)output, kBlockSize);
354 }
355 }
356
TestQuadratureOscillator()357 void TestQuadratureOscillator() {
358 WavWriter wav_writer(2, kSampleRate, 10);
359 wav_writer.Open("warps_quadrature.wav");
360 QuadratureOscillator q;
361 q.Init(kSampleRate);
362 while (!wav_writer.done()) {
363 float triangle = wav_writer.triangle();
364 float x[2];
365 q.Render(triangle, 100.8f, &x[0], &x[1], 1);
366 wav_writer.Write(x, 2, 32767.0f);
367 }
368 }
369
main(void)370 int main(void) {
371 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
372 TestSRCUp<SampleRateConverter<SRC_UP, 6, 48> >("warps_src_up_fir_48.wav");
373 TestSRC96To576To96();
374 // TestModulator();
375 // TestEasterEgg();
376 TestOscillators();
377 TestFilterBankReconstruction();
378 TestSineTransition();
379 TestGain();
380 TestQuadratureOscillator();
381 }
382