CSL  5.2
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 
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 
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 
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 
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 
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();
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