aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/com/jsyn/unitgen/ParabolicEnvelope.java
blob: 6de97d999fbc7c6d3b82781a7757f1b7fd617e4e (plain)
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;
        }
    }
}