From 2785ec51000f9dd7a7640f1a4edb69f541d757f1 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Wed, 30 Nov 2016 19:02:58 -0800 Subject: cleanup for 16.7.8, doc MultiChannelSynthesizer, add DoubleTable.length() --- src/com/jsyn/JSyn.java | 6 +-- src/com/jsyn/data/DoubleTable.java | 12 ++++-- src/com/jsyn/midi/MidiSynthesizer.java | 20 +++++++++ src/com/jsyn/util/MultiChannelSynthesizer.java | 60 +++++++++++++++++++++++--- src/com/jsyn/util/PolyphonicInstrument.java | 2 +- 5 files changed, 85 insertions(+), 15 deletions(-) (limited to 'src/com/jsyn') diff --git a/src/com/jsyn/JSyn.java b/src/com/jsyn/JSyn.java index 7598305..8eed8a9 100644 --- a/src/com/jsyn/JSyn.java +++ b/src/com/jsyn/JSyn.java @@ -56,10 +56,10 @@ public class JSyn { // Update these for every release. private final static int VERSION_MAJOR = 16; private final static int VERSION_MINOR = 7; - private final static int VERSION_REVISION = 6; - public final static int BUILD_NUMBER = 460; + private final static int VERSION_REVISION = 8; + public final static int BUILD_NUMBER = 462; private final static long BUILD_TIME = new GregorianCalendar(2016, - GregorianCalendar.AUGUST, 9).getTime().getTime(); + GregorianCalendar.NOVEMBER, 30).getTime().getTime(); public final static String VERSION = VERSION_MAJOR + "." + VERSION_MINOR + "." + VERSION_REVISION; diff --git a/src/com/jsyn/data/DoubleTable.java b/src/com/jsyn/data/DoubleTable.java index 0a34a95..ca64c94 100644 --- a/src/com/jsyn/data/DoubleTable.java +++ b/src/com/jsyn/data/DoubleTable.java @@ -4,9 +4,9 @@ * 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. @@ -21,7 +21,7 @@ import com.jsyn.exceptions.ChannelMismatchException; /** * Evaluate a Function by interpolating between the values in a table. This can be used for * wavetable lookup or waveshaping. - * + * * @author Phil Burk (C) 2010 Mobileer Inc */ public class DoubleTable implements Function { @@ -60,6 +60,10 @@ public class DoubleTable implements Function { table = new double[numFrames]; } + public int length() { + return table.length; + } + public void write(double[] data) { write(0, data, 0, data.length); } @@ -79,7 +83,7 @@ public class DoubleTable implements Function { /** * Treat the double array as a lookup table with a domain of -1.0 to 1.0. If the input is out of * range then the output will clip to the end values. - * + * * @param input * @return interpolated value from table */ diff --git a/src/com/jsyn/midi/MidiSynthesizer.java b/src/com/jsyn/midi/MidiSynthesizer.java index e011430..30204b0 100644 --- a/src/com/jsyn/midi/MidiSynthesizer.java +++ b/src/com/jsyn/midi/MidiSynthesizer.java @@ -16,8 +16,28 @@ package com.jsyn.midi; +import com.jsyn.instruments.DualOscillatorSynthVoice; import com.jsyn.util.MultiChannelSynthesizer; +/** + * Map MIDI messages into calls to a MultiChannelSynthesizer. + * Handles CONTROLLER_MOD_WHEEL, TIMBRE, VOLUME and PAN. + * Handles Bend Range RPN. + * + *

+    voiceDescription = DualOscillatorSynthVoice.getVoiceDescription();
+    multiSynth = new MultiChannelSynthesizer();
+    final int startChannel = 0;
+    multiSynth.setup(synth, startChannel, NUM_CHANNELS, VOICES_PER_CHANNEL, voiceDescription);
+    midiSynthesizer = new MidiSynthesizer(multiSynth);
+    // pass MIDI bytes
+    midiSynthesizer.onReceive(bytes, 0, bytes.length);
+    
+ * + * See the example UseMidiKeyboard.java + * + * @author Phil Burk (C) 2016 Mobileer Inc + */ public class MidiSynthesizer extends MessageParser { private MultiChannelSynthesizer multiSynth; diff --git a/src/com/jsyn/util/MultiChannelSynthesizer.java b/src/com/jsyn/util/MultiChannelSynthesizer.java index 6db0790..8027994 100644 --- a/src/com/jsyn/util/MultiChannelSynthesizer.java +++ b/src/com/jsyn/util/MultiChannelSynthesizer.java @@ -52,6 +52,8 @@ public class MultiChannelSynthesizer { private Synthesizer synth; private TwoInDualOut outputUnit; private ChannelContext[] channels; + private final static int MAX_VELOCITY = 127; + private double mMasterAmplitude = 0.25; private class ChannelGroupContext { private VoiceDescription voiceDescription; @@ -83,7 +85,6 @@ public class MultiChannelSynthesizer { private Pan panner; private double vibratoRate = 5.0; private double bendRangeOctaves = 2.0 / 12.0; -// private double bendRangeOctaves = 0.0 / 12.0; private int presetIndex; private ChannelGroupContext groupContext; VoiceOperation voiceOperation = new VoiceOperation() { @@ -120,7 +121,6 @@ public class MultiChannelSynthesizer { volumeMultiplier.output.connect(panner.input); panner.output.connect(0, outputUnit.inputA, 0); // Use MultiPassthrough panner.output.connect(1, outputUnit.inputB, 0); - } private void connectVoice(UnitVoice voice) { @@ -157,13 +157,12 @@ public class MultiChannelSynthesizer { presetIndex = programWrapped; } - void noteOff(int noteNumber, int velocity) { + void noteOff(int noteNumber, double amplitude) { groupContext.allocator.noteOff(noteNumber, synth.createTimeStamp()); } - void noteOn(int noteNumber, int velocity) { + void noteOn(int noteNumber, double amplitude) { double frequency = AudioMath.pitchToFrequency(noteNumber); - double amplitude = velocity / (4 * 128.0); TimeStamp timeStamp = synth.createTimeStamp(); //System.out.println("noteOn(noteNumber) -> " + frequency + " Hz"); groupContext.allocator.noteOn(noteNumber, frequency, amplitude, voiceOperation, timeStamp); @@ -257,14 +256,48 @@ public class MultiChannelSynthesizer { channelContext.programChange(program); } + + /** + * Turn off a note. + * @param channel + * @param noteNumber + * @param velocity between 0 and 127, will be scaled by masterAmplitude + */ public void noteOff(int channel, int noteNumber, int velocity) { + double amplitude = velocity * (1.0 / MAX_VELOCITY); + noteOff(channel, noteNumber, amplitude); + } + + /** + * Turn off a note. + * @param channel + * @param noteNumber + * @param amplitude between 0 and 1.0, will be scaled by masterAmplitude + */ + public void noteOff(int channel, int noteNumber, double amplitude) { ChannelContext channelContext = channels[channel]; - channelContext.noteOff(noteNumber, velocity); + channelContext.noteOff(noteNumber, amplitude * mMasterAmplitude); } + /** + * Turn on a note. + * @param channel + * @param noteNumber + * @param velocity between 0 and 127, will be scaled by masterAmplitude + */ public void noteOn(int channel, int noteNumber, int velocity) { + double amplitude = velocity * (1.0 / MAX_VELOCITY); + noteOn(channel, noteNumber, amplitude); + } + /** + * Turn on a note. + * @param channel + * @param noteNumber + * @param amplitude between 0 and 1.0, will be scaled by masterAmplitude + */ + public void noteOn(int channel, int noteNumber, double amplitude) { ChannelContext channelContext = channels[channel]; - channelContext.noteOn(noteNumber, velocity); + channelContext.noteOn(noteNumber, amplitude * mMasterAmplitude); } /** @@ -321,8 +354,21 @@ public class MultiChannelSynthesizer { channelContext.setPan(pan); } + /** + * @return stereo output port + */ public UnitOutputPort getOutput() { return outputUnit.output; } + /** + * Set amplitude for a single voice when the velocity is 127. + * @param masterAmplitude + */ + public void setMasterAmplitude(double masterAmplitude) { + mMasterAmplitude = masterAmplitude; + } + public double getMasterAmplitude() { + return mMasterAmplitude; + } } diff --git a/src/com/jsyn/util/PolyphonicInstrument.java b/src/com/jsyn/util/PolyphonicInstrument.java index 2cba78f..08460d0 100644 --- a/src/com/jsyn/util/PolyphonicInstrument.java +++ b/src/com/jsyn/util/PolyphonicInstrument.java @@ -86,7 +86,7 @@ public class PolyphonicInstrument extends Circuit implements UnitSource, Instrum * @param portName * @see exportAllInputPorts */ - void exportNamedInputPort(String portName) { + public void exportNamedInputPort(String portName) { UnitInputPort voicePort = null; PassThrough fanout = new PassThrough(); for (UnitVoice voice : voices) { -- cgit v1.2.3