CSL 5.2

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

- File List
- File Members

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
54 void testStringChorus() {
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
120 void testMonoFilePlayer() {
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
139 void testStereoFilePlayer() {
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
172 void testSoundFileTranspose() {
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
193 void testWaveShaper() {
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
223 void testFMInstrument() {
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
239 void testSOSInstrument() {
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
262 void testFancyFMInstrument() {
263 FancyFMInstrument * vox = new FancyFMInstrument;
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
281 void testSndFileInstrument() {
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
302 void testSndFileBank() {
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
354 void testGrainCloud() {
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
401 void test_vector_ifft() {
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