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