diff options
Diffstat (limited to 'src/main/java/com/jsyn/instruments/SubtractiveSynthVoice.java')
-rw-r--r-- | src/main/java/com/jsyn/instruments/SubtractiveSynthVoice.java | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/main/java/com/jsyn/instruments/SubtractiveSynthVoice.java b/src/main/java/com/jsyn/instruments/SubtractiveSynthVoice.java new file mode 100644 index 0000000..5cfc4b9 --- /dev/null +++ b/src/main/java/com/jsyn/instruments/SubtractiveSynthVoice.java @@ -0,0 +1,182 @@ +/* + * 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.instruments; + +import com.jsyn.ports.UnitInputPort; +import com.jsyn.ports.UnitOutputPort; +import com.jsyn.unitgen.Add; +import com.jsyn.unitgen.Circuit; +import com.jsyn.unitgen.EnvelopeDAHDSR; +import com.jsyn.unitgen.FilterLowPass; +import com.jsyn.unitgen.Multiply; +import com.jsyn.unitgen.SawtoothOscillatorBL; +import com.jsyn.unitgen.UnitOscillator; +import com.jsyn.unitgen.UnitVoice; +import com.jsyn.util.VoiceDescription; +import com.softsynth.shared.time.TimeStamp; + +/** + * Typical synthesizer voice with one oscillator and a biquad resonant filter. Modulate the amplitude and + * filter using DAHDSR envelopes. + * + * @author Phil Burk (C) 2010 Mobileer Inc + */ +public class SubtractiveSynthVoice extends Circuit implements UnitVoice { + private UnitOscillator osc; + private FilterLowPass filter; + private EnvelopeDAHDSR ampEnv; + private EnvelopeDAHDSR filterEnv; + private Add cutoffAdder; + private Multiply frequencyScaler; + + public UnitInputPort amplitude; + public UnitInputPort frequency; + /** + * This scales the frequency value. You can use this to modulate a group of instruments using a + * shared LFO and they will stay in tune. + */ + public UnitInputPort pitchModulation; + public UnitInputPort cutoff; + public UnitInputPort cutoffRange; + public UnitInputPort Q; + + public SubtractiveSynthVoice() { + add(frequencyScaler = new Multiply()); + // Add a tone generator. + add(osc = new SawtoothOscillatorBL()); + + // Use an envelope to control the amplitude. + add(ampEnv = new EnvelopeDAHDSR()); + + // Use an envelope to control the filter cutoff. + add(filterEnv = new EnvelopeDAHDSR()); + add(filter = new FilterLowPass()); + add(cutoffAdder = new Add()); + + filterEnv.output.connect(cutoffAdder.inputA); + cutoffAdder.output.connect(filter.frequency); + frequencyScaler.output.connect(osc.frequency); + osc.output.connect(filter.input); + filter.output.connect(ampEnv.amplitude); + + addPort(amplitude = osc.amplitude, "Amplitude"); + addPort(frequency = frequencyScaler.inputA, "Frequency"); + addPort(pitchModulation = frequencyScaler.inputB, "PitchMod"); + addPort(cutoff = cutoffAdder.inputB, "Cutoff"); + addPort(cutoffRange = filterEnv.amplitude, "CutoffRange"); + addPort(Q = filter.Q); + + ampEnv.export(this, "Amp"); + filterEnv.export(this, "Filter"); + + frequency.setup(osc.frequency); + pitchModulation.setup(0.2, 1.0, 4.0); + cutoff.setup(filter.frequency); + cutoffRange.setup(filter.frequency); + + // Make the circuit turn off when the envelope finishes to reduce CPU load. + ampEnv.setupAutoDisable(this); + + usePreset(0); + } + + @Override + public void noteOff(TimeStamp timeStamp) { + ampEnv.input.off(timeStamp); + filterEnv.input.off(timeStamp); + } + + @Override + public void noteOn(double freq, double ampl, TimeStamp timeStamp) { + frequency.set(freq, timeStamp); + amplitude.set(ampl, timeStamp); + + ampEnv.input.on(timeStamp); + filterEnv.input.on(timeStamp); + } + + @Override + public UnitOutputPort getOutput() { + return ampEnv.output; + } + + @Override + public void usePreset(int presetIndex) { + int n = presetIndex % presetNames.length; + switch (n) { + case 0: + ampEnv.attack.set(0.01); + ampEnv.decay.set(0.2); + ampEnv.release.set(1.0); + cutoff.set(500.0); + cutoffRange.set(500.0); + filter.Q.set(1.0); + break; + case 1: + ampEnv.attack.set(0.5); + ampEnv.decay.set(0.3); + ampEnv.release.set(0.2); + cutoff.set(500.0); + cutoffRange.set(500.0); + filter.Q.set(3.0); + break; + case 2: + default: + ampEnv.attack.set(0.1); + ampEnv.decay.set(0.3); + ampEnv.release.set(0.5); + cutoff.set(2000.0); + cutoffRange.set(500.0); + filter.Q.set(2.0); + break; + } + } + + static String[] presetNames = { + "FastSaw", "SlowSaw", "BrightSaw" + }; + + static class MyVoiceDescription extends VoiceDescription { + String[] tags = { + "electronic", "filter", "clean" + }; + + public MyVoiceDescription() { + super("SubtractiveSynth", presetNames); + } + + @Override + public UnitVoice createUnitVoice() { + return new SubtractiveSynthVoice(); + } + + @Override + public String[] getTags(int presetIndex) { + return tags; + } + + @Override + public String getVoiceClassName() { + return SubtractiveSynthVoice.class.getName(); + } + } + + public static VoiceDescription getVoiceDescription() { + return new MyVoiceDescription(); + } + +} |