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