CSL  5.2
Test_Sources.cpp
Go to the documentation of this file.
1 //
2 // Test_Sources.cpp -- C main functions for CSL noise and other source 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 source tests
7 // There are other source tests in Test_Oscillators.cpp and Test_Envelopes.cpp
8 //
9 
10 #ifndef USE_JUCE
11 #define USE_TEST_MAIN // use the main() function in test_support.h
12 #include "Test_Support.cpp" // include all of CSL core and the test support functions
13 #else
14 #include "Test_Support.h"
15 #endif
16 
17 /////////////////////// Here are the actual unit tests ////////////////////
18 
19 /// Noise tests, WhiteNoise & PinkNoise - using Scalable to protect our ears
20 
21 void testNoises() {
22  WhiteNoise whitey(0.2); // amplitude, offset
23 // logMsg("dumping quiet white noise...");
24 // dumpTest(whitey);
25  logMsg("playing quiet white noise...");
26  runTest(whitey);
27  logMsg("quiet white noise done.");
28 
29  PinkNoise pinky(42, 0.8); // seed, amplitude, offset
30 // logMsg("dumping quiet pink noise with seed...");
31 // dumpTest(pinky);
32  logMsg("playing quiet pink noise with seed...");
33  runTest(pinky);
34  logMsg("quiet pink noise with seed done.");
35 }
36 
37 /// Plucked string simulation
38 
39 #include "KarplusString.h"
40 
41 void testString() {
42  KarplusString pluck(fRandM(80, 1024)); // rand freq range
43  pluck.setScale(0.6); // quiet
44  pluck.trigger(); // srart it
45  logMsg("playing plucked string...");
46  runTest(pluck, 5);
47  logMsg("done.");
48 }
49 
50 /// Test a chorus of strings -- this demo plays an endless loop of string arpeggii.
51 /// For each arpeggio, it picks a starting pitch and pitch step, a starting position
52 /// and position increment, and a duration; the inner loop then creates notes and sleeps.
53 
55  unsigned numStrings = 64; // # strings
56  Mixer mix(2); // stereo mix
57  UGenVector strings; // vector of strings
58  UGenVector pans; // vector of panners
59 
60  for (int i = 0; i < numStrings; i++) { // loop to create strings/panners
61  KarplusString * plk = new KarplusString(); // create string sources
62  plk->setScale(40.0 / (float) numStrings); // make them loud
63  strings.push_back(plk); // add strings to the vector of strings
64  Panner * pan = new Panner(*plk); // create stereo panners on the strings
65  pans.push_back(pan); // add panners to the vector
66  mix.addInput(*pan); // add panners to the mixer
67  }
68  theIO->setRoot(mix); // send mix to IO
69  logMsg("playing 64-string chorus...");
70  unsigned cnt = 0; // string cnt
71 
72  while(1) { // loop for string arpeggio phrases
73  int numN = iRandM(3, 10); // pick # notes to play
74  int pit1 = iRandM(30, 84); // pick start pitch (in MIDI)
75  int pitX = iRandM(1, 4); // pick pitch step
76  if (coin()) // pick step up or down
77  pitX = 0 - pitX;
78  float pos1 = fRandZ(); // pick starting pos (0 - 1)
79  if (pos1 == 0)
80  pos1 = 0.1;
81  pos1 = sqrtf(pos1); // sqrt of starting pos (moves it away from 0)
82  if (coin()) // pick pos L or R
83  pos1 = 0.0f - pos1;
84  float posX = (pos1 > 0) // calc pan step
85  ? ((0.0f - ((pos1 + 1.0f) / (float)numN)))
86  : ((1.0f - pos1) / (float)numN);
87  float dela = fRandM(0.08, 0.25); // calc delay
88  logMsg("n: %d p: %d/%d \tx: %5.2f/%5.2f \td:%5.2f", numN, pit1, pitX, pos1, posX, dela);
89  // note loop
90  for (int i = 0; i < numN; i++) { // loop to create string gliss
91 // logMsg("\t\ts: %d p: %d x: %5.2f", cnt, pit1, pos1);
92  // set freq to MIDI pitch
93  ((KarplusString *)strings[cnt])->setFrequency(keyToFreq(pit1));
94  pit1 += pitX;
95  // set pan
96  ((Panner *)pans[cnt])->setPosition(pos1);
97  pos1 += posX;
98  // trigger
99  ((KarplusString *)strings[cnt])->trigger();
100  if (sleepSec(dela)) // sleep
101  goto done; // exit if sleep was interrupted
102  cnt++; // pick next string
103  if (cnt == numStrings) // should I check ifthe string is still active?
104  cnt = 0; // reset string counter
105  }
106  sleepSec(fRandM(0.02, 0.2)); // sleep a bit between sets
107  }
108 done:
109  logMsg("done.");
110  for (int i = 0; i < numStrings; i++) { // loop to create strings/panners
111  delete strings[i];
112  delete pans[i];
113  }
114 }
115 
116 ///////////////// SoundFile tests ////////
117 
118 /// Test the sound file player - mono, stereo input files
119 
121 // SoundFile sfile(CGestalt::dataFolder(), "Piano_A5_mf_mono.aiff"); // open a piano note file
122  SoundFile sfile(CGestalt::dataFolder() + "MKG1a1b.aiff");
123 // SoundFile sfile(CGestalt::dataFolder(), "Piano_A5_mf.caf"); // play a piano note
124 // SoundFile sfile(CGestalt::dataFolder(), "splash_mono.aiff");
125 
126  sfile.dump(); // print snd file info
127 
128 // float * left = sfile.mWavetable.monoBuffer(0); // dump the first few samples
129 // for (unsigned j = 0; j < 1000; j += 4) // 0 to 1000 by 4
130 // printf("\t\t%5.3f\n", left[j]);
131 
132  logMsg("Playing sound file...");
133  sfile.trigger();
134  runTest(sfile);
135 // runTest(pan);
136  logMsg("done.");
137 }
138 
140  SoundFile sfile(CGestalt::dataFolder() + "piano-tones.aiff"); // load a piano note
141  sfile.dump(); // print snd file info
142 
143 // float * left = sfile.mSampleBuffer.monoBuffer(0); // dump the first few samples
144 // float * rite = sfile.mSampleBuffer.monoBuffer(1);
145 // for (unsigned j = 0; j < 1000; j++)
146 // printf("\t\t%5.3f : %5.3f\n", *left++, *rite++);
147 
148  logMsg("Playing sound file...");
149  sfile.trigger();
150  runTest(sfile);
151  logMsg("done.");
152 }
153 
154 #ifdef USE_MP3 // uses libsndfile for now
155 
156 /// Test the MP3 file reader
157 
158 void testMP3FilePlayer() {
159  MP3File sfile(CGestalt::dataFolder(), "Piano_B4_096.mp3", true); // convert and play an MP3 file
160 // MP3File sfile("/Users/stp/Code/FMAK/music/Rock/Hard/LZ/02 - The Rain Song.mp3", true);
161  fi.log(); // print snd file info
162  logMsg("Playing sound file...");
163  fi.trigger();
164  runTest(sfile);
165  logMsg("done.");
166 }
167 
168 #endif
169 
170 /// Test the sound file player with rate shift
171 
173  SoundFile * sfile = new SoundFile(CGestalt::dataFolder() + "whistle_mono.aiff");
174  sfile->dump(); // print snd file info
175  Panner pan(*sfile, 0.0); // a panner
176  logMsg("playing sound file...");
177  float rate = 0.8;
178  theIO->setRoot(pan); // make some sound
179  for (int i = 0; i < 4; i++) { // loop to play transpositions
180  sfile->setRate(rate);
181  sfile->trigger();
182  sleepSec(1.4); // sleep for the desired duration
183  sfile->setToEnd();
184  rate += 0.15;
185  }
186  theIO->clearRoot(); // make some silence
187  logMsg("done.");
188  delete sfile;
189 }
190 
191 /// Test the WaveShaper
192 
194  WaveShaper wvs(110, 0); // wave-shape 1 = clipping
195  ADSR adsr(3.0, 1, 1, 0.7, 1);
196  wvs.setScale(adsr);
197  logMsg("Playing WaveShaper 1");
198  adsr.trigger();
199  runTest(wvs, 3);
200  logMsg("done.");
201  WaveShaper wv2(110, 2); // wave-shape 1 = clipping
202  ADSR ads2(3.0, 1, 1, 0.7, 1);
203  wv2.setScale(ads2);
204  logMsg("Playing WaveShaper 2");
205  ads2.trigger();
206  runTest(wv2, 3);
207  logMsg("done.");
208  WaveShaper wv3(110, 1); // wave-shape 1 = clipping
209  ADSR ads3(3.0, 1, 1, 0.7, 1);
210  wv3.setScale(ads3);
211  logMsg("Playing WaveShaper 3");
212  ads3.trigger();
213  runTest(wv3, 3);
214  logMsg("done.");
215 }
216 
217 ///////////////// Instrument tests ////////
218 
219 /// Test basic FM instrument
220 
221 #include <BasicFMInstrument.h>
222 
224  FMInstrument * vox = new FMInstrument;
225  logMsg("Playing simple fm instrument...");
226  float dur = 6.0;
227  float * dPtr = & dur;
228  vox->setParameter(set_duration_f, 1, (void **) &dPtr, "f");
229  vox->play();
230  runTest(*vox, dur);
231  logMsg("done.");
232  delete vox;
233 }
234 
235 /// Test SOS instrument - play 3 different timbres
236 
237 #include <AdditiveInstrument.h>
238 
240  AdditiveInstrument * vox1 = new AdditiveInstrument(48, 1.75f);
241  AdditiveInstrument * vox2 = new AdditiveInstrument(48, 1.75f);
242  AdditiveInstrument * vox3 = new AdditiveInstrument(48, 1.75f);
243  logMsg("Playing 3 SOS instruments...");
244  vox1->playMIDI(1.0f, 1, 30, 127);
245  runTest(*vox1, 1.0f);
246  vox2->playMIDI(1.0f, 1, 30, 127);
247  runTest(*vox2, 1.0f);
248  vox3->playMIDI(1.0f, 1, 30, 127);
249  runTest(*vox3, 1.0f);
250  vox1->playMIDI(1.0f, 1, 30, 127);
251  runTest(*vox1, 1.0f);
252  vox2->playMIDI(1.0f, 1, 30, 127);
253  runTest(*vox2, 1.0f);
254  vox3->playMIDI(1.0f, 1, 30, 127);
255  runTest(*vox3, 1.0f);
256  logMsg("done.");
257  delete vox1;
258  delete vox2;
259  delete vox3;
260 }
261 
264  logMsg("Playing fancy fm instrument...");
265  float dur = 6.0;
266  float * dPtr = & dur;
267  float freq = 220.0;
268  float * fPtr = & freq;
269  vox->setParameter(set_duration_f, 1, (void **) &dPtr, "f");
270  vox->setParameter(set_c_freq_f, 1, (void **) &fPtr, "f");
271  vox->play();
272  runTest(*vox, dur);
273  logMsg("done.");
274  delete vox;
275 }
276 
277 /// Test SoundFile instrument
278 
279 #include <SndFileInstrument.h>
280 
282  SndFileInstrument vox(CGestalt::dataFolder(), "round.aiff");
283  logMsg("Playing sound file instrument...");
284  vox.play();
285  runTest(vox);
286  logMsg("done.");
287 }
288 
289 // Add a sound file to the given UGenVector and Mixer, add a panner on it to the panner UGenVector
290 
291 void addSndtoBank(char * nam, UGenVector &snds, UGenVector &pans, Mixer &mix) {
292  SoundFile * sfile = new SoundFile(CGestalt::dataFolder() + nam);
293  snds.push_back(sfile); // add strings to the vector of strings
294  Panner * pan = new Panner(*sfile); // create stereo panners on the strings
295  pans.push_back(pan); // add panners to the vector
296  mix.addInput(*pan); // add panners to the mixer
297 }
298 
299 // Create a bank of 64 sample players using the above function
300 // run a loop playing stuttering sound samlpes
301 
303  unsigned numSounds = 64; // # sound files
304  Mixer mix(2); // stereo mix
305  UGenVector snds; // vector of sound files
306  UGenVector pans; // vector of panners
307 
308  for (int i = 0; i < numSounds / 4; i++) { // loop to set up snd file bank
309  addSndtoBank("Columbia-44_1.aiff", snds, pans, mix);
310  addSndtoBank("MKG1a1b.aiff", snds, pans, mix);
311  addSndtoBank("round.aiff", snds, pans, mix);
312  addSndtoBank("sns.aiff", snds, pans, mix);
313  }
314  Stereoverb reverb(mix); // stereo reverb
315  reverb.setRoomSize(0.98); // long reverb time
316  theIO->setRoot(reverb); // send mix to IO
317  logMsg("playing sound file forest...");
318 
319  while (1) { // loop for snd files
320  int numN = iRandM(3, 8); // pick # notes to play
321  int which = iRandM(0, 4); // pick which snd
322  int base = which * numSounds / 4;
323  // pick start point
324  SoundFile * snd = ((SoundFile *)snds[base]);
325  int startp = iRandV(snd->duration());
326  float dela = fRandM(0.05, 0.15); // calc delay
327  int dur = (int)(fRandM(dela, dela * 4.0f) * (float)CGestalt::frameRate()); // calc dur
328 
329  logMsg("n: %d s: %d fr: %d \tdu: %d", numN, which, startp, dur);
330  // note loop
331  for (int i = 0; i < numN; i++) { // loop to create snd file "stutter"
332  snd = ((SoundFile *)snds[which + numN]);
333  snd->setStart(startp);
334  snd->setStop(startp + dur);
335  // set pan to rand
336  ((Panner *)pans[which + numN])->setPosition(fRand1());
337  snd->trigger(); // trigger
338  if (sleepSec(dela)) // sleep
339  goto done; // exit if sleep was interrupted
340  }
341  }
342 done:
343  logMsg("done.");
344  for (int i = 0; i < numSounds; i++) { // loop to create strings/panners
345  delete snds[i];
346  delete pans[i];
347  }
348 }
349 
350 // Play a grain cloud
351 
352 #include <Granulator.h>
353 
355  GrainCloud cloud; // grain cloud
356  GrainPlayer player(& cloud); // grain player
357  // open and read in a file for granulation
358  SoundFile sndFile(CGestalt::dataFolder() + "MKG1a1b.aiff");
359  sndFile.dump();
360 
361  cloud.mSamples = sndFile.mWavetable.buffer(0);
362  cloud.numSamples = sndFile.duration();
363  cloud.mRateBase = 1.0f; // set the grain cloud parameters
364  cloud.mRateRange = 0.8f;
365  cloud.mOffsetBase = 0.5f;
366  cloud.mOffsetRange = 0.5f;
367  cloud.mDurationBase = 0.15f;
368  cloud.mDurationRange = 0.12f;
369  cloud.mDensityBase = 16.0f;
370  cloud.mDensityRange = 10.0f;
371  cloud.mWidthBase = 0.0f;
372  cloud.mWidthRange = 1.0f;
373  cloud.mVolumeBase = 8.0f;
374  cloud.mVolumeRange = 20.5f;
375  cloud.mEnvelopeBase = 0.5f;
376  cloud.mEnvelopeRange = 0.49f;
377  logMsg("playing Granular cloud.");
378  cloud.startThreads(); // start the grain create/reap threads
379  runTest(player, 15);
380  logMsg("done.");
381  cloud.isPlaying = false;
382  sleepSec(0.5);
383 }
384 
385 ///////////////// IFFT tests ////////
386 
387 void test_ifft() {
388  IFFT vox; // use default IFFT parameters
389  vox.setBinMagPhase(2, 0.25, 0); // set a few harmonics
390  vox.setBinMagPhase(4, 0.08, 0);
391  vox.setBinMagPhase(6, 0.04, 0);
392  vox.setBinMagPhase(8, 0.02, 0);
393 // vox.setBinMagPhase(5, 0.1, 0); // 5th bin = 440 Hz?
394  logMsg("playing IFFT...");
395  runTest(vox);
396  logMsg("IFFT done.");
397 }
398 
399 /// do vector cross-fade the long way
400 
402  float dur = 8.0f;
403  IFFT vox1, vox2; // create ifft players
404 
405  vox1.setBinMagPhase(4, 0.25, 0); // set different harmonics
406  vox1.setBinMagPhase(6, 0.25, 0);
407  LineSegment env1(dur, 1, 0.0001);
408  MulOp mul1(vox1, env1); // use a MulOp
409 
410  vox2.setBinMagPhase(5, 0.25, 0); // for the 2nd IFFT
411  vox2.setBinMagPhase(9, 0.25, 0);
412  LineSegment env2(dur, 0.0001, 1);
413  MulOp mul2(vox2, env2);
414 
415  AddOp add(mul1, mul2); // sum the MulOps
416 
417  logMsg("playing IFFT crossfade...");
418  runTest(add, dur);
419  logMsg("IFFT crossfade done.");
420 }
421 
422 //////// RUN_TESTS Function ////////
423 
424 #ifndef USE_JUCE
425 
426 void runTests() {
427 // testNoises();
428 // testString();
429 // testMonoSoundFilePlayer();
430 // testStereoSoundFilePlayer();
431 // testMP3FilePlayer();
432 // testSoundFileTranspose();
433 // testFMInstrument();
434 // testSndFileInstrument();
435 // testFancyFMInstrument();
436  test_ifft();
437 // test_vector_ifft();
438 }
439 
440 #else
441 
442 // test list for Juce GUI
443 
444 testStruct srcTestList[] = {
445  "Noise tests", testNoises, "Test noise generators",
446  "Plucked string", testString, "Waves of string arpeggii, stereo with reverb",
447  "String melodies", testStringChorus, "Many random string arpeggii",
448  "Mono snd file player", testMonoFilePlayer, "Test playing a sound file",
449  "Stereo snd file player", testStereoFilePlayer, "Play a stereo sound file",
450 #ifdef USE_MP3
451  "MP3 Snd file player", testMP3FilePlayer, "Play an MP3 file",
452 #endif
453  "Snd file transpose", testSoundFileTranspose, "Demonstrate transposing a sound file",
454  "Sample file bank", testSndFileBank, "Play a large sample bank from sound files",
455  "FM instrument", testFMInstrument, "Play the basic FM instrument",
456  "Fancy FM instrument", testFancyFMInstrument, "FM note with attack chiff and vibrato",
457  "SumOfSines instrument", testSOSInstrument, "Demonstrate the SumOfSines instrument",
458  "Snd file instrument", testSndFileInstrument, "Test the sound file instrument",
459  "WaveShaping synthesis", testWaveShaper, "Play 2 wave-shaper notes with envelopes",
460  "IFFT synthesis", test_ifft, "Make a sound with IFFT synthesis",
461  "Vector IFFT", test_vector_ifft, "Vector synthesis with 2 IFFTs",
462  "Soundfile granulation", testGrainCloud, "Random sound file granulation example",
463  NULL, NULL, NULL
464 };
465 
466 #endif