CSL  5.2
Test_Envelopes.cpp
Go to the documentation of this file.
1 //
2 // Test_Envelopes.cpp -- C main functions for the basic CSL envelope and control patching 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 #ifndef USE_JUCE
10 #define USE_TEST_MAIN // use the main() function in test_support.h
11 #include "Test_Support.cpp" // include all of CSL core and the test support functions
12 #else
13 #include "Test_Support.h"
14 #endif
15 
16 /////////////////////// Here are the actual unit tests ////////////////////
17 
18 /// Apply a glissando to a sine with a LineSegment
19 
20 void testGliss() {
21  Osc vox;
22  LineSegment line(3, 2000, 60, kLine);
23  line.dump();
24  vox.setFrequency(line);
25  vox.setScale(0.3);
26  logMsg("playing gliss sin with linear segment...");
27  runTest(vox);
28  logMsg("done.\n");
29 
30  LineSegment line2(3, 2000, 60, kExpon);
31  line2.dump();
32  vox.setFrequency(line2);
33  logMsg("playing gliss sin with exponential segment...");
34  runTest(vox);
35  logMsg("done.\n");
36 }
37 
38 /// test an amplitude swell
39 
40 void testSwell() {
41  Osc vox(220);
42  LineSegment line(3, 0.0, 0.5);
43  vox.setScale(line);
44  vox.dump();
45  logMsg("playing swell sin with line segment...");
46  runTest(vox);
47  logMsg("done.\n");
48 }
49 
50 /// AM and FM using the dynamic scale and frequency inputs
51 
52 void testARSin() {
53  Osc osc(220); // carrier to be enveloped
54  AR a_env(2, 0.6, 1.0); // AR constructor dur, att, rel
55  osc.setScale(a_env); // amplitude modulate the sine
56  logMsg("AR env dump");
57  osc.dump();
58  logMsg("playing AR sin...");
59  a_env.trigger();
60  runTest(osc);
61  logMsg("done.\n");
62 }
63 
64 /// Do the same using the Envelope as an effect
65 
66 void testARSin2() {
67  Osc osc(220); // carrier to be enveloped
68  AR a_env(2, 0.2, 1.0); // AR constructor dur, att, rel
69  a_env.setScale(osc); // amplitude modulate the sine
70  logMsg("playing AR sin 2...");
71  a_env.trigger();
72  runTest(a_env);
73  logMsg("done.\n");
74 }
75 
76 /// Test an envelope applied to frequency
77 
79  Osc vox;
80  Envelope env(3, 0, 220, 0.7, 280, 1.3, 180, 2.0, 200, 3, 100);
81  logMsg("");
82  logMsg("BP env dump");
83  env.dump();
84  logMsg("");
85  vox.setFrequency(env);
86  vox.setScale(0.3);
87  logMsg("playing sin with BP envelope on frequency");
88  env.trigger();
89  runTest(vox);
90  logMsg("done.\n");
91 }
92 
93 /// Test an envelope applied to frequency & scale
94 
95 void testAMFMEnvs() {
96  Osc vox;
97  Envelope env(3, 0, 100, 0.7, 180, 1.3, 180, 2.0, 200, 3, 140);
98  Envelope env2(3, 0.0, 0, 1.0, 1, 2.5, 0, 2.75, 1, 3, 0);
99  vox.setFrequency(env);
100  vox.setScale(env2);
101  logMsg("playing sin with BP envelopes on frequency & scale");
102  fflush(stdout);
103  env.trigger();
104  env2.trigger();
105  runTest(vox);
106  logMsg("done.\n");
107 }
108 
109 
110 //////////////////////// Envelope tests ////////////////////////////////////////////
111 
112 /// Demonstrate an ADSR
113 
114 void testADSR2() {
115  float duration = 3.0; // total dur
116  float attack = 0.06; // att time
117  float decay = 0.1; // dec time
118  float sustain = 0.1; // sust value
119  float release = 1.5; // release time
120  ADSR adsr(duration, attack, decay, sustain, release); // constructor
121  Osc vox(220);
122  vox.setScale(adsr);
123  logMsg("playing sharp ADSR envelope.");
124  adsr.trigger();
125  runTest(vox);
126  logMsg("done.\n");
127 
128  ADSR adsr2(duration, 0.5, 0, 1, 0.5);
129  vox.setScale(adsr2);
130  logMsg("playing gradual ADSR envelope.");
131  adsr2.trigger();
132  runTest(vox);
133  logMsg("done.\n");
134 }
135 
136 /// FM using 2 oscs and 2 ADSRs
137 
138 #define BASE_FREQ 440.0
139 //#define BASE_FREQ 8000.0
140 
141 void testADSR_FM() {
142  ADSR a_env(3, 0.1, 0.1, 0.5, 1); // set up 2 standard ADSRs (3-sec duration)
143  ADSR i_env(3, 1.5, 0, 1, 0.4);
144  // percussive envelopes
145 // ADSR a_env(3, 0.02, 0.1, 0.05, 2); // set up 2 standard ADSRs (3-sec duration)
146 // ADSR i_env(3, 0.0001, 0.1, 0, 0);
147  Osc car(BASE_FREQ); // init the 2 oscillators (fc = fm)
148  Osc mod(BASE_FREQ*1.414);
149 // i_env.setScale(BASE_FREQ); // scale the index envelope by the mod. freq
150  i_env.setScale(BASE_FREQ);
151  mod.setScale(i_env);
152  mod.setOffset(BASE_FREQ);
153  car.setFrequency(mod);
154  car.setScale(a_env);
155  i_env.trigger();
156  a_env.trigger();
157  logMsg("playing ADSR FM\n");
158 // car.dump();
159  runTest(car);
160  logMsg("done.\n");
161 }
162 
163 /// test the rand env as the freq of a SOS
164 
166  SumOfSines sos(kFrequency, 6, 0.2, 0.2, 0.1, 0.05, 0.02, 0.02);
167  sos.createCache(); // make the cached wavetable
168  AR a_env(6, 1, 1); // dur, att, rel
169  // RandEnvelope (frq, amp, offset, step)
170  RandEnvelope f_env(3, 80, 200, 40); // freq env = random walk
171  sos.setFrequency(f_env); // set the carrier's frequency
172  sos.setScale(a_env); // multiply index envelope by mod freq
173  logMsg("playing random gliss...");
174 // f_env.trigger(); // reset the envelopes to time 0
175  a_env.trigger();
176  runTest(sos, 6); // run the test to play a note on the root of the DSP graph
177  logMsg("done.\n");
178 }
179 
180 /// Function to create and answer a RandFreqEnv UGen patch
181 
183  Osc * vox = new Osc; // declare an oscillator
184  RandEnvelope * a_env = new RandEnvelope(4, 0.5, 0.5, 0.5); // ampl env = random (frq, amp, off, step)
185  RandEnvelope * f_env = new RandEnvelope(3, 80, 200, 40); // freq env = random (frq, amp, off, step)
186  Osc * lfo = new Osc(fRandM(0.3, 0.6), 1, 0, fRandM(0, CSL_PI)); // LFO with rand frq/phase
187  Panner * pan = new Panner(*vox, *lfo); // stereo panner
188  vox->setFrequency(*f_env); // set the carrier's frequency
189  vox->setScale(*a_env); // multiply index envelope by mod freq
190  pan->setScale(0.04); // scale softer
191  return (pan); // return &pan
192 }
193 
194 /// set up 50 RandFreqEnv patches
195 
197  float duration = 20; // total dur
198  Mixer mix(2); // stereo mixer
199 
200  for (unsigned i = 0; i < 50; i++) // play a mix of RandFreqEnvPatch instruments
201  mix.addInput(createRandFreqEnvPatch(duration));
202 
203  logMsg("playing mix of 50 random gliss oscs...");
204 #ifndef CSL_WINDOWS
205  srand(getpid()); // seed the rand generator -- UNIX SPECIFIC CODE HERE
206 #endif
207  runTest(mix, duration);
208  logMsg("done.\n");
209  mix.deleteInputs(); // clean up
210 }
211 
212 /// test the use of scaling
213 
214 void testEnvScale() {
215  Osc vox; // declare 2 oscillators
216  LineSegment line(2, 60, 100);
217  vox.setFrequency(line); // set the carrier's frequency
218  ADSR a_env(2, 0.6, 0.1, 0.3, 1); // amplitude env = std ADSR
219  a_env.setScale(vox); // multiply index envelope by mod freq
220  logMsg("playing env as VCA...");
221  a_env.trigger();
222  runTest(a_env, 2); // run the test to play a note on the root of the DSP graph
223  logMsg("done.\n");
224 }
225 
226 /// FM with vibrato (with AR-envelope), attack chiff (filtered noise with AR-envelope),
227 /// and random freq. drift and ampl. swell envelopes
228 
229 void testFancy_FM() {
230  Osc car(BASE_FREQ); // init the 2 oscillators (fc = fm)
231  Osc mod(BASE_FREQ * 1.05);
232  ADSR a_env(3, 0.04, 0.2, 0.5, 1); // set up 2 standard ADSRs (3-sec duration)
233  ADSR i_env(3, 1.0, 0, 1, 1.0);
234 
235  Envelope mVibEnv(kExpon, 3, 0.0, 0.1, 2, 1.0, 3, 0.1); // vibrato envelope (expon triangle)
236  ADSR mChiffEnv(3, 0.01, 0.01, 0.0, 2); // attack-chiff envelope
237  Osc mVibrato(6); // sine oscillator for vibrato
238  WhiteNoise mChiff; // attach chiff noise source
239  Butter mChFilter(mChiff, BW_BAND_PASS, 4000.f, 200.f); // and filter
240 
241  mVibEnv.setScale(8); // scale vibrato envelope
242  mVibrato.setScale(mVibEnv); // apply vibrato envelope
243  mVibrato.setOffset(BASE_FREQ); // shift vibrato up
244 
245  mChiffEnv.setScale(2.0); // scale chiff envelope
246  mChFilter.setScale(mChiffEnv); // apply chiff envelope
247  car.setOffset(mChFilter); // add in chiff
248 
249  i_env.setScale(BASE_FREQ * 2); // scale mod index envelope
250  mod.setScale(i_env); // scale modulator
251  mod.setOffset(mVibrato); // add in vibrato and base freq
252  car.setFrequency(mod); // apply FM modulation
253  car.setScale(a_env); // apply ampl envelope
254 
255  Panner mPanner(car, 0.0); // stereo panner
256  Freeverb mReverb(mPanner); // mono reverb
257  mReverb.setRoomSize(0.99); // longer reverb
258 
259  i_env.trigger(); // GO -- trigger envelopes
260  a_env.trigger();
261  mVibEnv.trigger();
262  mChiffEnv.trigger();
263 
264  logMsg("playing Fancy FM\n");
265  runTest(mReverb, 4); // run the test
266  runTest(mReverb, 4); // run the test
267  logMsg("done.\n");
268 }
269 
270 /// Make an envelope from scratch by adding breakpoints
271 
273  float dur = 5; // total dur
274  SumOfSines sos(kFrequency, 5, 0.4, 0.2, 0.1, 0.05, 0.02);
275  sos.createCache(); // make the cached wavetable
276  Envelope a_env; // make an empty envelope
277  float tim = 0.0;
278  do { // add a bunch of break points to it
279  a_env.addBreakpoint(tim, fRandZ());
280  tim += fRandM(0.2, 0.5); // pick next time
281  } while (tim < dur);
282  a_env.addBreakpoint(dur, 0); // add final b-point
283  a_env.dump();
284  sos.setScale(a_env); // apply env
285  Panner pan(sos, fRand1()); // put sos in a panner
286  logMsg("playing mix of 50 random SOS oscs...");
287  a_env.trigger(); // trigger env
288  runTest(pan, dur);
289  logMsg("done.\n");
290 }
291 
292 // create a UGen patch for a SOS note with a made-up envelope
293 
294 UnitGenerator * sosNote(float dur, float frq, float amp) {
295  SumOfSines * sos = new SumOfSines(frq);
296  for (int i = 0; i < 30; i++) // add 30 partials per note
297  sos->addPartial((float)i, fRandZ(), fRandZ() * CSL_TWOPI);
298  sos->createCache(); // make the cached wavetable
299  Envelope * a_env = new Envelope; // make an empty envelope
300  float tim = 0.0;
301  do { // add a bunch of break points to it
302  a_env->addBreakpoint(tim, fRandZ());
303  tim += fRandM(0.3, 0.7); // pick next time
304  } while (tim < dur);
305  a_env->addBreakpoint(dur, 0);
306  a_env->setScale(amp); // make it quiet
307  sos->setScale(*a_env); // apply env
308  a_env->trigger();
309  Panner * pan = new Panner(*sos, fRand1());
310  return (pan); // return pan
311 }
312 
314  float duration = 20; // total dur
315  Mixer mix(2); // stereo mixer
316  for (unsigned i = 0; i < 100; i++) // play a mix of SOS instruments
317  mix.addInput(sosNote(duration, fRandM(100, 300), 0.02));
318  logMsg("playing mix of 100 random-env SOS oscs...");
319 #ifndef CSL_WINDOWS
320  srand(getpid()); // seed the rand generator -- UNIX SPECIFIC CODE HERE
321 #endif
322  runTest(mix, duration);
323  logMsg("done.\n");
324  mix.deleteInputs(); // clean up
325 }
326 
327 //////// RUN_TESTS Function ////////
328 
329 #ifndef USE_JUCE
330 
331 void runTests() {
332 // testGliss(); // Simple sine demo tests
333 // testSwell();
334 // testFrequencyEnv(); // Basic waveform tests
335 // testARSin(); // Ways of simple scaling
336 // testARSin2(); // Ways of simple scaling
337 // testAMFMEnvs();
338 // testADSR2(); // test truncating and interpolating wavetable osc
339 // testADSR_FM();
340 // testRandFreqEnv();
341 // testEnvScale();
342  testFancy_FM();
343 }
344 
345 #else
346 
347 // test list for Juce GUI
348 
349 testStruct envTestList[] = {
350  "Glissando test", testGliss, "Demonstrate a glissando function",
351  "Swell on aqmplitude", testSwell, "Make an amplitude swell",
352  "Frequency envelope", testFrequencyEnv, "Play a note with a frequency envelope",
353  "AR sine", testARSin, "Play an AR (attack/release) amplitude envelope",
354 // "AR sine 2", testARSin2, "",
355  "AM/FM envelopes", testAMFMEnvs, "Test AM and FM envelopes",
356  "ADSR 2", testADSR2, "Play an ADSR (attack/decay/sustain/release)",
357  "ADSR FM", testADSR_FM, "Dual-envelope FM example",
358  "Rand Freq envelope", testRandFreqEnv, "Play a random-walk frequency envelope",
359  "50 Rand F/A envs", test50RandFreqEnv, "Test 50 random frequency envelope players",
360 // "Envelope scaling", testEnvScale, "",
361  "Fancy FM", testFancy_FM, "Play a fancy FM note",
362  "Complex envelope", testComplexEnvelope, "Play a note with a complex amplitude envelope",
363  "Many random SOS", testManyRandSOS, "Layer many SumOfSines instruments with envelopes",
364  NULL, NULL, NULL
365 };
366 
367 #endif