aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/jsyn/instruments/WaveShapingVoice.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/jsyn/instruments/WaveShapingVoice.java')
-rw-r--r--src/com/jsyn/instruments/WaveShapingVoice.java187
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();
+ }
+
+}