1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/*
* Copyright 1997 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;
import com.jsyn.ports.UnitOutputPort;
/**
* ParabolicEnvelope unit. Output goes from zero to amplitude then back to zero in a parabolic arc.
* <P>
* Generate a short parabolic envelope that could be used for granular synthesis. The output starts
* at zero, peaks at the value of amplitude then returns to zero. This unit has two states, IDLE and
* RUNNING. If a trigger is received when IDLE, the envelope is started and another trigger is sent
* out the triggerOutput port. This triggerOutput can be used to latch values for the synthesis of a
* grain. If a trigger is received when RUNNING, then it is ignored and passed out the triggerPass
* port. The triggerPass can be connected to the triggerInput of another ParabolicEnvelope. Thus you
* can implement a simple grain allocation scheme by daisy chaining the triggers of
* ParabolicEnvelopes.
* <P>
* The envelope is generated by a double integrator method so it uses relatively little CPU time.
*
* @author (C) 1997 Phil Burk, SoftSynth.com
* @see EnvelopeDAHDSR
*/
public class ParabolicEnvelope extends UnitGenerator {
/** Fastest repeat rate of envelope if it were continually retriggered in Hertz. */
public UnitInputPort frequency;
/** True value triggers envelope when in resting state. */
public UnitInputPort triggerInput;
public UnitInputPort amplitude;
/** Trigger output when envelope started. */
public UnitOutputPort triggerOutput;
/** Input trigger passed out if ignored for daisy chaining. */
public UnitOutputPort triggerPass;
public UnitOutputPort output;
private double slope;
private double curve;
private double level;
private boolean running;
/* Define Unit Ports used by connect() and set(). */
public ParabolicEnvelope() {
addPort(triggerInput = new UnitInputPort("Input"));
addPort(frequency = new UnitInputPort("Frequency", UnitOscillator.DEFAULT_FREQUENCY));
addPort(amplitude = new UnitInputPort("Amplitude", UnitOscillator.DEFAULT_AMPLITUDE));
addPort(output = new UnitOutputPort("Output"));
addPort(triggerOutput = new UnitOutputPort("TriggerOutput"));
addPort(triggerPass = new UnitOutputPort("TriggerPass"));
}
@Override
public void generate(int start, int limit) {
double[] frequencies = frequency.getValues();
double[] amplitudes = amplitude.getValues();
double[] triggerInputs = triggerInput.getValues();
double[] outputs = output.getValues();
double[] triggerPasses = triggerPass.getValues();
double[] triggerOutputs = triggerOutput.getValues();
for (int i = start; i < limit; i++) {
if (!running) {
if (triggerInputs[i] > 0) {
double freq = frequencies[i] * synthesisEngine.getInverseNyquist();
freq = (freq > 1.0) ? 1.0 : ((freq < -1.0) ? -1.0 : freq);
double ampl = amplitudes[i];
double freq2 = freq * freq; /* Square frequency. */
slope = 4.0 * ampl * (freq - freq2);
curve = -8.0 * ampl * freq2;
level = 0.0;
triggerOutputs[i] = UnitGenerator.TRUE;
running = true;
} else {
triggerOutputs[i] = UnitGenerator.FALSE;
}
triggerPasses[i] = UnitGenerator.FALSE;
} else /* RUNNING */
{
level += slope;
slope += curve;
if (level <= 0.0) {
level = 0.0;
running = false;
/* Autostop? - FIXME */
}
triggerOutputs[i] = UnitGenerator.FALSE;
triggerPasses[i] = triggerInputs[i];
}
outputs[i] = level;
}
}
}
|