CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

Test_Panners.cpp
Go to the documentation of this file.
1 //
2 // Test_Panners.cpp -- C main functions for the basic CSL panner and mixer tests.
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5 // This program simply reads the run_tests() function (at the bottom of this file)
6 // and executes a list of basic CSL tests
7 //
8
9 #ifdef USE_JUCE
10 #include "Test_Support.h"
11 #else
12 #define USE_TEST_MAIN // use the main() function in test_support.h
13 #include "Test_Support.cpp" // include all of CSL core and the test support functions
14 #endif
15
16 //#define USE_CONVOLVER
17
18 #ifdef USE_CONVOLVER
19 #include "Convolver.h" // FFT-based convolver
20 #endif
21
22 /////////////////////// Here are the actual unit tests ////////////////////
23
24 /// Pan a sine to stereo
25
26 void testPan() {
27 Osc vox(440); // src sine
28 Osc lfo(0.2, 1, 0, CSL_PI); // position LFO
29 vox.setScale(0.3);
30 Panner pan(vox, lfo); // panner
31 logMsg("playing a panning sine...");
32 runTest(pan, 8);
33 logMsg("done.\n");
34 }
35
36 /// Pan a sine to "N" channels
37
38 void testN2MPan() {
39 Osc vox(440);
40 Osc lfoX(0.2, 1, 0, CSL_PI);
41 Osc lfoY(0.2, 1, 0, 0);
42 vox.setScale(0.3);
43 // NtoMPanner(UnitGenerator & i, UnitGenerator & pX, UnitGenerator & pY, float a, unsigned in_c, unsigned out_c, float spr);
44 NtoMPanner pan(vox, lfoX, lfoY, 1, 1, 2, 2); // a panner
45 logMsg("playing N-channel panning sine...");
46 runTest(pan, 5);
47 logMsg("done.\n");
48 }
49
50 /// Test mixer -- really slow additive synthesis
51
52 void testSineMixer() {
53 Osc vox1(431, 0.3); // create 4 scaled sine waves
54 Osc vox2(540, 0.1);
55 Osc vox3(890, 0.03);
56 Osc vox4(1280, 0.01);
57 // AR vol(5, 1, 1); // amplitude envelope
58 // Mixer mix(2, vol); // stereo mixer with envelope
59 Mixer mix(2); // create a stereo mixer
60 mix.addInput(vox1); // add the sines to the mixer
61 mix.addInput(vox2);
62 mix.addInput(vox3);
63 mix.addInput(vox4);
64 logMsg("playing mix of 4 sines...");
65 runTest(mix);
66 logMsg("mix done.\n");
67 }
68
69 /// Pan and mix 2 sines
70
71 void testPanMix() {
72 Osc vox1, vox2; // sources oscs
73 RandEnvelope env1(0.5, 80, 180); // random freq envelopes
74 RandEnvelope env2(0.5, 80, 180); // (frq, amp, offset, step)
75 vox1.setFrequency(env1); // set osc freq and scale
76 vox1.setScale(0.3);
77 vox2.setFrequency(env2);
78 vox2.setScale(0.3);
79 Osc lfo1(0.3), lfo2(0.5, 1, 0, CSL_PI);// position LFOs (out of phase)
80 Panner pan1(vox1, lfo1); // 2 panners
81 Panner pan2(vox2, lfo2);
82 Mixer mix(2); // stereo mixer
83 mix.addInput(pan1);
84 mix.addInput(pan2);
85 logMsg("playing mix of panning sins...");
86 #ifndef CSL_WINDOWS
87 srand(getpid()); // seed the rand generator -- UNIX SPECIFIC CODE HERE
88 #endif
89 runTest(mix, 15);
90 logMsg("done.\n");
91 }
92
93 /// Pan and mix many sines
94
95 void testBigPanMix() {
96 int num = 64; // # of layers
97 float scale = 3.0f / (float) num; // ampl scale
98 Mixer mix(2); // stereo mixer
99 for (int i = 0; i < num; i++) { // loop to add a panning, LFO-controlled osc to the mix
100 Osc * vox = new Osc();
101 RandEnvelope * env = new RandEnvelope(0.5, 80, 180);
102 vox->setFrequency(*env);
103 vox->setScale(scale);
104 Osc * lfo = new Osc(fRandM(0.5, 0.9), 1, 0, fRandM(0, CSL_PI));
105 Panner * pan = new Panner(*vox, *lfo);
106 mix.addInput(*pan);
107 }
108 logMsg("playing mix of %d panning sins...", num);
109 #ifndef CSL_WINDOWS
110 srand(getpid()); // seed the rand generator -- UNIX SPECIFIC CODE HERE
111 #endif
112 runTest(mix, 60);
113 logMsg("done.\n");
114 mix.deleteInputs(); // clean up
115 }
116
117 /// Make a bank or 50 sines with random walk panners and glissandi
118
119 void testOscBank() {
120 Mixer mix(2); // stereo mixer
121 for (unsigned i = 0; i < 50; i++) { // RandEnvelope(float frequency, float amplitude, float offset, float step);
122 RandEnvelope * pos = new RandEnvelope;
123 RandEnvelope * freq = new RandEnvelope(0.8, 200, 300, 20);
124 // Sine * vox = new Sine(110.0, 0.01); // use computed sine
125 Osc * vox = new Osc(110.0, 0.01); // use stored look-up table
126 vox->setFrequency(* freq);
127 Panner * pan = new Panner(* vox, * pos);
128 mix.addInput(pan);
129 }
130 logMsg("playing mix of panning sines...");
131 #ifndef CSL_WINDOWS
132 srand(getpid()); // seed the rand generator so we get different results -- UNIX SPECIFIC CODE HERE
133 #endif
134 runTest(mix, 60);
135 logMsg("done.\n");
136 mix.deleteInputs(); // clean up
137 }
138
139 /// swap sound channels with a ChannelMappedBuffer InOut
140 /// Constructor: InOut(input, inChan, outChan, [ch-1 ... ch-outChan]);
141
142 #include "InOut.h" /// Copy in-out plug
143
144 void testCMapIO() {
145 Osc osc(220); // carrier to be enveloped
146 AR a_env(2, 0.6, 1.0); // AR constructor dur, att, rel
147 osc.setScale(a_env); // amplitude modulate the sine
148 Panner pan(osc, 0.0); // panner
149 InOut chanMap(pan, 2, 2, kNoProc, 2, 1); // swap stereo channels
150 logMsg("playing swapped sin...");
151 runTest(chanMap);
152 logMsg("done.\n");
153 }
154
155 ////////// Convolution
156
157 #ifdef USE_CONVOLVER
158
159 void testConvolver() {
160 JSoundFile fi(CGestalt::dataFolder(), "rim3_L.aiff");
161 try {
162 fi.openForRead();
163 } catch (CException) {
164 logMsg(kLogError, "Cannot read sound file...");
165 return;
166 }
167 logMsg("playing sound file...");
168 fi.trigger();
169 runTest(fi);
170 logMsg("sound file player done.\n");
171 // Create convolver; FFT size will be block size * 2
172 Convolver cv(CGestalt::dataFolder(), "Quadraverb_large_L.aiff");
173 cv.setInput(fi);
174 logMsg("playing convolver...");
175 fi.trigger();
176 runTest(cv);
177 fi.trigger();
178 runTest(cv);
179 fi.close();
180 logMsg("convolver done.\n");
181 }
182
183 #define IRLEN (44100 * 4) // 4 sec. IR
184
185 void testConvolver2() {
186 WhiteNoise nois; // amplitude, offset
187 AR env(0.05, 0.0001, 0.049); // AR constructor dur, att, rel
188 nois.setScale(env); // amplitude modulate the sine
189
190 logMsg("playing noise burst...");
191 env.trigger();
192 runTest(nois);
193 logMsg("done.\n");
194 // make a simple IR with a few echoes
195 Buffer buf(1, IRLEN);
196 buf.allocateBuffers();
197 float * samp = buf.monoBuffer(0);
198 for (unsigned i = 0; i < IRLEN; i += 5000)
199 samp[i] = 1 / (1 + (sqrt(i) / 5000));
200 // Create convolver; FFT size will be block size * 2
201 Convolver cv(buf);
202 cv.setInput(nois);
203 logMsg("playing convolver...");
204 env.trigger();
205 runTest(cv);
206 env.trigger();
207 runTest(cv);
208 logMsg("convolver done.\n");
209 }
210
211 void testConvolver3() {
212 WhiteNoise nois; // amplitude, offset
213 AR env(0.05, 0.0001, 0.049); // AR constructor dur, att, rel
214 nois.setScale(env); // amplitude modulate the sine
215
216 logMsg("playing noise burst...");
217 env.trigger();
218 runTest(nois);
219 logMsg("done.\n");
220 Convolver cv(CGestalt::dataFolder(), "3.3s_LargeCathedral_mono.aiff");
221 cv.setInput(nois);
222 logMsg("playing convolver...");
223 env.trigger();
224 runTest(cv);
225 env.trigger();
226 runTest(nois);
227 env.trigger();
228 runTest(cv);
229 logMsg("convolver done.\n");
230 }
231
232 #endif
233
234 #ifndef CSL_WINDOWS
235
236 /// Spatializer with HRTF
237
238 #include "SpatialAudio.h"
239 #include "Binaural.h"
240
241 /// Repeat a short test file moving in circles around the horizontal plane
242
243 void test_Binaural_horiz() {
244 // Open a mono soundfile
245 SoundFile sndfile(CGestalt::dataFolder() + "splash_mono.aiff");
246 sndfile.dump();
247
248 char folder[CSL_NAME_LEN]; // create HRTF data location
249 strcpy(folder, CGestalt::dataFolder().c_str()); // CSL data folder location
250 strcat(folder, "IRCAM_HRTF/512_DB/HRTF_1047.dat"); // HRTF data location
251 HRTFDatabase::Reload(folder); // Load the HRTF data
252 HRTFDatabase::Database()->dump();
253
254 // make the sound "Positionable"
255 SpatialSource source(sndfile);
256 // Create a spatializer.
257 Spatializer panner(kBinaural);
258 // Add the sound source to it
259 panner.addSource(source);
260 // loop to play transpositions
261 logMsg("playing HRTF-spatialized rotating sound source (horizontal plane)...");
262 theIO->setRoot(panner); // make some sound
263
264 for (int i = 0; i < 30; i++) {
265 source.setPosition('s', (float) (i * 24), 0.0f, 2.0f); // rotate in small steps
266 source.dump();
267 sndfile.trigger();
268 sleepSec(0.8);
269 }
270 theIO->clearRoot();
271 logMsg("done.");
272 }
273
274 /// Repeat a short test file moving in circles around the vertical plane at AZ = CSL_PIHALF
275 /// (axial plane in line with your ears, easy to localize)
276
277 void test_Binaural_vertAxial() {
278 // Open a mono soundfile
279 SoundFile sndfile(CGestalt::dataFolder() + "guanno_mono.aiff");
280 sndfile.dump();
281 // make the sound "Positionable"
282 SpatialSource source(sndfile);
283 // Create a spatializer.
284 Spatializer panner(kBinaural);
285 // Add the sound source to it
286 panner.addSource(source);
287 // loop to play transpositions
288 logMsg("playing HRTF-spatialized rotating sound source (vertical plane)...");
289 theIO->setRoot(panner); // make some sound
290 for (int i = 30; i > 6; i--) {
291 source.setPosition('s', CSL_PIHALF, (float) (i * 15), 2.0f); // rotate in small steps
292 source.dump();
293 sndfile.trigger();
294 sleepSec(0.8);
295 }
296 theIO->clearRoot();
297 logMsg("done.");
298 }
299
300 /// Repeat a short test file moving in circles around the vertical plane at AZ = 0
301 /// (median plane between your ears, hard to localize)
302
303 void test_Binaural_vertMedian() {
304 // Open a mono soundfile
305 SoundFile sndfile(CGestalt::dataFolder() + "triangle_mono.aiff");
306 sndfile.openForRead();
307 sndfile.dump();
308 sndfile.setToEnd();
309 // make the sound "Positionable"
310 SpatialSource source(sndfile);
311 // Create a spatializer.
312 Spatializer panner(kBinaural);
313 // Add the sound source to it
314 panner.addSource(source);
315 // loop to play transpositions
316 logMsg("playing HRTF-spatialized rotating sound source (medial plane)...");
317 theIO->setRoot(panner); // make some sound
318 for (int i = 30; i > 6; i--) {
319 source.setPosition('s', 0.0f, (float) (i * 15), 2.0f); // rotate in small steps
320 source.dump();
321 sndfile.trigger();
322 sleepSec(0.8);
323 }
324 theIO->clearRoot();
325 logMsg("done.");
326 }
327
328 /// Spatializer with Ambisonics
329
330 void test_Ambi_horiz() {
331 // Open a mono soundfile
332 SoundFile sndfile(CGestalt::dataFolder() + "triangle_mono.aiff");
333 sndfile.dump();
334 // make the sound "Positionable"
335 SpatialSource source(sndfile);
336 // Create a spatializer.
337 Spatializer panner(kAmbisonic);
338 // Add the sound source to it
339 panner.addSource(source);
340 // loop to play transpositions
341 logMsg("playing Ambisonic-spatialized rotating sound source (horizontal plane)...");
342 theIO->setRoot(panner); // make some sound
343 for (int i = 0; i < 30; i++) {
344 source.setPosition('s', (float) (i * 24), 0.0f, 2.0f); // rotate in small steps
345 source.dump();
346 sndfile.trigger();
347 sleepSec(0.8);
348 }
349 theIO->clearRoot();
350 logMsg("done.");
351 }
352
353 /// Spatializer with simple panners & filters and/or reverb
354
355 void test_SimpleP() {
356 // Open a mono soundfile
357 SoundFile sndfile(CGestalt::dataFolder() + "Piano_A5_mf_mono.aiff");
358 sndfile.dump();
359 // make the sound "Positionable"
360 SpatialSource source(sndfile);
361 // Create a "simple" spatializer.
362 Spatializer panner(kSimple);
363 // Add the sound source to it
364 panner.addSource(source);
365 // loop to play transpositions
366 logMsg("playing simply spatialized rotating sound source...");
367 Mixer mix(2);
368 mix.addInput(panner);
369 theIO->setRoot(mix); // make some sound
370 for (int i = 0; i < 30; i++) {
371 // rotate in small steps, getting farther away
372 source.setPosition('s', (float) (i * 24.0f), 0.0f, (2.0f + (i * 0.15f)));
373 source.dump();
374 sndfile.trigger();
375 sleepSec(0.9);
376 }
377 theIO->clearRoot();
378 logMsg("done.");
379 }
380
381 /// Spatializer with VBAP
382
383 void test_VBAP_horiz() {
384 // Open a mono soundfile
385 SoundFile sndfile(CGestalt::dataFolder() + "triangle_mono.aiff");
386 sndfile.openForRead();
387 sndfile.dump();
388 sndfile.setToEnd();
389 // make the sound "Positionable"
390 SpatialSource source(sndfile);
391 // Create a spatializer.
392 Spatializer panner(kVBAP);
393 // Add the sound source to it
394 panner.addSource(source);
395 // loop to play transpositions
396 logMsg("playing VBAP-spatialized rotating sound source (horizontal plane)...");
397 theIO->setRoot(panner); // make some sound
398 for (int i = 0; i < 30; i++) {
399 source.setPosition('s', (float) (i * 24), 0.0f, 2.0f); // rotate in small steps
400 source.dump();
401 sndfile.trigger();
402 sleepSec(0.8);
403 }
404 theIO->clearRoot();
405 logMsg("done.");
406 }
407
408 #endif
409
410 //////// RUN_TESTS Function ////////
411
412 #ifndef USE_JUCE
413
414 void runTests() {
415 // testPan();
416 // testN2MPan();
417 // testSineMixer();
418 // testPanMix();
419 // testConvolver();
420 // testConvolver2();
421 // testConvolver3();
422 // testOscBank();
423 // testCMapIO();
424 test_Binaural_horiz();
425 // test_Binaural_vertAxial();
426 // test_Binaural_vertMedian();
427 }
428
429 #else
430
431 // test list for Juce GUI
432
433 testStruct panTestList[] = {
434 "Stereo panner", testPan, "Demonstrate the stero panner",
435 // "N2M panner", testN2MPan,
436 "Mixer", testSineMixer, "Mixer with 4 sine inputs (slow sum-of-sines)",
437 "Panning mixer", testPanMix, "Play a panning stereo mixer",
438 "Bigger panning mixer", testBigPanMix, "Test a mixer with many inputs",
439 #ifdef USE_CONVOLVER
440 "Test convolver", testConvolver, "Test a convolver",
441 "Test convolver 2", testConvolver2, "Test a convolver",
442 "Test convolver 3", testConvolver3, "Test a convolver",
443 #endif
444 "Osc bank", testOscBank, "Mix a bank of oscillators",
445 "Channel-mapped IO", testCMapIO, "Demonstrate channel-mapped IO",
446 #ifndef CSL_WINDOWS
447 "HRTF horiz circles", test_Binaural_horiz, "Test the HRTF-based binaural panner",
448 "HRTF axial circles", test_Binaural_vertAxial,"Play a HRTF-panner with axial circles",
449 "HRTF median circles", test_Binaural_vertMedian,"Play a HRTF-panner with median circles",
450 #endif
451 "Ambisonics", test_Ambi_horiz, "Test the Ambisonic-based spatial panner",
452 "Simple", test_SimpleP, "Test the simple spatial panner",
453 "VBAP", test_VBAP_horiz, "Test the VBAP-based spatial panner",
454 NULL, NULL, NULL
455 };
456
457 #endif