diff options
Diffstat (limited to 'src/com/jsyn/instruments/WaveShapingVoice.java')
-rw-r--r-- | src/com/jsyn/instruments/WaveShapingVoice.java | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/com/jsyn/instruments/WaveShapingVoice.java b/src/com/jsyn/instruments/WaveShapingVoice.java new file mode 100644 index 0000000..5044f21 --- /dev/null +++ b/src/com/jsyn/instruments/WaveShapingVoice.java @@ -0,0 +1,187 @@ +/* + * Copyright 2011 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.data.DoubleTable; +import com.jsyn.ports.UnitFunctionPort; +import com.jsyn.ports.UnitInputPort; +import com.jsyn.ports.UnitOutputPort; +import com.jsyn.unitgen.Circuit; +import com.jsyn.unitgen.EnvelopeDAHDSR; +import com.jsyn.unitgen.FunctionEvaluator; +import com.jsyn.unitgen.Multiply; +import com.jsyn.unitgen.SineOscillator; +import com.jsyn.unitgen.UnitOscillator; +import com.jsyn.unitgen.UnitVoice; +import com.jsyn.util.VoiceDescription; +import com.softsynth.math.ChebyshevPolynomial; +import com.softsynth.math.PolynomialTableData; +import com.softsynth.shared.time.TimeStamp; + +/** + * Waveshaping oscillator with envelopes. + * + * @author Phil Burk (C) 2011 Mobileer Inc + */ +public class WaveShapingVoice extends Circuit implements UnitVoice { + private static final long serialVersionUID = -2704222221111608377L; + private static final int NUM_PRESETS = 3; + private UnitOscillator osc; + private FunctionEvaluator waveShaper; + private EnvelopeDAHDSR ampEnv; + private EnvelopeDAHDSR rangeEnv; + private Multiply frequencyScaler; + + public UnitInputPort range; + public UnitInputPort frequency; + public UnitInputPort amplitude; + public UnitFunctionPort function; + public UnitInputPort pitchModulation; + + // default Chebyshev polynomial table to share. + private static DoubleTable chebyshevTable; + private final static int CHEBYSHEV_ORDER = 11; + + static { + // Make table with Chebyshev polynomial to share among voices + PolynomialTableData chebData = new PolynomialTableData( + ChebyshevPolynomial.T(CHEBYSHEV_ORDER), 1024); + chebyshevTable = new DoubleTable(chebData.getData()); + } + + public WaveShapingVoice() { + add(frequencyScaler = new Multiply()); + add(osc = new SineOscillator()); + add(waveShaper = new FunctionEvaluator()); + add(rangeEnv = new EnvelopeDAHDSR()); + add(ampEnv = new EnvelopeDAHDSR()); + + addPort(amplitude = ampEnv.amplitude); + addPort(range = osc.amplitude, "Range"); + addPort(function = waveShaper.function); + addPort(frequency = frequencyScaler.inputA, "Frequency"); + addPort(pitchModulation = frequencyScaler.inputB, "PitchMod"); + + ampEnv.export(this, "Amp"); + rangeEnv.export(this, "Range"); + + function.set(chebyshevTable); + + // Connect units. + osc.output.connect(rangeEnv.amplitude); + rangeEnv.output.connect(waveShaper.input); + ampEnv.output.connect(waveShaper.amplitude); + frequencyScaler.output.connect(osc.frequency); + + // Set reasonable defaults for the ports. + pitchModulation.setup(0.1, 1.0, 10.0); + range.setup(0.1, 0.8, 1.0); + frequency.setup(osc.frequency); + amplitude.setup(0.0, 0.5, 1.0); + + // Make the circuit turn off when the envelope finishes to reduce CPU load. + ampEnv.setupAutoDisable(this); + + usePreset(2); + } + + @Override + public UnitOutputPort getOutput() { + return waveShaper.output; + } + + @Override + public void noteOn(double freq, double amp, TimeStamp timeStamp) { + frequency.set(freq, timeStamp); + amplitude.set(amp, timeStamp); + ampEnv.input.on(timeStamp); + rangeEnv.input.on(timeStamp); + } + + @Override + public void noteOff(TimeStamp timeStamp) { + ampEnv.input.off(timeStamp); + rangeEnv.input.off(timeStamp); + } + + @Override + public void usePreset(int presetIndex) { + int n = presetIndex % NUM_PRESETS; + switch (n) { + case 0: + ampEnv.attack.set(0.01); + ampEnv.decay.set(0.2); + ampEnv.release.set(1.0); + rangeEnv.attack.set(0.01); + rangeEnv.decay.set(0.2); + rangeEnv.sustain.set(0.4); + rangeEnv.release.set(1.0); + break; + case 1: + ampEnv.attack.set(0.5); + ampEnv.decay.set(0.3); + ampEnv.release.set(0.2); + rangeEnv.attack.set(0.03); + rangeEnv.decay.set(0.2); + rangeEnv.sustain.set(0.5); + rangeEnv.release.set(1.0); + break; + default: + ampEnv.attack.set(0.1); + ampEnv.decay.set(0.3); + ampEnv.release.set(0.5); + rangeEnv.attack.set(0.01); + rangeEnv.decay.set(0.2); + rangeEnv.sustain.set(0.9); + rangeEnv.release.set(1.0); + break; + } + } + + static class MyVoiceDescription extends VoiceDescription { + static String[] presetNames = { + "FastChebyshev", "SlowChebyshev", "BrightChebyshev" + }; + static String[] tags = { + "electronic", "waveshaping", "clean" + }; + + public MyVoiceDescription() { + super("Waveshaping", presetNames); + } + + @Override + public UnitVoice createUnitVoice() { + return new WaveShapingVoice(); + } + + @Override + public String[] getTags(int presetIndex) { + return tags; + } + + @Override + public String getVoiceClassName() { + return WaveShapingVoice.class.getName(); + } + } + + public static VoiceDescription getVoiceDescription() { + return new MyVoiceDescription(); + } + +} |