aboutsummaryrefslogtreecommitdiffstats
path: root/tests/com/jsyn/unitgen
diff options
context:
space:
mode:
Diffstat (limited to 'tests/com/jsyn/unitgen')
-rw-r--r--tests/com/jsyn/unitgen/CalibrateMoogFilter.java141
-rw-r--r--tests/com/jsyn/unitgen/EnablingGate.java51
-rw-r--r--tests/com/jsyn/unitgen/NonRealTimeTestCase.java48
-rw-r--r--tests/com/jsyn/unitgen/RecordMoogFilter.java153
-rw-r--r--tests/com/jsyn/unitgen/TestConnections.java113
-rw-r--r--tests/com/jsyn/unitgen/TestDelay.java73
-rw-r--r--tests/com/jsyn/unitgen/TestEnable.java78
-rw-r--r--tests/com/jsyn/unitgen/TestEnvelopeAttackDecay.java126
-rw-r--r--tests/com/jsyn/unitgen/TestEnvelopeDAHDSR.java339
-rw-r--r--tests/com/jsyn/unitgen/TestFunction.java78
-rw-r--r--tests/com/jsyn/unitgen/TestMath.java392
-rw-r--r--tests/com/jsyn/unitgen/TestRamps.java196
-rw-r--r--tests/com/jsyn/unitgen/TestUnitGate.java80
13 files changed, 1868 insertions, 0 deletions
diff --git a/tests/com/jsyn/unitgen/CalibrateMoogFilter.java b/tests/com/jsyn/unitgen/CalibrateMoogFilter.java
new file mode 100644
index 0000000..a830fcc
--- /dev/null
+++ b/tests/com/jsyn/unitgen/CalibrateMoogFilter.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import javax.swing.JApplet;
+
+import com.jsyn.JSyn;
+import com.jsyn.Synthesizer;
+
+/**
+ * Play a sawtooth through a 4-pole filter.
+ *
+ * @author Phil Burk (C) 2010 Mobileer Inc
+ */
+public class CalibrateMoogFilter extends JApplet {
+ private Synthesizer synth;
+ private UnitOscillator oscillator;
+ private SineOscillator reference;
+ ZeroCrossingCounter zeroCounter;
+ PitchDetector pitchDetector;
+ ZeroCrossingCounter sineZeroCounter;
+ PitchDetector sinePitchDetector;
+ private FilterFourPoles filterMoog;
+ private LineOut lineOut;
+
+ @Override
+ public void init() {
+ synth = JSyn.createSynthesizer();
+ synth.setRealTime(false);
+ synth.add(oscillator = new SawtoothOscillatorBL());
+ synth.add(reference = new SineOscillator());
+ synth.add(filterMoog = new FilterFourPoles());
+ synth.add(pitchDetector = new PitchDetector());
+ synth.add(sinePitchDetector = new PitchDetector());
+ synth.add(zeroCounter = new ZeroCrossingCounter());
+ synth.add(sineZeroCounter = new ZeroCrossingCounter());
+ synth.add(lineOut = new LineOut());
+
+ oscillator.output.connect(filterMoog.input);
+ filterMoog.output.connect(zeroCounter.input);
+ zeroCounter.output.connect(pitchDetector.input);
+ reference.output.connect(0, lineOut.input, 0);
+ filterMoog.output.connect(0, lineOut.input, 1);
+
+ reference.output.connect(sineZeroCounter.input);
+ sineZeroCounter.output.connect(sinePitchDetector.input);
+
+ oscillator.frequency.set(130.0);
+ oscillator.amplitude.set(0.001);
+ filterMoog.frequency.set(440.0);
+ filterMoog.Q.set(4.1);
+ }
+
+ @Override
+ public void start() {
+ // Start synthesizer using default stereo output at 44100 Hz.
+ synth.start();
+ pitchDetector.start();
+ sinePitchDetector.start();
+ lineOut.start();
+ }
+
+ @Override
+ public void stop() {
+ pitchDetector.stop();
+ sinePitchDetector.stop();
+ lineOut.stop();
+ synth.stop();
+ }
+
+ public void test() {
+ init();
+ start();
+ try {
+ calibrate();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ stop();
+ }
+
+ private void calibrate() throws InterruptedException {
+ synth.sleepFor(2.0);
+ double freq = 100.0;
+ System.out
+ .printf("freq, moogFreq, ratio, moogConf, sineFreq, sineConf, moogZRate, sineZRate\n");
+ long startingFrameCount = synth.getFrameCount();
+ long startingMoogZeroCount = zeroCounter.getCount();
+ long startingSineZeroCount = sineZeroCounter.getCount();
+ for (int i = 0; i < 50; i++) {
+ reference.frequency.set(freq);
+ filterMoog.frequency.set(freq);
+ synth.sleepFor(2.0);
+
+ long endingFrameCount = synth.getFrameCount();
+ long elapsedFrames = endingFrameCount - startingFrameCount;
+ startingFrameCount = endingFrameCount;
+
+ long endingMoogZeroCount = zeroCounter.getCount();
+ long elapsedMoogZeros = endingMoogZeroCount - startingMoogZeroCount;
+ startingMoogZeroCount = endingMoogZeroCount;
+
+ long endingSineZeroCount = sineZeroCounter.getCount();
+ long elapsedSineZeros = endingSineZeroCount - startingSineZeroCount;
+ startingSineZeroCount = endingSineZeroCount;
+
+ double moogZeroRate = elapsedMoogZeros * (double) synth.getFrameRate() / elapsedFrames;
+ double sineZeroRate = elapsedSineZeros * (double) synth.getFrameRate() / elapsedFrames;
+
+ double moogMeasuredFreq = pitchDetector.frequency.get();
+ double moogConfidence = pitchDetector.confidence.get();
+ double sineMeasuredFreq = sinePitchDetector.frequency.get();
+ double sineConfidence = sinePitchDetector.confidence.get();
+ double ratio = freq / moogMeasuredFreq;
+ System.out.printf("%7.2f, %8.5f, %7.5f, %4.2f, %8.5f, %4.2f, %8.4f, %8.4f\n", freq,
+ moogMeasuredFreq, ratio, moogConfidence, sineMeasuredFreq, sineConfidence,
+ moogZeroRate, sineZeroRate);
+
+ freq *= 1.1;
+ }
+ }
+
+ public static void main(String args[]) {
+ new CalibrateMoogFilter().test();
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/EnablingGate.java b/tests/com/jsyn/unitgen/EnablingGate.java
new file mode 100644
index 0000000..daf36be
--- /dev/null
+++ b/tests/com/jsyn/unitgen/EnablingGate.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import com.jsyn.ports.UnitInputPort;
+
+/**
+ * This can be used to block the execution of upstream units. It can be placed at the output of a
+ * circuit and driven with an amplitude envelope.
+ *
+ * @author Phil Burk (C) 2010 Mobileer Inc
+ */
+public class EnablingGate extends UnitFilter {
+ public UnitInputPort gate;
+
+ /* Define Unit Ports used by connect() and set(). */
+ public EnablingGate() {
+ super();
+ addPort(gate = new UnitInputPort("Gate"));
+ }
+
+ @Override
+ public void generate(int start, int limit) {
+ double[] aValues = input.getValues();
+ double[] bValues = gate.getValues();
+ double[] outputs = output.getValues();
+ for (int i = start; i < limit; i++) {
+ outputs[i] = aValues[i] * bValues[i];
+ }
+ // If we end up at zero then disable pulling of data.
+ // We do this at the end so that envelope can get started.
+ if (outputs[limit - 1] <= 0.0) {
+ setEnabled(false);
+ }
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/NonRealTimeTestCase.java b/tests/com/jsyn/unitgen/NonRealTimeTestCase.java
new file mode 100644
index 0000000..5d332a9
--- /dev/null
+++ b/tests/com/jsyn/unitgen/NonRealTimeTestCase.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import junit.framework.TestCase;
+
+import com.jsyn.engine.SynthesisEngine;
+
+public abstract class NonRealTimeTestCase extends TestCase {
+
+ protected SynthesisEngine synthesisEngine;
+
+ public NonRealTimeTestCase() {
+ super();
+ }
+
+ public NonRealTimeTestCase(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ synthesisEngine = new SynthesisEngine();
+ synthesisEngine.setRealTime(false);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ synthesisEngine.stop();
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/RecordMoogFilter.java b/tests/com/jsyn/unitgen/RecordMoogFilter.java
new file mode 100644
index 0000000..6af11fd
--- /dev/null
+++ b/tests/com/jsyn/unitgen/RecordMoogFilter.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2010 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import javax.swing.JApplet;
+
+import com.jsyn.JSyn;
+import com.jsyn.Synthesizer;
+import com.jsyn.util.WaveRecorder;
+
+/**
+ * Measure actual frequency as a function of input frequency and Q.
+ *
+ * @author Phil Burk (C) 2010 Mobileer Inc
+ */
+public class RecordMoogFilter extends JApplet {
+ private final static boolean SWEEP_Q = false;
+ private final static boolean SWEEP_FREQUENCY = true;
+ private final static int NUM_STEPS = 11;
+
+ private final static double MIN_Q = 0.0;
+ private final static double DEFAULT_Q = 9.0;
+ private final static double MAX_Q = 10.0;
+
+ private final static double MIN_FREQUENCY = 100.0;
+ private final static double DEFAULT_FREQUENCY = 500.0;
+ private final static double MAX_FREQUENCY = 4000.0;
+
+ private Synthesizer synth;
+ private WhiteNoise source;
+ private SineOscillator reference;
+ private FilterFourPoles filterMoog;
+ private LineOut lineOut;
+ private WaveRecorder recorder;
+
+ @Override
+ public void init() {
+ synth = JSyn.createSynthesizer();
+ synth.setRealTime(false);
+ synth.add(source = new WhiteNoise());
+ synth.add(filterMoog = new FilterFourPoles());
+ synth.add(reference = new SineOscillator());
+ synth.add(lineOut = new LineOut());
+
+ source.output.connect(filterMoog.input);
+ reference.output.connect(0, lineOut.input, 0);
+ filterMoog.output.connect(0, lineOut.input, 1);
+
+ reference.amplitude.set(0.5);
+ source.amplitude.set(0.5);
+ filterMoog.frequency.set(DEFAULT_FREQUENCY);
+ filterMoog.Q.set(DEFAULT_Q);
+
+ File waveFile = new File("temp_recording.wav");
+ // Default is stereo, 16 bits.
+ try {
+ recorder = new WaveRecorder(synth, waveFile);
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ System.out.println("Writing to WAV file " + waveFile.getAbsolutePath());
+ }
+
+ @Override
+ public void start() {
+ // Start synthesizer using default stereo output at 44100 Hz.
+ synth.start();
+ lineOut.start();
+
+ reference.output.connect(0, recorder.getInput(), 0);
+ filterMoog.output.connect(0, recorder.getInput(), 1);
+ recorder.start();
+ }
+
+ @Override
+ public void stop() {
+ if (recorder != null) {
+ recorder.stop();
+ try {
+ recorder.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ lineOut.stop();
+ synth.stop();
+ }
+
+ public void test() {
+ init();
+ start();
+ try {
+ calibrate();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ stop();
+ }
+
+ private void calibrate() throws InterruptedException {
+ synth.sleepFor(0.2);
+ double freq = SWEEP_FREQUENCY ? MIN_FREQUENCY : DEFAULT_FREQUENCY;
+ double q = SWEEP_Q ? MIN_Q : DEFAULT_Q;
+ double stepQ = (MAX_Q - MIN_Q) / (NUM_STEPS - 1);
+ double scaleFrequency = Math.pow((MAX_FREQUENCY / MIN_FREQUENCY), (1.0 / (NUM_STEPS - 1)));
+ System.out.printf("freq, q, measured\n");
+ for (int i = 0; i < NUM_STEPS; i++) {
+ double refAmp = reference.amplitude.get();
+ reference.amplitude.set(0.0);
+ synth.sleepFor(0.1);
+ reference.amplitude.set(refAmp);
+
+ System.out.printf("%8.2f, %6.3f, \n", freq, q);
+ filterMoog.frequency.set(freq);
+ reference.frequency.set(freq);
+ filterMoog.Q.set(q);
+
+ synth.sleepFor(2.0);
+
+ if (SWEEP_FREQUENCY) {
+ freq *= scaleFrequency;
+ }
+ if (SWEEP_Q) {
+ q += stepQ;
+ }
+ }
+ }
+
+ public static void main(String args[]) {
+ new RecordMoogFilter().test();
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/TestConnections.java b/tests/com/jsyn/unitgen/TestConnections.java
new file mode 100644
index 0000000..d15a257
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestConnections.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import junit.framework.TestCase;
+
+import com.jsyn.JSyn;
+import com.jsyn.Synthesizer;
+
+public class TestConnections extends TestCase {
+ Add add1;
+ Add add2;
+ Add add3;
+
+ Synthesizer synth;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ synth = JSyn.createSynthesizer();
+
+ synth.add(add1 = new Add());
+ synth.add(add2 = new Add());
+ synth.add(add3 = new Add());
+
+ add1.start();
+ add2.start();
+ add3.start();
+
+ add1.inputA.set(0.1);
+ add1.inputB.set(0.2);
+
+ add2.inputA.set(0.4);
+ add2.inputB.set(0.8);
+
+ add3.inputA.set(1.6);
+ add3.inputB.set(3.2);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testSet() throws InterruptedException {
+ synth.sleepFor(0.01);
+ assertEquals("set inputs of adder", 0.3, add1.output.getValue(), 0.0001);
+ }
+
+ public void testConnect() throws InterruptedException {
+ synth.sleepFor(0.01);
+ assertEquals("set inputs of adder", 0.3, add1.output.getValue(), 0.0001);
+ assertEquals("set inputs of adder", 1.2, add2.output.getValue(), 0.0001);
+
+ // Test different ways of connecting.
+ add1.output.connect(add2.inputB);
+ checkConnection();
+
+ add1.output.connect(0, add2.inputB, 0);
+ checkConnection();
+
+ add1.output.connect(add2.inputB.getConnectablePart(0));
+ checkConnection();
+
+ add1.output.getConnectablePart(0).connect(add2.inputB);
+ checkConnection();
+
+ add1.output.getConnectablePart(0).connect(add2.inputB.getConnectablePart(0));
+ checkConnection();
+
+ add2.inputB.connect(add1.output);
+ checkConnection();
+
+ add2.inputB.connect(0, add1.output, 0);
+ checkConnection();
+
+ add2.inputB.connect(add1.output.getConnectablePart(0));
+ checkConnection();
+
+ add2.inputB.getConnectablePart(0).connect(add1.output);
+ checkConnection();
+
+ add2.inputB.getConnectablePart(0).connect(add1.output.getConnectablePart(0));
+ checkConnection();
+ }
+
+ private void checkConnection() throws InterruptedException {
+ synth.sleepFor(0.01);
+ assertEquals("connection should not change output", 0.3, add1.output.getValue(), 0.0001);
+ assertEquals("replace set value with output", 0.7, add2.output.getValue(), 0.0001);
+
+ // Revert to set value after disconnection.
+ add1.output.disconnectAll();
+ synth.sleepFor(0.01);
+ assertEquals("still the same", 0.3, add1.output.getValue(), 0.0001);
+ assertEquals("should revert to original set() value", 1.2, add2.output.getValue(), 0.0001);
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/TestDelay.java b/tests/com/jsyn/unitgen/TestDelay.java
new file mode 100644
index 0000000..12af1cd
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestDelay.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import com.jsyn.util.AudioStreamReader;
+
+public class TestDelay extends NonRealTimeTestCase {
+ public void testFloor() {
+ double x = -7.3;
+ int n = (int) Math.floor(x);
+ assertEquals("int", -8, n);
+ }
+
+ public void checkInterpolatingDelay(int maxFrames, double delayFrames)
+ throws InterruptedException {
+ synthesisEngine.start();
+
+ System.out.printf("test delayFrames = %7.5f\n", delayFrames);
+ InterpolatingDelay delay = new InterpolatingDelay();
+ synthesisEngine.add(delay);
+ delay.allocate(maxFrames);
+ delay.delay.set(delayFrames / 44100.0);
+ SawtoothOscillator osc = new SawtoothOscillator();
+ synthesisEngine.add(osc);
+ osc.frequency.set(synthesisEngine.getFrameRate() / 4.0);
+ osc.amplitude.set(1.0);
+ osc.output.connect(delay.input);
+
+ int samplesPerFrame = 1;
+ AudioStreamReader reader = new AudioStreamReader(synthesisEngine, samplesPerFrame);
+ delay.output.connect(reader.getInput());
+
+ delay.start();
+ for (int i = 0; i < (3 * maxFrames); i++) {
+ if (reader.available() == 0) {
+ synthesisEngine.sleepFor(0.01);
+ }
+ double actual = reader.read();
+ double expected = 1 + i - delayFrames;
+ if (expected < 0.0) {
+ expected = 0.0;
+ }
+ // System.out.printf( "[%d] expected = %7.3f, delayed = %7.3f\n", i, expected, actual );
+ // assertEquals("delayed output", expected, actual, 0.00001);
+ }
+ }
+
+ public void testSmall() throws InterruptedException {
+ checkInterpolatingDelay(40, 7.0);
+ }
+
+ public void testEven() throws InterruptedException {
+ checkInterpolatingDelay(44100, 13671.0);
+ }
+
+ public void testInterpolatingDelay() throws InterruptedException {
+ checkInterpolatingDelay(44100, 13671.4);
+ }
+}
diff --git a/tests/com/jsyn/unitgen/TestEnable.java b/tests/com/jsyn/unitgen/TestEnable.java
new file mode 100644
index 0000000..37a4a2b
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestEnable.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import junit.framework.TestCase;
+
+import com.jsyn.engine.SynthesisEngine;
+
+public class TestEnable extends TestCase {
+ SynthesisEngine synthesisEngine;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ synthesisEngine = new SynthesisEngine();
+ synthesisEngine.setRealTime(false);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ synthesisEngine.stop();
+ }
+
+ public void testEnablingGate() throws InterruptedException {
+ LinearRamp ramp = new LinearRamp();
+ synthesisEngine.add(ramp);
+ EnablingGate enabler = new EnablingGate();
+ synthesisEngine.add(enabler);
+ Add adder = new Add();
+ synthesisEngine.add(adder);
+
+ ramp.output.connect(enabler.input);
+ enabler.output.connect(adder.inputA);
+
+ // set up so ramp should equal time
+ ramp.current.set(0.0);
+ ramp.input.set(1.0);
+ ramp.time.set(1.0);
+ enabler.gate.set(1.0);
+
+ synthesisEngine.start();
+ double startTime = synthesisEngine.getCurrentTime();
+ // pull from final adder
+ adder.start();
+ synthesisEngine.sleepUntil(startTime + 0.1);
+ double tolerance = 0.002;
+ assertEquals("ramp going up", 0.1, ramp.output.getValue(), tolerance);
+ assertEquals("enabler going up", 0.1, enabler.output.getValue(), tolerance);
+ assertEquals("adder going up", 0.1, adder.output.getValue(), tolerance);
+ synthesisEngine.sleepUntil(startTime + 0.2);
+ assertEquals("start enabled", 0.2, adder.output.getValue(), tolerance);
+
+ // disable everything upstream
+ enabler.gate.set(0.0);
+
+ synthesisEngine.sleepUntil(startTime + 0.3);
+ assertEquals("should not be pulled", 0.2, ramp.output.getValue(), tolerance);
+ assertEquals("should be disabled", false, enabler.isEnabled());
+ assertEquals("should be zero", 0.0, enabler.output.getValue(), tolerance);
+ assertEquals("zero", 0.0, adder.output.getValue(), tolerance);
+
+ }
+}
diff --git a/tests/com/jsyn/unitgen/TestEnvelopeAttackDecay.java b/tests/com/jsyn/unitgen/TestEnvelopeAttackDecay.java
new file mode 100644
index 0000000..50ecb15
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestEnvelopeAttackDecay.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import com.jsyn.engine.SynthesisEngine;
+
+public class TestEnvelopeAttackDecay extends TestUnitGate {
+ double attackTime;
+ double decayTime;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ synthesisEngine = new SynthesisEngine();
+ synthesisEngine.setRealTime(false);
+ attackTime = 0.2;
+ decayTime = 0.4;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ synthesisEngine.stop();
+ }
+
+ public void testOnOff() throws InterruptedException {
+ EnvelopeAttackDecay envelope = new EnvelopeAttackDecay();
+ synthesisEngine.add(envelope);
+
+ envelope.attack.set(0.1);
+ envelope.decay.set(0.2);
+
+ synthesisEngine.start();
+ envelope.start();
+ time = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(time + 0.1);
+ assertEquals("still idling", 0.0, envelope.output.getValue());
+
+ // Trigger the envelope using on/off
+ envelope.input.on();
+ time = synthesisEngine.getCurrentTime();
+ // Check end of attack cycle.
+ synthesisEngine.sleepUntil(time + 0.1);
+ assertTrue("at peak", (envelope.output.getValue() > 0.8));
+ envelope.input.off();
+ // Check end of decay cycle.
+ synthesisEngine.sleepUntil(time + 0.3);
+ assertTrue("at peak", (envelope.output.getValue() < 0.1));
+
+ synthesisEngine.sleepFor(0.1);
+
+ // Trigger the envelope using trigger()
+ envelope.input.trigger();
+ time = synthesisEngine.getCurrentTime();
+ // Check end of attack cycle.
+ synthesisEngine.sleepUntil(time + 0.1);
+ assertTrue("at peak", (envelope.output.getValue() > 0.8));
+ // Check end of decay cycle.
+ synthesisEngine.sleepUntil(time + 0.3);
+ assertTrue("at peak", (envelope.output.getValue() < 0.1));
+
+ }
+
+ public void testRetrigger() throws InterruptedException {
+ EnvelopeAttackDecay envelope = new EnvelopeAttackDecay();
+ synthesisEngine.add(envelope);
+
+ envelope.attack.set(0.1);
+ envelope.decay.set(0.2);
+
+ synthesisEngine.start();
+ envelope.start();
+ time = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(time + 0.1);
+ assertEquals("still idling", 0.0, envelope.output.getValue());
+
+ // Trigger the envelope using trigger()
+ envelope.input.trigger();
+ // Check end of attack cycle.
+ synthesisEngine.sleepFor(0.1);
+ assertEquals("at peak", 1.0, envelope.output.getValue(), 0.1);
+
+ // Decay half way.
+ synthesisEngine.sleepFor(0.1);
+ assertTrue("at peak", (envelope.output.getValue() < 0.7));
+
+ // Retrigger while decaying
+ envelope.input.trigger();
+ // Will get to top faster.
+ synthesisEngine.sleepFor(0.1);
+ assertEquals("at peak", 1.0, envelope.output.getValue(), 0.1);
+
+ // Check end of decay cycle.
+ synthesisEngine.sleepFor(0.2);
+ assertTrue("at peak", (envelope.output.getValue() < 0.1));
+
+ }
+
+ public void testAutoDisable() throws InterruptedException {
+
+ LinearRamp ramp = new LinearRamp();
+ synthesisEngine.add(ramp);
+ EnvelopeAttackDecay envelope = new EnvelopeAttackDecay();
+ envelope.attack.set(0.1);
+ envelope.decay.set(0.1);
+ synthesisEngine.add(envelope);
+ ramp.output.connect(envelope.amplitude);
+
+ checkAutoDisable(ramp, envelope);
+
+ }
+}
diff --git a/tests/com/jsyn/unitgen/TestEnvelopeDAHDSR.java b/tests/com/jsyn/unitgen/TestEnvelopeDAHDSR.java
new file mode 100644
index 0000000..8c781ac
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestEnvelopeDAHDSR.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import com.jsyn.engine.SynthesisEngine;
+
+public class TestEnvelopeDAHDSR extends TestUnitGate {
+ double delayTime;
+ double attackTime;
+ double holdTime;
+ double decayTime;
+ double sustainLevel;
+ double releaseTime;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ synthesisEngine = new SynthesisEngine();
+ synthesisEngine.setRealTime(false);
+ delayTime = 0.1;
+ attackTime = 0.2;
+ holdTime = 0.3;
+ decayTime = 0.4;
+ sustainLevel = 0.5;
+ releaseTime = 0.6;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ synthesisEngine.stop();
+ }
+
+ public void testStages() throws InterruptedException {
+ EnvelopeDAHDSR ramp = checkToSustain();
+
+ // Change sustain level to simulate tremolo sustain.
+ sustainLevel = 0.7;
+ ramp.sustain.set(sustainLevel);
+ time += 0.01;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("sustain moving delaying", sustainLevel, ramp.output.getValue(), 0.01);
+
+ // Gate off to let envelope release.
+ ramp.input.set(0.0);
+ synthesisEngine.sleepUntil(time + (releaseTime * 0.1));
+ double releaseValue = ramp.output.getValue();
+ assertEquals("partway down release", sustainLevel * 0.36, releaseValue, 0.01);
+ }
+
+ private EnvelopeDAHDSR checkToSustain() throws InterruptedException {
+ EnvelopeDAHDSR ramp = new EnvelopeDAHDSR();
+ synthesisEngine.add(ramp);
+
+ ramp.delay.set(delayTime);
+ ramp.attack.set(attackTime);
+ ramp.hold.set(holdTime);
+ ramp.decay.set(decayTime);
+ ramp.sustain.set(sustainLevel);
+ ramp.release.set(releaseTime);
+
+ synthesisEngine.start();
+ ramp.start();
+ time = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(time + (2.0 * delayTime));
+ assertEquals("still idling", 0.0, ramp.output.getValue());
+
+ // Trigger the envelope.
+ ramp.input.set(1.0);
+ time = synthesisEngine.getCurrentTime();
+ // Check end of delay cycle.
+ synthesisEngine.sleepUntil(time + (delayTime * 0.9));
+ assertEquals("still delaying", 0.0, ramp.output.getValue(), 0.01);
+ // Half way up attack ramp.
+ synthesisEngine.sleepUntil(time + delayTime + (attackTime * 0.5));
+ assertEquals("half attack", 0.5, ramp.output.getValue(), 0.01);
+ // Holding after attack.
+ synthesisEngine.sleepUntil(time + delayTime + attackTime + (holdTime * 0.1));
+ assertEquals("holding", 1.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(time + delayTime + attackTime + (holdTime * 0.9));
+ assertEquals("still holding", 1.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(time + delayTime + attackTime + holdTime + decayTime);
+ time = synthesisEngine.getCurrentTime();
+ assertEquals("at sustain", sustainLevel, ramp.output.getValue(), 0.01);
+ return ramp;
+ }
+
+ public void testRetrigger() throws InterruptedException {
+ EnvelopeDAHDSR ramp = checkToSustain();
+
+ // Gate off to let envelope release.
+ ramp.input.set(0.0);
+ synthesisEngine.sleepUntil(time + (releaseTime * 0.1));
+ double releaseValue = ramp.output.getValue();
+ assertEquals("partway down release", sustainLevel * 0.36, releaseValue, 0.01);
+
+ // Retrigger during release phase.
+ time = synthesisEngine.getCurrentTime();
+ ramp.input.set(1.0);
+ // Check end of delay cycle.
+ synthesisEngine.sleepUntil(time + (delayTime * 0.9));
+ assertEquals("still delaying", releaseValue, ramp.output.getValue(), 0.01);
+ // Half way up attack ramp from where it started.
+ synthesisEngine.sleepUntil(time + delayTime + (attackTime * 0.5));
+ assertEquals("half attack", releaseValue + 0.5, ramp.output.getValue(), 0.01);
+
+ }
+
+ // I noticed a hang while playing with knobs.
+ public void testHang() throws InterruptedException {
+
+ delayTime = 0.0;
+ attackTime = 0.0;
+ holdTime = 0.0;
+ decayTime = 0.0;
+ sustainLevel = 0.3;
+ releaseTime = 3.0;
+
+ EnvelopeDAHDSR ramp = new EnvelopeDAHDSR();
+ synthesisEngine.add(ramp);
+
+ ramp.delay.set(delayTime);
+ ramp.attack.set(attackTime);
+ ramp.hold.set(holdTime);
+ ramp.decay.set(decayTime);
+ ramp.sustain.set(sustainLevel);
+ ramp.release.set(releaseTime);
+
+ synthesisEngine.start();
+ ramp.start();
+ // Trigger the envelope.
+ ramp.input.set(1.0);
+ time = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(time + 0.01);
+ assertEquals("should jump to sustain level", sustainLevel, ramp.output.getValue());
+
+ // Gate off to let envelope release.
+ ramp.input.set(0.0);
+ synthesisEngine.sleepUntil(time + 1.0);
+ double releaseValue = ramp.output.getValue();
+ assertTrue("partway down release", sustainLevel > releaseValue);
+
+ holdTime = 0.5;
+ ramp.hold.set(holdTime);
+ decayTime = 0.5;
+ ramp.decay.set(decayTime);
+
+ // Retrigger during release phase and try to catch it at top of hold
+ time = synthesisEngine.getCurrentTime();
+ ramp.input.set(1.0);
+ // Check end of delay cycle.
+ synthesisEngine.sleepUntil(time + (holdTime * 0.1));
+ assertEquals("should jump to hold", 1.0, ramp.output.getValue(), 0.01);
+ }
+
+ public void testNegative() throws InterruptedException {
+ delayTime = -0.1;
+ attackTime = -0.2;
+ holdTime = -0.3;
+ decayTime = -0.4;
+ sustainLevel = 0.3;
+ releaseTime = -0.5;
+
+ EnvelopeDAHDSR ramp = new EnvelopeDAHDSR();
+ synthesisEngine.add(ramp);
+
+ ramp.delay.set(delayTime);
+ ramp.attack.set(attackTime);
+ ramp.hold.set(holdTime);
+ ramp.decay.set(decayTime);
+ ramp.sustain.set(sustainLevel);
+ ramp.release.set(releaseTime);
+
+ synthesisEngine.start();
+ ramp.start();
+ // Trigger the envelope.
+ ramp.input.set(1.0);
+ time = synthesisEngine.getCurrentTime();
+ time += 0.1;
+ synthesisEngine.sleepUntil(time + 0.01);
+ assertEquals("should jump to sustain level", sustainLevel, ramp.output.getValue());
+
+ ramp.sustain.set(sustainLevel = -0.4);
+ time += 0.1;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("sustain should clip at zero", sustainLevel, ramp.output.getValue());
+
+ ramp.sustain.set(sustainLevel = 0.4);
+ time += 0.1;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("sustain should come back", sustainLevel, ramp.output.getValue());
+
+ // Gate off to let envelope release.
+ ramp.input.set(0.0);
+ time += 0.1;
+ synthesisEngine.sleepUntil(time);
+ double releaseValue = ramp.output.getValue();
+ assertEquals("release quickly", 0.0, releaseValue);
+ }
+
+ public void testOnOff() throws InterruptedException {
+ EnvelopeDAHDSR ramp = new EnvelopeDAHDSR();
+ synthesisEngine.add(ramp);
+
+ ramp.delay.set(0.0);
+ ramp.attack.set(0.1);
+ ramp.hold.set(0.0);
+ ramp.decay.set(0.0);
+ ramp.sustain.set(0.9);
+ ramp.release.set(0.1);
+
+ synthesisEngine.start();
+ ramp.start();
+ time = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(time + 0.2);
+ assertEquals("still idling", 0.0, ramp.output.getValue());
+
+ // Trigger the envelope.
+ ramp.input.on();
+ time = synthesisEngine.getCurrentTime();
+ // Check end of delay cycle.
+ synthesisEngine.sleepUntil(time + 0.2);
+ assertEquals("at sustain", 0.9, ramp.output.getValue(), 0.01);
+
+ // Release the envelope.
+ ramp.input.off();
+ time = synthesisEngine.getCurrentTime();
+ // Check end of delay cycle.
+ synthesisEngine.sleepUntil(time + 0.2);
+ assertEquals("after release", 0.0, ramp.output.getValue(), 0.01);
+ }
+
+ public void testAutoDisable() throws InterruptedException {
+
+ LinearRamp ramp = new LinearRamp();
+ synthesisEngine.add(ramp);
+ EnvelopeDAHDSR envelope = new EnvelopeDAHDSR();
+ synthesisEngine.add(envelope);
+ envelope.attack.set(0.1);
+ envelope.decay.set(0.1);
+ envelope.release.set(0.1);
+ envelope.sustain.set(0.1);
+ ramp.output.connect(envelope.amplitude);
+
+ checkAutoDisable(ramp, envelope);
+
+ }
+
+ class GatedRampCircuit extends Circuit {
+ LinearRamp ramp;
+ EnvelopeDAHDSR envelope;
+
+ GatedRampCircuit() {
+ add(ramp = new LinearRamp());
+ add(envelope = new EnvelopeDAHDSR());
+ envelope.attack.set(0.1);
+ envelope.decay.set(0.1);
+ envelope.release.set(0.1);
+ envelope.sustain.set(0.1);
+
+ envelope.setupAutoDisable(this);
+ ramp.output.connect(envelope.amplitude);
+ }
+ }
+
+ public void testAutoDisableCircuit() throws InterruptedException {
+ GatedRampCircuit circuit = new GatedRampCircuit();
+ synthesisEngine.add(circuit);
+ checkAutoDisable(circuit.ramp, circuit.envelope);
+ }
+
+ public void checkReleaseTiming(double releaseTime, double tolerance)
+ throws InterruptedException {
+ delayTime = 0.0;
+ attackTime = 0.2;
+ holdTime = 0.0;
+ decayTime = 10.0;
+ sustainLevel = 1.0;
+
+ EnvelopeDAHDSR ramp = new EnvelopeDAHDSR();
+ synthesisEngine.add(ramp);
+
+ ramp.delay.set(delayTime);
+ ramp.attack.set(attackTime);
+ ramp.hold.set(holdTime);
+ ramp.decay.set(decayTime);
+ ramp.sustain.set(sustainLevel);
+ ramp.release.set(releaseTime);
+
+ synthesisEngine.start();
+ ramp.start();
+ // Trigger the envelope.
+ ramp.input.set(1.0);
+ time = synthesisEngine.getCurrentTime();
+ time += attackTime * 2;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("should be at to sustain level", sustainLevel, ramp.output.getValue());
+
+ // Start envelope release.
+ ramp.input.set(0.0);
+ final double db90 = 20.0 * Math.log(1.0 / 32768.0) / Math.log(10.0);
+ System.out.println("JSyns DB90 is actually " + db90);
+ int numSteps = 10;
+ for (int i = 0; i < 10; i++) {
+ time += releaseTime / numSteps;
+ synthesisEngine.sleepUntil(time);
+ double expectedDB = db90 * (i + 1) / numSteps;
+ double expectedAmplitude = sustainLevel * Math.pow(10.0, expectedDB / 20.0);
+ double releaseValue = ramp.output.getValue();
+ assertEquals("release " + i + " at", expectedAmplitude, releaseValue, tolerance);
+ }
+ time += releaseTime / numSteps;
+ synthesisEngine.sleepUntil(time);
+ double releaseValue = ramp.output.getValue();
+ assertEquals("env after release time should go to zero", 0.0, releaseValue, 0.0001);
+ }
+
+ public void testReleaseTiming() throws InterruptedException {
+ checkReleaseTiming(0.1, 0.004);
+ checkReleaseTiming(1.0, 0.002);
+ checkReleaseTiming(2.5, 0.001);
+ checkReleaseTiming(10.0, 0.001);
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/TestFunction.java b/tests/com/jsyn/unitgen/TestFunction.java
new file mode 100644
index 0000000..a8bfac0
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestFunction.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import junit.framework.TestCase;
+
+import com.jsyn.JSyn;
+import com.jsyn.Synthesizer;
+import com.jsyn.data.DoubleTable;
+import com.jsyn.data.Function;
+
+/**
+ * @author Phil Burk, (C) 2009 Mobileer Inc
+ */
+public class TestFunction extends TestCase {
+ Synthesizer synth;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ synth = JSyn.createSynthesizer();
+ synth.setRealTime(false);
+ synth.start();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ synth.stop();
+ }
+
+ public void testDoubleTable() {
+ double[] data = {
+ 2.0, 0.0, 3.0
+ };
+ DoubleTable table = new DoubleTable(data);
+ assertEquals("DoubleTable below", 2.0, table.evaluate(-1.4));
+ assertEquals("DoubleTable edge", 2.0, table.evaluate(-1.0));
+ assertEquals("DoubleTable mid", 1.0, table.evaluate(-0.5));
+ assertEquals("DoubleTable zero", 0.0, table.evaluate(0.0));
+ assertEquals("DoubleTable mid", 0.75, table.evaluate(0.25));
+ assertEquals("DoubleTable above", 3.0, table.evaluate(1.3));
+
+ }
+
+ public void testFunctionEvaluator() throws InterruptedException {
+ FunctionEvaluator shaper = new FunctionEvaluator();
+ synth.add(shaper);
+ shaper.start();
+
+ Function cuber = new Function() {
+ @Override
+ public double evaluate(double x) {
+ return x * x * x;
+ }
+ };
+ shaper.function.set(cuber);
+
+ shaper.input.set(0.5);
+ synth.sleepFor(0.001);
+
+ assertEquals("Cuber", (0.5 * 0.5 * 0.5), shaper.output.getValue());
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/TestMath.java b/tests/com/jsyn/unitgen/TestMath.java
new file mode 100644
index 0000000..0fde9b5
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestMath.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import junit.framework.TestCase;
+
+import com.jsyn.engine.SynthesisEngine;
+
+/**
+ * @author Phil Burk, (C) 2009 Mobileer Inc
+ */
+public class TestMath extends TestCase {
+ SynthesisEngine synthesisEngine;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ synthesisEngine = new SynthesisEngine();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testAdd() {
+ Add add = new Add();
+ add.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ add.inputA.setValueInternal(x);
+ add.inputB.setValueInternal(y);
+
+ add.generate();
+
+ assertEquals("Add", x + y, add.output.getValue(), 0.001);
+ }
+
+ public void testPartialAdd() {
+ Add add = new Add();
+ add.setSynthesisEngine(synthesisEngine);
+
+ double x = 2.5;
+ double y = 9.7;
+ add.inputA.setValueInternal(x);
+ add.inputB.setValueInternal(y);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ add.generate(2, 5);
+
+ assertEquals("Add partial", 0.0, add.output.getValues()[0], 0.001);
+ assertEquals("Add partial", 0.0, add.output.getValues()[1], 0.001);
+ assertEquals("Add partial", x + y, add.output.getValues()[2], 0.001);
+ assertEquals("Add partial", x + y, add.output.getValues()[3], 0.001);
+ assertEquals("Add partial", x + y, add.output.getValues()[4], 0.001);
+ assertEquals("Add partial", 0.0, add.output.getValues()[5], 0.001);
+ assertEquals("Add partial", 0.0, add.output.getValues()[6], 0.001);
+ assertEquals("Add partial", 0.0, add.output.getValues()[7], 0.001);
+
+ }
+
+ /**
+ * Unit test for Subtract.java - added by Lisa Tolentino 06/17/2009
+ */
+ public void testSubtract() {
+ Subtract sub = new Subtract();
+ sub.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ sub.inputA.setValueInternal(x);
+ sub.inputB.setValueInternal(y);
+
+ sub.generate();
+
+ assertEquals("Subtract", x - y, sub.output.getValue(), 0.001);
+ }
+
+ public void testPartialSubtract() {
+ Subtract sub = new Subtract();
+ sub.setSynthesisEngine(synthesisEngine);
+
+ double x = 2.5;
+ double y = 9.7;
+ sub.inputA.setValueInternal(x);
+ sub.inputB.setValueInternal(y);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ sub.generate(2, 5);
+
+ assertEquals("Subtract partial", 0.0, sub.output.getValues()[0], 0.001);
+ assertEquals("Subtract partial", 0.0, sub.output.getValues()[1], 0.001);
+ assertEquals("Subtract partial", x - y, sub.output.getValues()[2], 0.001);
+ assertEquals("Subtract partial", x - y, sub.output.getValues()[3], 0.001);
+ assertEquals("Subtract partial", x - y, sub.output.getValues()[4], 0.001);
+ assertEquals("Subtract partial", 0.0, sub.output.getValues()[5], 0.001);
+ assertEquals("Subtract partial", 0.0, sub.output.getValues()[6], 0.001);
+ assertEquals("Subtract partial", 0.0, sub.output.getValues()[7], 0.001);
+
+ }
+
+ /**
+ * Unit test for Multiply.java - added by Lisa Tolentino 06/19/2009
+ */
+ public void testMultiply() {
+ Multiply mult = new Multiply();
+ mult.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ mult.inputA.setValueInternal(x);
+ mult.inputB.setValueInternal(y);
+
+ mult.generate();
+
+ assertEquals("Multiply", x * y, mult.output.getValue(), 0.001);
+ }
+
+ public void testPartialMultiply() {
+ Multiply mult = new Multiply();
+ mult.setSynthesisEngine(synthesisEngine);
+
+ double x = 2.5;
+ double y = 9.7;
+ mult.inputA.setValueInternal(x);
+ mult.inputB.setValueInternal(y);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ mult.generate(2, 5);
+
+ assertEquals("Multiply partial", 0.0, mult.output.getValues()[0], 0.001);
+ assertEquals("Multiply partial", 0.0, mult.output.getValues()[1], 0.001);
+ assertEquals("Multiply partial", x * y, mult.output.getValues()[2], 0.001);
+ assertEquals("Multiply partial", x * y, mult.output.getValues()[3], 0.001);
+ assertEquals("Multiply partial", x * y, mult.output.getValues()[4], 0.001);
+ assertEquals("Multiply partial", 0.0, mult.output.getValues()[5], 0.001);
+ assertEquals("Multiply partial", 0.0, mult.output.getValues()[6], 0.001);
+ assertEquals("Multiply partial", 0.0, mult.output.getValues()[7], 0.001);
+
+ }
+
+ /**
+ * Unit test for Divide.java - added by Lisa Tolentino 06/19/2009
+ */
+ public void testDivide() {
+ Divide divide = new Divide();
+ divide.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ divide.inputA.setValueInternal(x);
+ divide.inputB.setValueInternal(y);
+
+ divide.generate();
+
+ assertEquals("Divide", x / y, divide.output.getValue(), 0.001);
+ }
+
+ public void testPartialDivide() {
+ Divide divide = new Divide();
+ divide.setSynthesisEngine(synthesisEngine);
+
+ double x = 2.5;
+ double y = 9.7;
+ divide.inputA.setValueInternal(x);
+ divide.inputB.setValueInternal(y);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ divide.generate(2, 5);
+
+ assertEquals("Divide partial", 0.0, divide.output.getValues()[0], 0.001);
+ assertEquals("Divide partial", 0.0, divide.output.getValues()[1], 0.001);
+ assertEquals("Divide partial", x / y, divide.output.getValues()[2], 0.001);
+ assertEquals("Divide partial", x / y, divide.output.getValues()[3], 0.001);
+ assertEquals("Divide partial", x / y, divide.output.getValues()[4], 0.001);
+ assertEquals("Divide partial", 0.0, divide.output.getValues()[5], 0.001);
+ assertEquals("Divide partial", 0.0, divide.output.getValues()[6], 0.001);
+ assertEquals("Divide partial", 0.0, divide.output.getValues()[7], 0.001);
+
+ }
+
+ /**
+ * Unit test for MultiplyAdd.java - added by Lisa Tolentino 06/19/2009
+ */
+ public void testMultiplyAdd() {
+ MultiplyAdd multAdd = new MultiplyAdd();
+ multAdd.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ double z = 2.28;
+ multAdd.inputA.setValueInternal(x);
+ multAdd.inputB.setValueInternal(y);
+ multAdd.inputC.setValueInternal(z);
+
+ multAdd.generate();
+
+ assertEquals("MultiplyAdd", (x * y) + z, multAdd.output.getValue(), 0.001);
+ }
+
+ public void testPartialMultiplyAdd() {
+ MultiplyAdd multAdd = new MultiplyAdd();
+ multAdd.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ double z = 2.28;
+ multAdd.inputA.setValueInternal(x);
+ multAdd.inputB.setValueInternal(y);
+ multAdd.inputC.setValueInternal(z);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ multAdd.generate(2, 5);
+
+ assertEquals("MultiplyAdd partial", 0.0, multAdd.output.getValues()[0], 0.001);
+ assertEquals("MultiplyAdd partial", 0.0, multAdd.output.getValues()[1], 0.001);
+ assertEquals("MultiplyAdd partial", (x * y) + z, multAdd.output.getValues()[2], 0.001);
+ assertEquals("MultiplyAdd partial", (x * y) + z, multAdd.output.getValues()[3], 0.001);
+ assertEquals("MultiplyAdd partial", (x * y) + z, multAdd.output.getValues()[4], 0.001);
+ assertEquals("MultiplyAdd partial", 0.0, multAdd.output.getValues()[5], 0.001);
+ assertEquals("MultiplyAdd partial", 0.0, multAdd.output.getValues()[6], 0.001);
+ assertEquals("MultiplyAdd partial", 0.0, multAdd.output.getValues()[7], 0.001);
+
+ }
+
+ /**
+ * Unit test for Compare.java - added by Lisa Tolentino 06/19/2009
+ */
+ public void testCompare() {
+ UnitBinaryOperator compare = new Compare();
+ compare.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ compare.inputA.setValueInternal(x);
+ compare.inputB.setValueInternal(y);
+
+ compare.generate();
+
+ assertEquals("Compare", (x > y ? 1 : 0), compare.output.getValue(), 0.001);
+ }
+
+ public void testPartialCompare() {
+ UnitBinaryOperator compare = new Compare();
+ compare.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ compare.inputA.setValueInternal(x);
+ compare.inputB.setValueInternal(y);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ compare.generate(2, 5);
+
+ assertEquals("Compare partial", 0.0, compare.output.getValues()[0], 0.001);
+ assertEquals("Compare partial", 0.0, compare.output.getValues()[1], 0.001);
+ assertEquals("Compare partial", (x > y ? 1 : 0), compare.output.getValues()[2], 0.001);
+ assertEquals("Compare partial", (x > y ? 1 : 0), compare.output.getValues()[3], 0.001);
+ assertEquals("Compare partial", (x > y ? 1 : 0), compare.output.getValues()[4], 0.001);
+ assertEquals("Compare partial", 0.0, compare.output.getValues()[5], 0.001);
+ assertEquals("Compare partial", 0.0, compare.output.getValues()[6], 0.001);
+ assertEquals("Compare partial", 0.0, compare.output.getValues()[7], 0.001);
+
+ }
+
+ /**
+ * Unit test for Maximum.java - added by Lisa Tolentino 06/20/2009
+ */
+ public void testMaximum() {
+ Maximum max = new Maximum();
+ max.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ max.inputA.setValueInternal(x);
+ max.inputB.setValueInternal(y);
+
+ max.generate();
+
+ assertEquals("Maximum", (x > y ? x : y), max.output.getValue(), 0.001);
+ }
+
+ public void testPartialMaximum() {
+ Maximum max = new Maximum();
+ max.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ max.inputA.setValueInternal(x);
+ max.inputB.setValueInternal(y);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ max.generate(2, 5);
+
+ assertEquals("Maximum partial", 0.0, max.output.getValues()[0], 0.001);
+ assertEquals("Maximum partial", 0.0, max.output.getValues()[1], 0.001);
+ assertEquals("Maximum partial", (x > y ? x : y), max.output.getValues()[2], 0.001);
+ assertEquals("Maximum partial", (x > y ? x : y), max.output.getValues()[3], 0.001);
+ assertEquals("Maximum partial", (x > y ? x : y), max.output.getValues()[4], 0.001);
+ assertEquals("Maximum partial", 0.0, max.output.getValues()[5], 0.001);
+ assertEquals("Maximum partial", 0.0, max.output.getValues()[6], 0.001);
+ assertEquals("Maximum partial", 0.0, max.output.getValues()[7], 0.001);
+
+ }
+
+ /**
+ * Unit test for Minimum.java - added by Lisa Tolentino 06/20/2009
+ */
+ public void testMinimum() {
+ Minimum min = new Minimum();
+ min.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ min.inputA.setValueInternal(x);
+ min.inputB.setValueInternal(y);
+
+ min.generate();
+
+ assertEquals("Minimum", (x < y ? x : y), min.output.getValue(), 0.001);
+ }
+
+ public void testPartialMinimum() {
+ Minimum min = new Minimum();
+ min.setSynthesisEngine(synthesisEngine);
+
+ double x = 33.99;
+ double y = 8.31;
+ min.inputA.setValueInternal(x);
+ min.inputB.setValueInternal(y);
+
+ // Only generate a few values in the middle.
+ // This is to test low latency feedback loops.
+ // Only generate values for 2,3,4
+ min.generate(2, 5);
+
+ assertEquals("Maximum partial", 0.0, min.output.getValues()[0], 0.001);
+ assertEquals("Maximum partial", 0.0, min.output.getValues()[1], 0.001);
+ assertEquals("Maximum partial", (x < y ? x : y), min.output.getValues()[2], 0.001);
+ assertEquals("Maximum partial", (x < y ? x : y), min.output.getValues()[3], 0.001);
+ assertEquals("Maximum partial", (x < y ? x : y), min.output.getValues()[4], 0.001);
+ assertEquals("Maximum partial", 0.0, min.output.getValues()[5], 0.001);
+ assertEquals("Maximum partial", 0.0, min.output.getValues()[6], 0.001);
+ assertEquals("Maximum partial", 0.0, min.output.getValues()[7], 0.001);
+
+ }
+
+ public void testPowerOfTwo() {
+ PowerOfTwo powerOfTwo = new PowerOfTwo();
+ powerOfTwo.setSynthesisEngine(synthesisEngine);
+ final double smallValue = -1.5308084989341915E-17;
+ double values[] = {
+ 0.0, 1.3, 4.5, -0.5, -1.0, -2.8, smallValue, -smallValue, 1.0 - smallValue,
+ 1.0 + smallValue
+ };
+ for (double in : values) {
+ powerOfTwo.input.setValueInternal(in);
+ powerOfTwo.generate();
+ assertEquals("PowerOfTwo", Math.pow(2.0, in), powerOfTwo.output.getValue(), 0.001);
+ }
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/TestRamps.java b/tests/com/jsyn/unitgen/TestRamps.java
new file mode 100644
index 0000000..83ebacf
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestRamps.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+public class TestRamps extends NonRealTimeTestCase {
+
+ public void viewContinuousRamp(double duration, double startValue, double targetValue)
+ throws InterruptedException {
+ ContinuousRamp ramp = new ContinuousRamp();
+ synthesisEngine.add(ramp);
+
+ ramp.current.set(startValue);
+ ramp.input.set(startValue);
+ ramp.time.set(duration);
+
+ synthesisEngine.setRealTime(false);
+ synthesisEngine.start();
+ ramp.start();
+ synthesisEngine.sleepUntil(synthesisEngine.getCurrentTime() + 0.01);
+ ramp.input.set(targetValue);
+
+ double time = synthesisEngine.getCurrentTime();
+ int numLoops = 20;
+ double increment = duration / numLoops;
+ for (int i = 0; i < (numLoops + 1); i++) {
+ double value = ramp.output.getValue();
+ System.out.printf("i = %d, t = %9.5f, value = %8.4f\n", i, time, value);
+ time += increment;
+ synthesisEngine.sleepUntil(time);
+ }
+
+ synthesisEngine.stop();
+ }
+
+ public void checkContinuousRamp(double duration, double startValue, double targetValue)
+ throws InterruptedException {
+ ContinuousRamp ramp = new ContinuousRamp();
+ synthesisEngine.add(ramp);
+
+ ramp.current.set(startValue);
+ ramp.input.set(startValue);
+ ramp.time.set(duration);
+
+ synthesisEngine.setRealTime(false);
+ synthesisEngine.start();
+ ramp.start();
+ synthesisEngine.sleepUntil(synthesisEngine.getCurrentTime() + 0.01);
+ assertEquals("start flat", ramp.input.getValue(), ramp.output.getValue());
+
+ ramp.input.set(targetValue);
+ double startTime = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(startTime + (duration / 2));
+ assertEquals("ramping up", (targetValue + startValue) / 2.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + duration);
+ assertEquals("ramping up", targetValue, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + duration + 0.1);
+ assertEquals("flat again", targetValue, ramp.output.getValue());
+
+ synthesisEngine.stop();
+ }
+
+ public void testContinuousRamp() throws InterruptedException {
+ viewContinuousRamp(4.0, 0.0, 1.0);
+ }
+
+ public void testExponentialRamp() throws InterruptedException {
+ ExponentialRamp ramp = new ExponentialRamp();
+ synthesisEngine.add(ramp);
+
+ double duration = 0.3;
+ ramp.current.set(1.0);
+ ramp.input.set(1.0);
+ ramp.time.set(duration);
+
+ synthesisEngine.start();
+ ramp.start();
+ synthesisEngine.sleepUntil(synthesisEngine.getCurrentTime() + 0.01);
+ assertEquals("start flat", ramp.input.getValue(), ramp.output.getValue());
+
+ ramp.input.set(8.0);
+ double startTime = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(startTime + 0.1);
+ assertEquals("ramping up", 2.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.2);
+ assertEquals("ramping up", 4.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.3);
+ assertEquals("ramping up", 8.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.4);
+ assertEquals("flat again", 8.0, ramp.output.getValue());
+ }
+
+ public void testLinearRamp() throws InterruptedException {
+ LinearRamp ramp = new LinearRamp();
+ synthesisEngine.add(ramp);
+
+ double duration = 0.4;
+ ramp.current.set(0.0);
+ ramp.input.set(0.0);
+ ramp.time.set(duration);
+
+ synthesisEngine.start();
+ ramp.start();
+ synthesisEngine.sleepUntil(synthesisEngine.getCurrentTime() + 0.01);
+ assertEquals("start flat", ramp.input.getValue(), ramp.output.getValue());
+
+ ramp.input.set(8.0);
+ double startTime = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(startTime + 0.1);
+ assertEquals("ramping up", 2.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.2);
+ assertEquals("ramping up", 4.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.3);
+ assertEquals("ramping up", 6.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.4);
+ assertEquals("flat again", 8.0, ramp.output.getValue());
+ }
+
+ public void testExponentialRampConnected() throws InterruptedException {
+ ExponentialRamp ramp = new ExponentialRamp();
+ PassThrough pass = new PassThrough();
+ synthesisEngine.add(ramp);
+ synthesisEngine.add(pass);
+
+ double duration = 0.3;
+ ramp.current.set(1.0);
+ pass.input.set(1.0);
+ ramp.time.set(duration);
+
+ // Send value through a connected unit.
+ pass.input.set(1.0);
+ pass.output.connect(ramp.input);
+
+ synthesisEngine.start();
+ ramp.start();
+ synthesisEngine.sleepUntil(synthesisEngine.getCurrentTime() + 0.01);
+ assertEquals("start flat", ramp.input.getValue(), ramp.output.getValue());
+
+ pass.input.set(8.0);
+ double startTime = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(startTime + 0.1);
+ assertEquals("ramping up", 2.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.2);
+ assertEquals("ramping up", 4.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.3);
+ assertEquals("ramping up", 8.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.4);
+ assertEquals("flat again", 8.0, ramp.output.getValue());
+ }
+
+ public void testLinearRampConnected() throws InterruptedException {
+ LinearRamp ramp = new LinearRamp();
+ PassThrough pass = new PassThrough();
+ synthesisEngine.add(ramp);
+ synthesisEngine.add(pass);
+
+ double duration = 0.4;
+ ramp.current.set(0.0);
+ pass.input.set(0.0);
+ ramp.time.set(duration);
+
+ // Send value through a connected unit.
+ pass.input.set(0.0);
+ pass.output.connect(ramp.input);
+
+ synthesisEngine.start();
+ ramp.start();
+ synthesisEngine.sleepUntil(synthesisEngine.getCurrentTime() + 0.01);
+ assertEquals("start flat", ramp.input.getValue(), ramp.output.getValue());
+
+ pass.input.set(8.0);
+ double startTime = synthesisEngine.getCurrentTime();
+ synthesisEngine.sleepUntil(startTime + 0.1);
+ assertEquals("ramping up", 2.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.2);
+ assertEquals("ramping up", 4.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.3);
+ assertEquals("ramping up", 6.0, ramp.output.getValue(), 0.01);
+ synthesisEngine.sleepUntil(startTime + 0.4);
+ assertEquals("flat again", 8.0, ramp.output.getValue());
+ }
+
+}
diff --git a/tests/com/jsyn/unitgen/TestUnitGate.java b/tests/com/jsyn/unitgen/TestUnitGate.java
new file mode 100644
index 0000000..14129aa
--- /dev/null
+++ b/tests/com/jsyn/unitgen/TestUnitGate.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2009 Phil Burk, Mobileer Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jsyn.unitgen;
+
+import junit.framework.TestCase;
+
+import com.jsyn.engine.SynthesisEngine;
+
+public class TestUnitGate extends TestCase {
+
+ protected SynthesisEngine synthesisEngine;
+ protected double time;
+
+ public void checkAutoDisable(LinearRamp ramp, UnitGate envelope) throws InterruptedException {
+ double tolerance = 0.01;
+ Add adder = new Add();
+ synthesisEngine.add(adder);
+
+ envelope.output.connect(adder.inputA);
+ if (ramp.getCircuit() != null) {
+ ramp.output.connect(adder.inputB);
+ }
+
+ envelope.input.setAutoDisableEnabled(true);
+ envelope.setEnabled(false);
+
+ // set up so ramp value should equal time
+ ramp.current.set(0.0);
+ ramp.input.set(1.0);
+ ramp.time.set(1.0);
+
+ synthesisEngine.start();
+ // pull from final adder
+ adder.start();
+
+ time = synthesisEngine.getCurrentTime();
+ time += 0.1;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("still idling", 0.0, envelope.output.getValue());
+ assertEquals("ramp frozen at beginning", 0.0, ramp.output.getValue(), tolerance);
+
+ // run multiple times to make sure we can retrigger the envelope.
+ for (int i = 0; i < 3; i++) {
+ double level = ramp.output.getValue();
+ // Trigger the envelope using trigger()
+ envelope.input.on();
+ time += 0.1;
+ level += 0.1;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("ramp going up " + i, level, ramp.output.getValue(), tolerance);
+ assertTrue("enabled at peak", envelope.isEnabled());
+
+ envelope.input.off();
+ time += 0.1;
+ level += 0.1;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("ramp going up more " + i, level, ramp.output.getValue(), tolerance);
+ assertEquals("at bottom", 0.0, envelope.output.getValue(), 0.1);
+
+ time += 0.2;
+ synthesisEngine.sleepUntil(time);
+ assertEquals("ramp frozen " + i, level, ramp.output.getValue(), tolerance);
+ }
+ }
+
+}