diff options
Diffstat (limited to 'src/com/jsyn')
248 files changed, 0 insertions, 24850 deletions
diff --git a/src/com/jsyn/JSyn.java b/src/com/jsyn/JSyn.java deleted file mode 100644 index bbc2891..0000000 --- a/src/com/jsyn/JSyn.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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; - -import java.sql.Date; -import java.util.GregorianCalendar; - -import com.jsyn.devices.AudioDeviceManager; -import com.jsyn.engine.SynthesisEngine; - -/** - * JSyn Synthesizer for Java. Use this factory class to create a synthesizer. This code demonstrates - * how to start playing a sine wave: - * - * <pre><code> - // Create a context for the synthesizer. - synth = JSyn.createSynthesizer(); - - // Start synthesizer using default stereo output at 44100 Hz. - synth.start(); - - // Add a tone generator. - synth.add( osc = new SineOscillator() ); - // Add a stereo audio output unit. - synth.add( lineOut = new LineOut() ); - - // Connect the oscillator to both channels of the output. - osc.output.connect( 0, lineOut.input, 0 ); - osc.output.connect( 0, lineOut.input, 1 ); - - // Set the frequency and amplitude for the sine wave. - osc.frequency.set( 345.0 ); - osc.amplitude.set( 0.6 ); - - // We only need to start the LineOut. It will pull data from the oscillator. - lineOut.start(); -</code> </pre> - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class JSyn { - // Update these for every release. - private final static int VERSION_MAJOR = 16; - private final static int VERSION_MINOR = 8; - private final static int VERSION_REVISION = 1; - public final static int BUILD_NUMBER = 464; - private final static long BUILD_TIME = new GregorianCalendar(2017, - GregorianCalendar.OCTOBER, 16).getTime().getTime(); - - public final static String VERSION = VERSION_MAJOR + "." + VERSION_MINOR + "." - + VERSION_REVISION; - public final static int VERSION_CODE = (VERSION_MAJOR << 16) + (VERSION_MINOR << 8) - + VERSION_REVISION; - public final static String VERSION_TEXT = "V" + VERSION + " (build " + BUILD_NUMBER + ", " - + (new Date(BUILD_TIME)) + ")"; - - public static Synthesizer createSynthesizer() { - return new SynthesisEngine(); - } - - public static Synthesizer createSynthesizer(AudioDeviceManager audioDeviceManager) { - return new SynthesisEngine(audioDeviceManager); - } -} diff --git a/src/com/jsyn/Synthesizer.java b/src/com/jsyn/Synthesizer.java deleted file mode 100644 index bfabb4c..0000000 --- a/src/com/jsyn/Synthesizer.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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; - -import com.jsyn.devices.AudioDeviceManager; -import com.jsyn.unitgen.UnitGenerator; -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -/** - * A synthesizer used by JSyn to generate audio. The synthesizer executes a network of unit - * generators to create an audio signal. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public interface Synthesizer { - - public final static int FRAMES_PER_BLOCK = 8; - - /** - * Starts a background thread that generates audio using the default frame rate of 44100 and two - * stereo output channels. - */ - public void start(); - - /** - * Starts a background thread that generates audio using the specified frame rate and two stereo - * output channels. - * - * @param frameRate in Hertz - */ - public void start(int frameRate); - - /** - * Starts the synthesizer using specific audio devices. - * <p> - * Note that using more than 2 channels will probably require the use of JPortAudio because - * JavaSound currently does not support more than two channels. - * JPortAudio is available at - * <a href="http://www.softsynth.com/jsyn/developers/download.php">http://www.softsynth.com/jsyn/developers/download.php</a>. - * <p> - * If you use more than 2 inputs or outputs then you will probably want to use {@link com.jsyn.unitgen.ChannelIn} - * or {@link com.jsyn.unitgen.ChannelOut}, which can be associated with any indexed channel. - * - * @param frameRate in Hertz - * @param inputDeviceID obtained from an {@link AudioDeviceManager} or pass - * AudioDeviceManager.USE_DEFAULT_DEVICE - * @param numInputChannels 0 for no input, 1 for mono, 2 for stereo, etcetera - * @param ouputDeviceID obtained from an AudioDeviceManager or pass - * AudioDeviceManager.USE_DEFAULT_DEVICE - * @param numOutputChannels 0 for no output, 1 for mono, 2 for stereo, etcetera - */ - public void start(int frameRate, int inputDeviceID, int numInputChannels, int ouputDeviceID, - int numOutputChannels); - - /** @return JSyn version as a string */ - public String getVersion(); - - /** @return version as an integer that always increases */ - public int getVersionCode(); - - /** Stops the background thread that generates the audio. */ - public void stop(); - - /** - * An AudioDeviceManager is an interface to audio hardware. It might be implemented using - * JavaSound or a wrapper around PortAudio. - * - * @return audio device manager being used by the synthesizer. - */ - public AudioDeviceManager getAudioDeviceManager(); - - /** @return the frame rate in samples per second */ - public int getFrameRate(); - - /** - * Add a unit generator to the synthesizer so it can be played. This is required before starting - * or connecting a unit generator into a network. - * - * @param ugen a unit generator to be executed by the synthesizer - */ - public void add(UnitGenerator ugen); - - /** Removes a unit generator added using add(). */ - public void remove(UnitGenerator ugen); - - /** @return the current audio time in seconds */ - public double getCurrentTime(); - - /** - * Start a unit generator at the specified time. This is not needed if a unit generator's output - * is connected to other units. Typically you only need to start units that have no outputs, for - * example LineOut or ChannelOut. - */ - public void startUnit(UnitGenerator unit, double time); - - public void startUnit(UnitGenerator unit, TimeStamp timeStamp); - - /** - * The startUnit and stopUnit methods are mainly for internal use. - * Please call unit.start() or unit.stop() instead. - * @param unit - */ - public void startUnit(UnitGenerator unit); - - public void stopUnit(UnitGenerator unit, double time); - - public void stopUnit(UnitGenerator unit, TimeStamp timeStamp); - - /** - * The startUnit and stopUnit methods are mainly for internal use. - * Please call unit.start() or unit.stop() instead. - * @param unit - */ - public void stopUnit(UnitGenerator unit); - - /** - * Sleep until the specified audio time is reached. In non-real-time mode, this will enable the - * synthesizer to run. - */ - public void sleepUntil(double time) throws InterruptedException; - - /** - * Sleep for the specified audio time duration. In non-real-time mode, this will enable the - * synthesizer to run. - */ - public void sleepFor(double duration) throws InterruptedException; - - /** - * If set true then the synthesizer will generate audio in real-time. Set it true for live - * audio. If false then JSyn will run in non-real-time mode. This can be used to generate audio - * to be written to a file. The default is true. - * - * @param realTime - */ - public void setRealTime(boolean realTime); - - /** Is JSyn running in real-time mode? */ - public boolean isRealTime(); - - /** Create a TimeStamp using the current audio time. */ - public TimeStamp createTimeStamp(); - - /** @return the current CPU usage as a fraction between 0.0 and 1.0 */ - public double getUsage(); - - /** @return inverse of frameRate, to avoid expensive divides */ - public double getFramePeriod(); - - /** - * This count is not reset if you stop and restart. - * - * @return number of frames synthesized - */ - public long getFrameCount(); - - /** Queue a command to be processed at a specific time in the background audio thread. */ - public void scheduleCommand(TimeStamp timeStamp, ScheduledCommand command); - - /** Queue a command to be processed at a specific time in the background audio thread. */ - public void scheduleCommand(double time, ScheduledCommand command); - - /** Queue a command to be processed as soon as possible in the background audio thread. */ - public void queueCommand(ScheduledCommand command); - - /** - * Clear all scheduled commands from the queue. - * Commands will be discarded. - */ - public void clearCommandQueue(); - - /** - * @return true if the Synthesizer has been started - */ - public boolean isRunning(); - - /** - * Add a task that will be run repeatedly on the Audio Thread before it generates every new block of Audio. - * This task must be very quick and should not perform any blocking operations. If you are not - * certain that you need an Audio rate task then don't use this. - * - * @param task - */ - public void addAudioTask(Runnable task); - - public void removeAudioTask(Runnable task); - -} diff --git a/src/com/jsyn/apps/AboutJSyn.java b/src/com/jsyn/apps/AboutJSyn.java deleted file mode 100644 index e6c1fbd..0000000 --- a/src/com/jsyn/apps/AboutJSyn.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.apps; - -import java.awt.GridLayout; - -import javax.swing.JApplet; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingConstants; - -import com.jsyn.JSyn; -import com.jsyn.Synthesizer; -import com.jsyn.swing.JAppletFrame; -import com.jsyn.swing.PortControllerFactory; -import com.jsyn.unitgen.LineOut; -import com.jsyn.unitgen.LinearRamp; -import com.jsyn.unitgen.SineOscillator; -import com.jsyn.unitgen.UnitOscillator; - -/** - * Show the version of JSyn and play some sine waves. This program will be run if you double click - * the JSyn jar file. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class AboutJSyn extends JApplet { - private static final long serialVersionUID = -2704222221111608377L; - private Synthesizer synth; - private UnitOscillator osc1; - private UnitOscillator osc2; - private LinearRamp lag; - private LineOut lineOut; - - @Override - public void init() { - synth = JSyn.createSynthesizer(); - - // Add a tone generator. - synth.add(osc1 = new SineOscillator()); - synth.add(osc2 = new SineOscillator()); - // Add a lag to smooth out amplitude changes and avoid pops. - synth.add(lag = new LinearRamp()); - // Add an output mixer. - synth.add(lineOut = new LineOut()); - // Connect the oscillator to the output. - osc1.output.connect(0, lineOut.input, 0); - osc2.output.connect(0, lineOut.input, 1); - - // Arrange the faders in a stack. - setLayout(new GridLayout(0, 1)); - - JPanel infoPanel = new JPanel(); - infoPanel.setLayout(new GridLayout(0, 1)); - infoPanel.add(new JLabel("About: " + synth, SwingConstants.CENTER)); - infoPanel.add(new JLabel("From: http://www.softsynth.com/", SwingConstants.CENTER)); - infoPanel.add(new JLabel("(C) 1997-2011 Mobileer Inc", SwingConstants.CENTER)); - add(infoPanel); - - // Set the minimum, current and maximum values for the port. - lag.output.connect(osc1.amplitude); - lag.output.connect(osc2.amplitude); - lag.input.setup(0.001, 0.5, 1.0); - lag.time.set(0.1); - lag.input.setName("Amplitude"); - add(PortControllerFactory.createExponentialPortSlider(lag.input)); - - osc1.frequency.setup(50.0, 300.0, 3000.0); - osc1.frequency.setName("Frequency (Left)"); - add(PortControllerFactory.createExponentialPortSlider(osc1.frequency)); - osc2.frequency.setup(50.0, 302.0, 3000.0); - osc2.frequency.setName("Frequency (Right)"); - add(PortControllerFactory.createExponentialPortSlider(osc2.frequency)); - validate(); - } - - @Override - public void start() { - // Start synthesizer using default stereo output at 44100 Hz. - synth.start(); - // We only need to start the LineOut. It will pull data from the - // oscillator. - lineOut.start(); - } - - @Override - public void stop() { - synth.stop(); - } - - /* Can be run as either an application or as an applet. */ - public static void main(String args[]) { - AboutJSyn applet = new AboutJSyn(); - JAppletFrame frame = new JAppletFrame("About JSyn", applet); - frame.setSize(440, 300); - frame.setVisible(true); - frame.test(); - } - -} diff --git a/src/com/jsyn/apps/InstrumentTester.java b/src/com/jsyn/apps/InstrumentTester.java deleted file mode 100644 index 6e347cd..0000000 --- a/src/com/jsyn/apps/InstrumentTester.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2012 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.apps; - -import java.awt.BorderLayout; -import java.io.IOException; - -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiMessage; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.Receiver; -import javax.swing.JApplet; - -import com.jsyn.JSyn; -import com.jsyn.Synthesizer; -import com.jsyn.devices.javasound.MidiDeviceTools; -import com.jsyn.instruments.JSynInstrumentLibrary; -import com.jsyn.midi.MessageParser; -import com.jsyn.swing.InstrumentBrowser; -import com.jsyn.swing.JAppletFrame; -import com.jsyn.swing.PresetSelectionListener; -import com.jsyn.swing.SoundTweaker; -import com.jsyn.unitgen.LineOut; -import com.jsyn.unitgen.UnitSource; -import com.jsyn.unitgen.UnitVoice; -import com.jsyn.util.PolyphonicInstrument; -import com.jsyn.util.VoiceDescription; -import com.softsynth.math.AudioMath; -import com.softsynth.shared.time.TimeStamp; - -/** - * Let the user select an instrument using the InstrumentBrowser and play - * them using the ASCII keyboard or with MIDI. - * Sound parameters can be tweaked using faders. - * - * @author Phil Burk (C) 2012 Mobileer Inc - */ -public class InstrumentTester extends JApplet { - private static final long serialVersionUID = -2704222221111608377L; - private Synthesizer synth; - private LineOut lineOut; - private SoundTweaker tweaker; - protected PolyphonicInstrument instrument; - private MyParser messageParser; - - class MyParser extends MessageParser { - - @Override - public void controlChange(int channel, int index, int value) { - } - - @Override - public void noteOff(int channel, int noteNumber, int velocity) { - instrument.noteOff(noteNumber, synth.createTimeStamp()); - } - - @Override - public void noteOn(int channel, int noteNumber, int velocity) { - double frequency = AudioMath.pitchToFrequency(noteNumber); - double amplitude = velocity / (4 * 128.0); - TimeStamp timeStamp = synth.createTimeStamp(); - instrument.noteOn(noteNumber, frequency, amplitude, timeStamp); - } - - } - - // Write a Receiver to get the messages from a Transmitter. - class CustomReceiver implements Receiver { - @Override - public void close() { - System.out.print("Closed."); - } - - @Override - public void send(MidiMessage message, long timeStamp) { - byte[] bytes = message.getMessage(); - messageParser.parse(bytes); - } - } - - public int setupMidiKeyboard() throws MidiUnavailableException, IOException, InterruptedException { - messageParser = new MyParser(); - - int result = 2; - MidiDevice keyboard = MidiDeviceTools.findKeyboard(); - Receiver receiver = new CustomReceiver(); - // Just use default synthesizer. - if (keyboard != null) { - // If you forget to open them you will hear no sound. - keyboard.open(); - // Put the receiver in the transmitter. - // This gives fairly low latency playing. - keyboard.getTransmitter().setReceiver(receiver); - System.out.println("Play MIDI keyboard: " + keyboard.getDeviceInfo().getDescription()); - result = 0; - } else { - System.out.println("Could not find a keyboard."); - } - return result; - } - - @Override - public void init() { - setLayout(new BorderLayout()); - - synth = JSyn.createSynthesizer(); - synth.add(lineOut = new LineOut()); - - InstrumentBrowser browser = new InstrumentBrowser(new JSynInstrumentLibrary()); - browser.addPresetSelectionListener(new PresetSelectionListener() { - - @Override - public void presetSelected(VoiceDescription voiceDescription, int presetIndex) { - UnitVoice[] voices = new UnitVoice[8]; - for (int i = 0; i < voices.length; i++) { - voices[i] = voiceDescription.createUnitVoice(); - } - instrument = new PolyphonicInstrument(voices); - synth.add(instrument); - instrument.usePreset(presetIndex, synth.createTimeStamp()); - String title = voiceDescription.getVoiceClassName() + ": " - + voiceDescription.getPresetNames()[presetIndex]; - useSource(instrument, title); - } - }); - add(browser, BorderLayout.NORTH); - - try { - setupMidiKeyboard(); - } catch (MidiUnavailableException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - validate(); - } - - private void useSource(UnitSource voice, String title) { - - lineOut.input.disconnectAll(0); - lineOut.input.disconnectAll(1); - - // Connect the source to both left and right output. - voice.getOutput().connect(0, lineOut.input, 0); - voice.getOutput().connect(0, lineOut.input, 1); - - if (tweaker != null) { - remove(tweaker); - } - try { - if (synth.isRunning()) { - synth.sleepFor(0.1); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - tweaker = new SoundTweaker(synth, title, voice); - add(tweaker, BorderLayout.CENTER); - validate(); - } - - @Override - public void start() { - // Start synthesizer using default stereo output at 44100 Hz. - synth.start(); - // We only need to start the LineOut. It will pull data from the - // oscillator. - lineOut.start(); - } - - @Override - public void stop() { - synth.stop(); - } - - /* Can be run as either an application or as an applet. */ - public static void main(String args[]) { - InstrumentTester applet = new InstrumentTester(); - JAppletFrame frame = new JAppletFrame("InstrumentTester", applet); - frame.setSize(600, 800); - frame.setVisible(true); - frame.test(); - } - -} diff --git a/src/com/jsyn/data/AudioSample.java b/src/com/jsyn/data/AudioSample.java deleted file mode 100644 index dcbbae5..0000000 --- a/src/com/jsyn/data/AudioSample.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.data; - -import java.util.ArrayList; - -/** - * Base class for FloatSample and ShortSample. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public abstract class AudioSample extends SequentialDataCommon { - protected int numFrames; - protected int channelsPerFrame = 1; - private double frameRate = 44100.0; - private double pitch; - private ArrayList<SampleMarker> markers; - - public abstract void allocate(int numFrames, int channelsPerFrame); - - @Override - public double getRateScaler(int index, double synthesisRate) { - return 1.0; - } - - public double getFrameRate() { - return frameRate; - } - - public void setFrameRate(double f) { - this.frameRate = f; - } - - @Override - public int getNumFrames() { - return numFrames; - } - - @Override - public int getChannelsPerFrame() { - return channelsPerFrame; - } - - public void setChannelsPerFrame(int channelsPerFrame) { - this.channelsPerFrame = channelsPerFrame; - } - - /** - * Set the recorded pitch as a fractional MIDI semitone value where 60 is Middle C. - * - * @param pitch - */ - public void setPitch(double pitch) { - this.pitch = pitch; - } - - public double getPitch() { - return pitch; - } - - public int getMarkerCount() { - if (markers == null) - return 0; - else - return markers.size(); - } - - public SampleMarker getMarker(int index) { - if (markers == null) - return null; - else - return markers.get(index); - } - - /** - * Add a marker that will be stored sorted by position. This is normally used internally by the - * SampleLoader. - * - * @param marker - */ - public void addMarker(SampleMarker marker) { - if (markers == null) - markers = new ArrayList<SampleMarker>(); - int idx = markers.size(); - for (int k = 0; k < markers.size(); k++) { - SampleMarker cue = markers.get(k); - if (cue.position > marker.position) { - idx = k; - break; - } - } - markers.add(idx, marker); - } -} diff --git a/src/com/jsyn/data/DoubleTable.java b/src/com/jsyn/data/DoubleTable.java deleted file mode 100644 index ca64c94..0000000 --- a/src/com/jsyn/data/DoubleTable.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.data; - -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 { - private double[] table; - - public DoubleTable(int numFrames) { - allocate(numFrames); - } - - public DoubleTable(double[] data) { - allocate(data.length); - write(data); - } - - public DoubleTable(ShortSample shortSample) { - if (shortSample.getChannelsPerFrame() != 1) { - throw new ChannelMismatchException("DoubleTable can only be built from mono samples."); - } - short[] buffer = new short[256]; - int framesLeft = shortSample.getNumFrames(); - allocate(framesLeft); - int cursor = 0; - while (framesLeft > 0) { - int numTransfer = framesLeft; - if (numTransfer > buffer.length) { - numTransfer = buffer.length; - } - shortSample.read(cursor, buffer, 0, numTransfer); - write(cursor, buffer, 0, numTransfer); - cursor += numTransfer; - framesLeft -= numTransfer; - } - } - - public void allocate(int numFrames) { - table = new double[numFrames]; - } - - public int length() { - return table.length; - } - - public void write(double[] data) { - write(0, data, 0, data.length); - } - - public void write(int startFrame, short[] data, int startIndex, int numFrames) { - for (int i = 0; i < numFrames; i++) { - table[startFrame + i] = data[startIndex + i] * (1.0 / 32768.0); - } - } - - public void write(int startFrame, double[] data, int startIndex, int numFrames) { - for (int i = 0; i < numFrames; i++) { - table[startFrame + i] = data[startIndex + i]; - } - } - - /** - * 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 - */ - @Override - public double evaluate(double input) { - double interp; - if (input < -1.0) { - interp = table[0]; - } else if (input < 1.0) { - double fractionalIndex = (table.length - 1) * (input - (-1.0)) / 2.0; - // We don't need floor() because fractionalIndex >= 0.0 - int index = (int) fractionalIndex; - double fraction = fractionalIndex - index; - - double s1 = table[index]; - double s2 = table[index + 1]; - interp = ((s2 - s1) * fraction) + s1; - } else { - interp = table[table.length - 1]; - } - return interp; - } -} diff --git a/src/com/jsyn/data/FloatSample.java b/src/com/jsyn/data/FloatSample.java deleted file mode 100644 index 2d8c973..0000000 --- a/src/com/jsyn/data/FloatSample.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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.data; - -import com.jsyn.unitgen.FixedRateMonoReader; -import com.jsyn.unitgen.FixedRateStereoReader; -import com.jsyn.unitgen.VariableRateMonoReader; -import com.jsyn.unitgen.VariableRateStereoReader; -import com.jsyn.util.SampleLoader; - -/** - * Store multi-channel floating point audio data in an interleaved buffer. The values are stored as - * 32-bit floats. You can play samples using one of the readers, for example VariableRateMonoReader. - * - * @author Phil Burk (C) 2010 Mobileer Inc - * @see SampleLoader - * @see FixedRateMonoReader - * @see FixedRateStereoReader - * @see VariableRateMonoReader - * @see VariableRateStereoReader - */ -public class FloatSample extends AudioSample implements Function { - private float[] buffer; - - public FloatSample() { - } - - /** Constructor for mono samples. */ - public FloatSample(int numFrames) { - this(numFrames, 1); - } - - /** Constructor for mono samples with data. */ - public FloatSample(float[] data) { - this(data.length, 1); - write(data); - } - - /** Constructor for multi-channel samples with data. */ - public FloatSample(float[] data, int channelsPerFrame) { - this(data.length / channelsPerFrame, channelsPerFrame); - write(data); - } - - /** - * Create a silent sample with enough memory to hold the audio data. The number of sample - * numbers in the array will be numFrames*channelsPerFrame. - * - * @param numFrames number of sample groups. A stereo frame contains 2 samples. - * @param channelsPerFrame 1 for mono, 2 for stereo - */ - public FloatSample(int numFrames, int channelsPerFrame) { - allocate(numFrames, channelsPerFrame); - } - - /** - * Allocate memory to hold the audio data. The number of sample numbers in the array will be - * numFrames*channelsPerFrame. - * - * @param numFrames number of sample groups. A stereo frame contains 2 samples. - * @param channelsPerFrame 1 for mono, 2 for stereo - */ - @Override - public void allocate(int numFrames, int channelsPerFrame) { - buffer = new float[numFrames * channelsPerFrame]; - this.numFrames = numFrames; - this.channelsPerFrame = channelsPerFrame; - } - - /** - * Note that in a stereo sample, a frame has two values. - * - * @param startFrame index of frame in the sample - * @param data data to be written - * @param startIndex index of first value in array - * @param numFrames - */ - public void write(int startFrame, float[] data, int startIndex, int numFrames) { - int numSamplesToWrite = numFrames * channelsPerFrame; - int firstSampleIndexToWrite = startFrame * channelsPerFrame; - System.arraycopy(data, startIndex, buffer, firstSampleIndexToWrite, numSamplesToWrite); - } - - /** - * Note that in a stereo sample, a frame has two values. - * - * @param startFrame index of frame in the sample - * @param data array to receive the data from the sample - * @param startIndex index of first location in array to start filling - * @param numFrames - */ - public void read(int startFrame, float[] data, int startIndex, int numFrames) { - int numSamplesToRead = numFrames * channelsPerFrame; - int firstSampleIndexToRead = startFrame * channelsPerFrame; - System.arraycopy(buffer, firstSampleIndexToRead, data, startIndex, numSamplesToRead); - } - - /** - * Write the entire array to the sample. The sample data must have already been allocated with - * enough room to contain the data. - * - * @param data - */ - public void write(float[] data) { - write(0, data, 0, data.length / getChannelsPerFrame()); - } - - public void read(float[] data) { - read(0, data, 0, data.length / getChannelsPerFrame()); - } - - @Override - public double readDouble(int index) { - return buffer[index]; - } - - @Override - public void writeDouble(int index, double value) { - buffer[index] = (float) value; - } - - /** - * Interpolate between two adjacent samples. - * Note that this will only work for mono, single channel samples. - * - * @param fractionalIndex must be >=0 and < (size-1) - */ - public double interpolate(double fractionalIndex) { - int index = (int) fractionalIndex; - float phase = (float) (fractionalIndex - index); - float source = buffer[index]; - float target = buffer[index + 1]; - return ((target - source) * phase) + source; - } - - /** - * Note that this will only work for mono, single channel samples. - */ - @Override - public double evaluate(double input) { - // Input ranges from -1 to +1 - // Map it to range of sample with guard point. - double normalizedInput = (input + 1.0) * 0.5; - // Clip so it does not go out of range of the sample. - if (normalizedInput < 0.0) normalizedInput = 0.0; - else if (normalizedInput > 1.0) normalizedInput = 1.0; - double fractionalIndex = (getNumFrames() - 1.01) * normalizedInput; - return interpolate(fractionalIndex); - } -} diff --git a/src/com/jsyn/data/Function.java b/src/com/jsyn/data/Function.java deleted file mode 100644 index c0e6566..0000000 --- a/src/com/jsyn/data/Function.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.data; - -import com.jsyn.unitgen.FunctionEvaluator; -import com.jsyn.unitgen.FunctionOscillator; - -/** - * @author Phil Burk (C) 2010 Mobileer Inc - * @see FunctionEvaluator - * @see FunctionOscillator - */ -public interface Function { - /** - * Convert an input value to an output value. - * - * @param input - * @return generated value - */ - public double evaluate(double input); -} diff --git a/src/com/jsyn/data/HammingWindow.java b/src/com/jsyn/data/HammingWindow.java deleted file mode 100644 index d8e1238..0000000 --- a/src/com/jsyn/data/HammingWindow.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2009 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.data; - -public class HammingWindow implements SpectralWindow { - private double[] data; - - /** Construct a generalized Hamming Window */ - public HammingWindow(int length, double alpha, double beta) { - data = new double[length]; - double scaler = 2.0 * Math.PI / (length - 1); - for (int i = 0; i < length; i++) { - data[i] = alpha - (beta * (Math.cos(i * scaler))); - } - } - - /** Traditional Hamming Window with alpha = 25/46 and beta = 21/46 */ - public HammingWindow(int length) { - this(length, 25.0 / 46.0, 21.0 / 46.0); - } - - @Override - public double get(int index) { - return data[index]; - } - -} diff --git a/src/com/jsyn/data/HannWindow.java b/src/com/jsyn/data/HannWindow.java deleted file mode 100644 index 878d07c..0000000 --- a/src/com/jsyn/data/HannWindow.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013 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.data; - -import com.jsyn.unitgen.SpectralFFT; -import com.jsyn.unitgen.SpectralIFFT; - -/** - * A HammingWindow with alpha and beta = 0.5. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @see SpectralWindow - * @see SpectralFFT - * @see SpectralIFFT - */ -public class HannWindow extends HammingWindow { - - public HannWindow(int length) { - super(length, 0.5, 0.5); - } - -} diff --git a/src/com/jsyn/data/SampleMarker.java b/src/com/jsyn/data/SampleMarker.java deleted file mode 100644 index d3db1d4..0000000 --- a/src/com/jsyn/data/SampleMarker.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2012 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.data; - -/** - * A marker for an audio sample. - * - * @author (C) 2012 Phil Burk, Mobileer Inc - */ - -public class SampleMarker { - /** Sample frame index. */ - public int position; - public String name; - public String comment; -} diff --git a/src/com/jsyn/data/SegmentedEnvelope.java b/src/com/jsyn/data/SegmentedEnvelope.java deleted file mode 100644 index efdfd89..0000000 --- a/src/com/jsyn/data/SegmentedEnvelope.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.data; - -import com.jsyn.unitgen.EnvelopeDAHDSR; -import com.jsyn.unitgen.VariableRateMonoReader; - -/** - * Store an envelope as a series of line segments. Each line is described as a duration and a target - * value. The envelope can be played using a {@link VariableRateMonoReader}. Here is an example that - * generates an envelope that looks like a traditional ADSR envelope. - * - * <pre> - * <code> - * // Create an amplitude envelope and fill it with data. - * double[] ampData = { - * 0.02, 0.9, // duration,value pair 0, "attack" - * 0.10, 0.5, // pair 1, "decay" - * 0.50, 0.0 // pair 2, "release" - * }; - * SegmentedEnvelope ampEnvelope = new SegmentedEnvelope( ampData ); - * - * // Hang at end of decay segment to provide a "sustain" segment. - * ampEnvelope.setSustainBegin( 1 ); - * ampEnvelope.setSustainEnd( 1 ); - * - * // Play the envelope using queueOn so that it uses the sustain and release information. - * synth.add( ampEnv = new VariableRateMonoReader() ); - * ampEnv.dataQueue.queueOn( ampEnvelope ); - * </code> - * </pre> - * - * As an alternative you could use an {@link EnvelopeDAHDSR}. - * - * @author Phil Burk (C) 2010 Mobileer Inc - * @see VariableRateMonoReader - * @see EnvelopeDAHDSR - */ -public class SegmentedEnvelope extends SequentialDataCommon { - private double[] buffer; - - public SegmentedEnvelope(int maxFrames) { - allocate(maxFrames); - } - - public SegmentedEnvelope(double[] pairs) { - this(pairs.length / 2); - write(pairs); - } - - public void allocate(int maxFrames) { - buffer = new double[maxFrames * 2]; - this.maxFrames = maxFrames; - this.numFrames = 0; - } - - /** - * Write frames of envelope data. A frame consists of a duration and a value. - * - * @param startFrame Index of frame in envelope to write to. - * @param data Pairs of duration and value. - * @param startIndex Index of frame in data[] to read from. - * @param numToWrite Number of frames (pairs) to write. - */ - public void write(int startFrame, double[] data, int startIndex, int numToWrite) { - System.arraycopy(data, startIndex * 2, buffer, startFrame * 2, numToWrite * 2); - if ((startFrame + numToWrite) > numFrames) { - numFrames = startFrame + numToWrite; - } - } - - public void read(int startFrame, double[] data, int startIndex, int numToRead) { - System.arraycopy(buffer, startFrame * 2, data, startIndex * 2, numToRead * 2); - } - - public void write(double[] data) { - write(0, data, 0, data.length / 2); - } - - public void read(double[] data) { - read(0, data, 0, data.length / 2); - } - - /** Read the value of an envelope, not the duration. */ - @Override - public double readDouble(int index) { - return buffer[(index * 2) + 1]; - } - - @Override - public void writeDouble(int index, double value) { - buffer[(index * 2) + 1] = value; - if ((index + 1) > numFrames) { - numFrames = index + 1; - } - } - - @Override - public double getRateScaler(int index, double synthesisPeriod) { - double duration = buffer[index * 2]; - if (duration < synthesisPeriod) { - duration = synthesisPeriod; - } - return 1.0 / duration; - } - - @Override - public int getChannelsPerFrame() { - return 1; - } -} diff --git a/src/com/jsyn/data/SequentialData.java b/src/com/jsyn/data/SequentialData.java deleted file mode 100644 index 0deb5c9..0000000 --- a/src/com/jsyn/data/SequentialData.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.data; - -import com.jsyn.unitgen.FixedRateMonoReader; -import com.jsyn.unitgen.FixedRateMonoWriter; -import com.jsyn.unitgen.FixedRateStereoReader; -import com.jsyn.unitgen.FixedRateStereoWriter; -import com.jsyn.unitgen.VariableRateMonoReader; -import com.jsyn.unitgen.VariableRateStereoReader; - -/** - * Interface for objects that can be read and/or written by index. The index is not stored - * internally so they can be shared by multiple readers. - * - * @author Phil Burk (C) 2010 Mobileer Inc - * @see FixedRateMonoReader - * @see FixedRateStereoReader - * @see FixedRateMonoWriter - * @see FixedRateStereoWriter - * @see VariableRateMonoReader - * @see VariableRateStereoReader - */ -public interface SequentialData { - /** - * Write a value at the given index. - * - * @param index sample index is ((frameIndex * channelsPerFrame) + channelIndex) - * @param value the value to be written - */ - void writeDouble(int index, double value); - - /** - * Read a value from the sample independently from the internal storage format. - * - * @param index sample index is ((frameIndex * channelsPerFrame) + channelIndex) - */ - - double readDouble(int index); - - /*** - * @return Beginning of sustain loop or -1 if no loop. - */ - public int getSustainBegin(); - - /** - * SustainEnd value is the frame index of the frame just past the end of the loop. The number of - * frames included in the loop is (SustainEnd - SustainBegin). - * - * @return End of sustain loop or -1 if no loop. - */ - public int getSustainEnd(); - - /*** - * @return Beginning of release loop or -1 if no loop. - */ - public int getReleaseBegin(); - - /*** - * @return End of release loop or -1 if no loop. - */ - public int getReleaseEnd(); - - /** - * Get rate to play the data. In an envelope this correspond to the inverse of the frame - * duration and would vary frame to frame. For an audio sample it is 1.0. - * - * @param index - * @param synthesisRate - * @return rate to scale the playback speed. - */ - double getRateScaler(int index, double synthesisRate); - - /** - * @return For a stereo sample, return 2. - */ - int getChannelsPerFrame(); - - /** - * @return The number of valid frames that can be read. - */ - int getNumFrames(); -} diff --git a/src/com/jsyn/data/SequentialDataCommon.java b/src/com/jsyn/data/SequentialDataCommon.java deleted file mode 100644 index 5cc51df..0000000 --- a/src/com/jsyn/data/SequentialDataCommon.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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.data; - -/** - * Abstract base class for envelopes and samples that adds sustain and release loops. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public abstract class SequentialDataCommon implements SequentialData { - protected int numFrames; - protected int maxFrames; - private int sustainBegin = -1; - private int sustainEnd = -1; - private int releaseBegin = -1; - private int releaseEnd = -1; - - @Override - public abstract void writeDouble(int index, double value); - - @Override - public abstract double readDouble(int index); - - @Override - public abstract double getRateScaler(int index, double synthesisRate); - - @Override - public abstract int getChannelsPerFrame(); - - /** - * @return Maximum number of frames of data. - */ - public int getMaxFrames() { - return maxFrames; - } - - /** - * Set number of frames of data. Input will be clipped to maxFrames. This is useful when - * changing the contents of a sample or envelope. - */ - public void setNumFrames(int numFrames) { - if (numFrames > maxFrames) - numFrames = maxFrames; - this.numFrames = numFrames; - } - - @Override - public int getNumFrames() { - return numFrames; - } - - // JavaDocs will be copied from SequentialData - - @Override - public int getSustainBegin() { - return this.sustainBegin; - } - - @Override - public int getSustainEnd() { - return this.sustainEnd; - } - - @Override - public int getReleaseBegin() { - return this.releaseBegin; - } - - @Override - public int getReleaseEnd() { - return this.releaseEnd; - } - - /** - * Set beginning of a sustain loop. When UnitDataQueuePort.queueOn() is called, - * if the loop is set then the attack portion will be queued followed by this sustain - * region using queueLoop(). - * The number of frames in the loop will be (SustainEnd - SustainBegin). - * <p> - * For a steady sustain level, like in an ADSR envelope, set SustainBegin and - * SustainEnd to the same frame. - * <p> - * For a sustain that is modulated, include two or more frames in the loop. - * - * @param sustainBegin - */ - public void setSustainBegin(int sustainBegin) { - this.sustainBegin = sustainBegin; - } - - /** - * SustainEnd value is the frame index of the frame just past the end of the loop. - * The number of frames included in the loop is (SustainEnd - SustainBegin). - * - * @param sustainEnd - */ - public void setSustainEnd(int sustainEnd) { - this.sustainEnd = sustainEnd; - } - - /** - * The release loop behaves like the sustain loop but it is triggered - * by UnitDataQueuePort.queueOff(). - * - * @param releaseBegin - */ - public void setReleaseBegin(int releaseBegin) { - this.releaseBegin = releaseBegin; - } - - /** - * ReleaseEnd value is the frame index of the frame just past the end of the loop. - * The number of frames included in the loop is (ReleaseEnd - ReleaseBegin). - * - * @param releaseEnd - */ - - public void setReleaseEnd(int releaseEnd) { - this.releaseEnd = releaseEnd; - } - -} diff --git a/src/com/jsyn/data/ShortSample.java b/src/com/jsyn/data/ShortSample.java deleted file mode 100644 index 4a4110e..0000000 --- a/src/com/jsyn/data/ShortSample.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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.data; - -import com.jsyn.engine.SynthesisEngine; -import com.jsyn.unitgen.FixedRateMonoReader; -import com.jsyn.unitgen.FixedRateStereoReader; -import com.jsyn.unitgen.VariableRateMonoReader; -import com.jsyn.unitgen.VariableRateStereoReader; -import com.jsyn.util.SampleLoader; - -/** - * Store multi-channel short audio data in an interleaved buffer. - * - * @author Phil Burk (C) 2010 Mobileer Inc - * @see SampleLoader - * @see FixedRateMonoReader - * @see FixedRateStereoReader - * @see VariableRateMonoReader - * @see VariableRateStereoReader - */ -public class ShortSample extends AudioSample { - private short[] buffer; - - public ShortSample() { - } - - public ShortSample(int numFrames, int channelsPerFrame) { - allocate(numFrames, channelsPerFrame); - } - - /** Constructor for mono samples with data. */ - public ShortSample(short[] data) { - this(data.length, 1); - write(data); - } - - /** Constructor for multi-channel samples with data. */ - public ShortSample(short[] data, int channelsPerFrame) { - this(data.length / channelsPerFrame, channelsPerFrame); - write(data); - } - - @Override - public void allocate(int numFrames, int channelsPerFrame) { - buffer = new short[numFrames * channelsPerFrame]; - this.numFrames = numFrames; - this.channelsPerFrame = channelsPerFrame; - } - - /** - * Note that in a stereo sample, a frame has two values. - * - * @param startFrame index of frame in the sample - * @param data data to be written - * @param startIndex index of first value in array - * @param numFrames - */ - public void write(int startFrame, short[] data, int startIndex, int numFrames) { - int numSamplesToWrite = numFrames * channelsPerFrame; - int firstSampleIndexToWrite = startFrame * channelsPerFrame; - System.arraycopy(data, startIndex, buffer, firstSampleIndexToWrite, numSamplesToWrite); - } - - /** - * Note that in a stereo sample, a frame has two values. - * - * @param startFrame index of frame in the sample - * @param data array to receive the data from the sample - * @param startIndex index of first location in array to start filling - * @param numFrames - */ - public void read(int startFrame, short[] data, int startIndex, int numFrames) { - int numSamplesToRead = numFrames * channelsPerFrame; - int firstSampleIndexToRead = startFrame * channelsPerFrame; - System.arraycopy(buffer, firstSampleIndexToRead, data, startIndex, numSamplesToRead); - } - - public void write(short[] data) { - write(0, data, 0, data.length); - } - - public void read(short[] data) { - read(0, data, 0, data.length); - } - - public short readShort(int index) { - return buffer[index]; - } - - public void writeShort(int index, short value) { - buffer[index] = value; - } - - /** Read a sample converted to a double in the range -1.0 to almost 1.0. */ - @Override - public double readDouble(int index) { - return SynthesisEngine.convertShortToDouble(buffer[index]); - } - - /** - * Write a double that will be clipped to the range -1.0 to almost 1.0 and converted to a short. - */ - @Override - public void writeDouble(int index, double value) { - buffer[index] = SynthesisEngine.convertDoubleToShort(value); - } - -} diff --git a/src/com/jsyn/data/SpectralWindow.java b/src/com/jsyn/data/SpectralWindow.java deleted file mode 100644 index 0fcfac4..0000000 --- a/src/com/jsyn/data/SpectralWindow.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2009 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.data; - -public interface SpectralWindow { - public double get(int index); -} diff --git a/src/com/jsyn/data/SpectralWindowFactory.java b/src/com/jsyn/data/SpectralWindowFactory.java deleted file mode 100644 index 01cced6..0000000 --- a/src/com/jsyn/data/SpectralWindowFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013 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.data; - -import com.jsyn.unitgen.SpectralFFT; -import com.jsyn.unitgen.SpectralFilter; -import com.jsyn.unitgen.SpectralIFFT; - -/** - * Create shared windows as needed for use with FFTs and IFFTs. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @see SpectralWindow - * @see SpectralFFT - * @see SpectralIFFT - * @see SpectralFilter - */ -public class SpectralWindowFactory { - private static final int NUM_WINDOWS = 16; - private static final int MIN_SIZE_LOG_2 = 2; - private static HammingWindow[] hammingWindows = new HammingWindow[NUM_WINDOWS]; - private static HannWindow[] hannWindows = new HannWindow[NUM_WINDOWS]; - - /** @return a shared standard HammingWindow */ - public static HammingWindow getHammingWindow(int sizeLog2) { - int index = sizeLog2 - MIN_SIZE_LOG_2; - if (hammingWindows[index] == null) { - hammingWindows[index] = new HammingWindow(1 << sizeLog2); - } - return hammingWindows[index]; - } - - /** @return a shared HannWindow */ - public static HannWindow getHannWindow(int sizeLog2) { - int index = sizeLog2 - MIN_SIZE_LOG_2; - if (hannWindows[index] == null) { - hannWindows[index] = new HannWindow(1 << sizeLog2); - } - return hannWindows[index]; - } -} diff --git a/src/com/jsyn/data/Spectrum.java b/src/com/jsyn/data/Spectrum.java deleted file mode 100644 index 66e4ee4..0000000 --- a/src/com/jsyn/data/Spectrum.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013 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.data; - -import com.jsyn.unitgen.SpectralFFT; -import com.jsyn.unitgen.SpectralIFFT; -import com.jsyn.unitgen.SpectralProcessor; - -/** - * Complex spectrum with real and imaginary parts. The frequency associated with each bin of the - * spectrum is: - * - * <pre> - * frequency = binIndex * sampleRate / size - * </pre> - * - * Note that the upper half of the spectrum is above the Nyquist frequency. Those frequencies are - * mirrored around the Nyquist frequency. Note that this spectral API is experimental and may change - * at any time. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @version 016 - * @see SpectralFFT - * @see SpectralIFFT - * @see SpectralProcessor - */ -public class Spectrum { - private double[] real; - private double[] imaginary; - public static final int DEFAULT_SIZE_LOG_2 = 9; - public static final int DEFAULT_SIZE = 1 << DEFAULT_SIZE_LOG_2; - - public Spectrum() { - this(DEFAULT_SIZE); - } - - public Spectrum(int size) { - setSize(size); - } - - public double[] getReal() { - return real; - } - - public double[] getImaginary() { - return imaginary; - } - - /** - * If you change the size of the spectrum then the real and imaginary arrays will be - * reallocated. - * - * @param size - */ - public void setSize(int size) { - if ((real == null) || (real.length != size)) { - real = new double[size]; - imaginary = new double[size]; - } - } - - public int size() { - return real.length; - } - - /** - * Copy this spectrum to another spectrum of the same length. - * - * @param destination - */ - public void copyTo(Spectrum destination) { - assert (size() == destination.size()); - System.arraycopy(real, 0, destination.real, 0, real.length); - System.arraycopy(imaginary, 0, destination.imaginary, 0, imaginary.length); - } - - public void clear() { - for (int i = 0; i < real.length; i++) { - real[i] = 0.0; - imaginary[i] = 0.0; - } - } -} diff --git a/src/com/jsyn/devices/AudioDeviceFactory.java b/src/com/jsyn/devices/AudioDeviceFactory.java deleted file mode 100644 index 612c81d..0000000 --- a/src/com/jsyn/devices/AudioDeviceFactory.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.devices; - -import com.jsyn.util.JavaTools; - -/** - * Create a device appropriate for the platform. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class AudioDeviceFactory { - private static AudioDeviceManager instance; - - /** - * Use a custom device interface. Overrides the selection of a default device manager. - * - * @param instance - */ - public static void setInstance(AudioDeviceManager instance) { - AudioDeviceFactory.instance = instance; - } - - /** - * Try to load JPortAudio or JavaSound devices. - * - * @return A device supported on this platform. - */ - public static AudioDeviceManager createAudioDeviceManager() { - return createAudioDeviceManager(false); - } - - /** - * Try to load JPortAudio or JavaSound devices. - * - * @param preferJavaSound if true then try to create a JavaSound manager before other types. - * @return A device supported on this platform. - */ - public static AudioDeviceManager createAudioDeviceManager(boolean preferJavaSound) { - if (preferJavaSound) { - tryJavaSound(); - tryJPortAudio(); - } else { - tryJPortAudio(); - tryJavaSound(); - } - return instance; - } - - private static void tryJavaSound() { - if (instance == null) { - try { - @SuppressWarnings("unchecked") - Class<AudioDeviceManager> clazz = JavaTools.loadClass( - "com.jsyn.devices.javasound.JavaSoundAudioDevice", false); - if (clazz != null) { - instance = clazz.newInstance(); - } - } catch (Throwable e) { - System.err.println("Could not load JavaSound device. " + e); - } - } - } - - private static void tryJPortAudio() { - if (instance == null) { - try { - if (JavaTools.loadClass("com.portaudio.PortAudio", false) != null) { - instance = (AudioDeviceManager) JavaTools.loadClass( - "com.jsyn.devices.jportaudio.JPortAudioDevice").newInstance(); - } - - } catch (Throwable e) { - System.err.println("Could not load JPortAudio device. " + e); - } - } - } - -} diff --git a/src/com/jsyn/devices/AudioDeviceInputStream.java b/src/com/jsyn/devices/AudioDeviceInputStream.java deleted file mode 100644 index a3d1854..0000000 --- a/src/com/jsyn/devices/AudioDeviceInputStream.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2009 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.devices; - -import com.jsyn.io.AudioInputStream; - -public interface AudioDeviceInputStream extends AudioInputStream { - /** Start the input device. */ - public void start(); - - public void stop(); - - /** - * @return Estimated latency in seconds. - */ - public double getLatency(); -} diff --git a/src/com/jsyn/devices/AudioDeviceManager.java b/src/com/jsyn/devices/AudioDeviceManager.java deleted file mode 100644 index ac8d47c..0000000 --- a/src/com/jsyn/devices/AudioDeviceManager.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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.devices; - -/** - * Interface for an audio system. This may be implemented using JavaSound, or a native device - * wrapper. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public interface AudioDeviceManager { - /** - * Pass this value to the start method to request the default device ID. - */ - public final static int USE_DEFAULT_DEVICE = -1; - - /** - * @return The number of devices available. - */ - public int getDeviceCount(); - - /** - * Get the name of an audio device. - * - * @param deviceID An index between 0 to deviceCount-1. - * @return A name that can be shown to the user. - */ - public String getDeviceName(int deviceID); - - /** - * @return A name of the device manager that can be shown to the user. - */ - public String getName(); - - /** - * The user can generally select a default device using a control panel that is part of the - * operating system. - * - * @return The ID for the input device that the user has selected as the default. - */ - public int getDefaultInputDeviceID(); - - /** - * The user can generally select a default device using a control panel that is part of the - * operating system. - * - * @return The ID for the output device that the user has selected as the default. - */ - public int getDefaultOutputDeviceID(); - - /** - * @param deviceID - * @return The maximum number of channels that the device will support. - */ - public int getMaxInputChannels(int deviceID); - - /** - * @param deviceID An index between 0 to numDevices-1. - * @return The maximum number of channels that the device will support. - */ - public int getMaxOutputChannels(int deviceID); - - /** - * This the lowest latency that the device can support reliably. It should be used for - * applications that require low latency such as live processing of guitar signals. - * - * @param deviceID An index between 0 to numDevices-1. - * @return Latency in seconds. - */ - public double getDefaultLowInputLatency(int deviceID); - - /** - * This the highest latency that the device can support. High latency is recommended for - * applications that are not time critical, such as recording. - * - * @param deviceID An index between 0 to numDevices-1. - * @return Latency in seconds. - */ - public double getDefaultHighInputLatency(int deviceID); - - public double getDefaultLowOutputLatency(int deviceID); - - public double getDefaultHighOutputLatency(int deviceID); - - /** - * Set latency in seconds for the audio device. If set to zero then the DefaultLowLatency value - * for the device will be used. This is just a suggestion that will be used when the - * AudioDeviceInputStream is started. - **/ - public int setSuggestedInputLatency(double latency); - - public int setSuggestedOutputLatency(double latency); - - /** - * Create a stream that can be used internally by JSyn for outputting audio data. Applications - * should not call this directly. - */ - AudioDeviceOutputStream createOutputStream(int deviceID, int frameRate, int numOutputChannels); - - /** - * Create a stream that can be used internally by JSyn for acquiring audio input data. - * Applications should not call this directly. - */ - AudioDeviceInputStream createInputStream(int deviceID, int frameRate, int numInputChannels); - -} diff --git a/src/com/jsyn/devices/AudioDeviceOutputStream.java b/src/com/jsyn/devices/AudioDeviceOutputStream.java deleted file mode 100644 index 5c17efb..0000000 --- a/src/com/jsyn/devices/AudioDeviceOutputStream.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2009 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.devices; - -import com.jsyn.io.AudioOutputStream; - -public interface AudioDeviceOutputStream extends AudioOutputStream { - public void start(); - - public void stop(); - - /** - * @return Estimated latency in seconds. - */ - public double getLatency(); -} diff --git a/src/com/jsyn/devices/javasound/JavaSoundAudioDevice.java b/src/com/jsyn/devices/javasound/JavaSoundAudioDevice.java deleted file mode 100644 index 656dc1c..0000000 --- a/src/com/jsyn/devices/javasound/JavaSoundAudioDevice.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright 2009 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.devices.javasound; - -import java.util.ArrayList; -import java.util.logging.Logger; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.TargetDataLine; - -import com.jsyn.devices.AudioDeviceInputStream; -import com.jsyn.devices.AudioDeviceManager; -import com.jsyn.devices.AudioDeviceOutputStream; - -/** - * Use JavaSound to access the audio hardware. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class JavaSoundAudioDevice implements AudioDeviceManager { - private static final int BYTES_PER_SAMPLE = 2; - private static final boolean USE_BIG_ENDIAN = false; - - ArrayList<DeviceInfo> deviceRecords; - private double suggestedOutputLatency = 0.040; - private double suggestedInputLatency = 0.100; - private int defaultInputDeviceID = -1; - private int defaultOutputDeviceID = -1; - - static Logger logger = Logger.getLogger(JavaSoundAudioDevice.class.getName()); - - public JavaSoundAudioDevice() { - String osName = System.getProperty("os.name"); - if (osName.contains("Windows")) { - suggestedOutputLatency = 0.08; - logger.info("JSyn: default output latency set to " - + ((int) (suggestedOutputLatency * 1000)) + " msec for " + osName); - } - deviceRecords = new ArrayList<DeviceInfo>(); - sniffAvailableMixers(); - dumpAvailableMixers(); - } - - private void dumpAvailableMixers() { - for (DeviceInfo deviceInfo : deviceRecords) { - logger.fine("" + deviceInfo); - } - } - - /** - * Build device info and determine default devices. - */ - private void sniffAvailableMixers() { - Mixer.Info[] mixers = AudioSystem.getMixerInfo(); - for (int i = 0; i < mixers.length; i++) { - DeviceInfo deviceInfo = new DeviceInfo(); - - deviceInfo.name = mixers[i].getName(); - Mixer mixer = AudioSystem.getMixer(mixers[i]); - - Line.Info[] lines = mixer.getTargetLineInfo(); - deviceInfo.maxInputs = scanMaxChannels(lines); - // Remember first device that supports input. - if ((defaultInputDeviceID < 0) && (deviceInfo.maxInputs > 0)) { - defaultInputDeviceID = i; - } - - lines = mixer.getSourceLineInfo(); - deviceInfo.maxOutputs = scanMaxChannels(lines); - // Remember first device that supports output. - if ((defaultOutputDeviceID < 0) && (deviceInfo.maxOutputs > 0)) { - defaultOutputDeviceID = i; - } - - deviceRecords.add(deviceInfo); - } - } - - private int scanMaxChannels(Line.Info[] lines) { - int maxChannels = 0; - for (Line.Info line : lines) { - if (line instanceof DataLine.Info) { - int numChannels = scanMaxChannels(((DataLine.Info) line)); - if (numChannels > maxChannels) { - maxChannels = numChannels; - } - } - } - return maxChannels; - } - - private int scanMaxChannels(DataLine.Info info) { - int maxChannels = 0; - for (AudioFormat format : info.getFormats()) { - int numChannels = format.getChannels(); - if (numChannels > maxChannels) { - maxChannels = numChannels; - } - } - return maxChannels; - } - - class DeviceInfo { - String name; - int maxInputs; - int maxOutputs; - - @Override - public String toString() { - return "AudioDevice: " + name + ", max in = " + maxInputs + ", max out = " + maxOutputs; - } - } - - private class JavaSoundStream { - AudioFormat format; - byte[] bytes; - int frameRate; - int deviceID; - int samplesPerFrame; - - public JavaSoundStream(int deviceID, int frameRate, int samplesPerFrame) { - this.deviceID = deviceID; - this.frameRate = frameRate; - this.samplesPerFrame = samplesPerFrame; - format = new AudioFormat(frameRate, 16, samplesPerFrame, true, USE_BIG_ENDIAN); - } - - Line getDataLine(DataLine.Info info) throws LineUnavailableException { - Line dataLine; - if (deviceID >= 0) { - Mixer.Info[] mixers = AudioSystem.getMixerInfo(); - Mixer mixer = AudioSystem.getMixer(mixers[deviceID]); - dataLine = mixer.getLine(info); - } else { - dataLine = AudioSystem.getLine(info); - } - return dataLine; - } - - int calculateBufferSize(double suggestedOutputLatency) { - int numFrames = (int) (suggestedOutputLatency * frameRate); - int numBytes = numFrames * samplesPerFrame * BYTES_PER_SAMPLE; - return numBytes; - } - - } - - private class JavaSoundOutputStream extends JavaSoundStream implements AudioDeviceOutputStream { - SourceDataLine line; - - public JavaSoundOutputStream(int deviceID, int frameRate, int samplesPerFrame) { - super(deviceID, frameRate, samplesPerFrame); - } - - @Override - public void start() { - DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); - if (!AudioSystem.isLineSupported(info)) { - // Handle the error. - logger.severe("JavaSoundOutputStream - not supported." + format); - } else { - try { - line = (SourceDataLine) getDataLine(info); - int bufferSize = calculateBufferSize(suggestedOutputLatency); - line.open(format, bufferSize); - logger.fine("Output buffer size = " + bufferSize + " bytes."); - line.start(); - - } catch (Exception e) { - e.printStackTrace(); - line = null; - } - } - } - - /** Grossly inefficient. Call the array version instead. */ - @Override - public void write(double value) { - double[] buffer = new double[1]; - buffer[0] = value; - write(buffer, 0, 1); - } - - @Override - public void write(double[] buffer) { - write(buffer, 0, buffer.length); - } - - @Override - public void write(double[] buffer, int start, int count) { - // Allocate byte buffer if needed. - if ((bytes == null) || ((bytes.length * 2) < count)) { - bytes = new byte[count * 2]; - } - - // Convert float samples to LittleEndian bytes. - int byteIndex = 0; - for (int i = 0; i < count; i++) { - // Offset before casting so that we can avoid using floor(). - // Also round by adding 0.5 so that very small signals go to zero. - double temp = (32767.0 * buffer[i + start]) + 32768.5; - int sample = ((int) temp) - 32768; - if (sample > Short.MAX_VALUE) { - sample = Short.MAX_VALUE; - } else if (sample < Short.MIN_VALUE) { - sample = Short.MIN_VALUE; - } - bytes[byteIndex++] = (byte) sample; // little end - bytes[byteIndex++] = (byte) (sample >> 8); // big end - } - - line.write(bytes, 0, byteIndex); - } - - @Override - public void stop() { - if (line != null) { - line.stop(); - line.flush(); - line.close(); - line = null; - } else { - new RuntimeException("AudioOutput stop attempted when no line created.") - .printStackTrace(); - } - } - - @Override - public double getLatency() { - if (line == null) { - return 0.0; - } - int numBytes = line.getBufferSize(); - int numFrames = numBytes / (BYTES_PER_SAMPLE * samplesPerFrame); - return ((double) numFrames) / frameRate; - } - - @Override - public void close() { - } - - } - - private class JavaSoundInputStream extends JavaSoundStream implements AudioDeviceInputStream { - TargetDataLine line; - - public JavaSoundInputStream(int deviceID, int frameRate, int samplesPerFrame) { - super(deviceID, frameRate, samplesPerFrame); - } - - @Override - public void start() { - DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); - if (!AudioSystem.isLineSupported(info)) { - // Handle the error. - logger.severe("JavaSoundInputStream - not supported." + format); - } else { - try { - line = (TargetDataLine) getDataLine(info); - int bufferSize = calculateBufferSize(suggestedInputLatency); - line.open(format, bufferSize); - logger.fine("Input buffer size = " + bufferSize + " bytes."); - line.start(); - } catch (Exception e) { - e.printStackTrace(); - line = null; - } - } - } - - @Override - public double read() { - double[] buffer = new double[1]; - read(buffer, 0, 1); - return buffer[0]; - } - - @Override - public int read(double[] buffer) { - return read(buffer, 0, buffer.length); - } - - @Override - public int read(double[] buffer, int start, int count) { - // Allocate byte buffer if needed. - if ((bytes == null) || ((bytes.length * 2) < count)) { - bytes = new byte[count * 2]; - } - int bytesRead = line.read(bytes, 0, bytes.length); - - // Convert BigEndian bytes to float samples - int bi = 0; - for (int i = 0; i < count; i++) { - int sample = bytes[bi++] & 0x00FF; // little end - sample = sample + (bytes[bi++] << 8); // big end - buffer[i + start] = sample * (1.0 / 32767.0); - } - return bytesRead / 4; - } - - @Override - public void stop() { - if (line != null) { - line.drain(); - line.close(); - } else { - new RuntimeException("AudioInput stop attempted when no line created.") - .printStackTrace(); - } - } - - @Override - public double getLatency() { - if (line == null) { - return 0.0; - } - int numBytes = line.getBufferSize(); - int numFrames = numBytes / (BYTES_PER_SAMPLE * samplesPerFrame); - return ((double) numFrames) / frameRate; - } - - @Override - public int available() { - return line.available() / BYTES_PER_SAMPLE; - } - - @Override - public void close() { - } - - } - - @Override - public AudioDeviceOutputStream createOutputStream(int deviceID, int frameRate, - int samplesPerFrame) { - return new JavaSoundOutputStream(deviceID, frameRate, samplesPerFrame); - } - - @Override - public AudioDeviceInputStream createInputStream(int deviceID, int frameRate, int samplesPerFrame) { - return new JavaSoundInputStream(deviceID, frameRate, samplesPerFrame); - } - - @Override - public double getDefaultHighInputLatency(int deviceID) { - return 0.300; - } - - @Override - public double getDefaultHighOutputLatency(int deviceID) { - return 0.300; - } - - @Override - public int getDefaultInputDeviceID() { - return defaultInputDeviceID; - } - - @Override - public int getDefaultOutputDeviceID() { - return defaultOutputDeviceID; - } - - @Override - public double getDefaultLowInputLatency(int deviceID) { - return 0.100; - } - - @Override - public double getDefaultLowOutputLatency(int deviceID) { - return 0.100; - } - - @Override - public int getDeviceCount() { - return deviceRecords.size(); - } - - @Override - public String getDeviceName(int deviceID) { - return deviceRecords.get(deviceID).name; - } - - @Override - public int getMaxInputChannels(int deviceID) { - return deviceRecords.get(deviceID).maxInputs; - } - - @Override - public int getMaxOutputChannels(int deviceID) { - return deviceRecords.get(deviceID).maxOutputs; - } - - @Override - public int setSuggestedOutputLatency(double latency) { - suggestedOutputLatency = latency; - return 0; - } - - @Override - public int setSuggestedInputLatency(double latency) { - suggestedInputLatency = latency; - return 0; - } - - @Override - public String getName() { - return "JavaSound"; - } - -} diff --git a/src/com/jsyn/devices/javasound/MidiDeviceTools.java b/src/com/jsyn/devices/javasound/MidiDeviceTools.java deleted file mode 100644 index 413beca..0000000 --- a/src/com/jsyn/devices/javasound/MidiDeviceTools.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2009 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.devices.javasound; - -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.Sequencer; -import javax.sound.midi.Synthesizer; - -public class MidiDeviceTools { - /** Print the available MIDI Devices. */ - public static void listDevices() { - // Ask the MidiSystem what is available. - MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); - // Print info about each device. - for (MidiDevice.Info info : infos) { - System.out.println("MIDI Info: " + info.getDescription() + ", " + info.getName() + ", " - + info.getVendor() + ", " + info.getVersion()); - // Get the device for more information. - try { - MidiDevice device = MidiSystem.getMidiDevice(info); - System.out.println(" Device: " + ", #recv = " + device.getMaxReceivers() - + ", #xmit = " + device.getMaxTransmitters() + ", open = " - + device.isOpen() + ", " + device); - } catch (MidiUnavailableException e) { - e.printStackTrace(); - } - } - } - - /** Find a MIDI transmitter that contains text in the name. */ - public static MidiDevice findKeyboard(String text) { - MidiDevice keyboard = null; - // Ask the MidiSystem what is available. - MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); - // Print info about each device. - for (MidiDevice.Info info : infos) { - try { - MidiDevice device = MidiSystem.getMidiDevice(info); - // Hardware devices are not Synthesizers or Sequencers. - if (!(device instanceof Synthesizer) && !(device instanceof Sequencer)) { - // Is this a transmitter? - // Might be -1 if unlimited. - if (device.getMaxTransmitters() != 0) { - if ((text == null) - || (info.getDescription().toLowerCase() - .contains(text.toLowerCase()))) { - keyboard = device; - System.out.println("Chose: " + info.getDescription()); - break; - } - } - } - } catch (MidiUnavailableException e) { - e.printStackTrace(); - } - } - return keyboard; - } - - public static MidiDevice findKeyboard() { - return findKeyboard(null); - } - -} diff --git a/src/com/jsyn/devices/jportaudio/JPortAudioDevice.java b/src/com/jsyn/devices/jportaudio/JPortAudioDevice.java deleted file mode 100644 index a8e574a..0000000 --- a/src/com/jsyn/devices/jportaudio/JPortAudioDevice.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2009 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.devices.jportaudio; - -import com.jsyn.devices.AudioDeviceInputStream; -import com.jsyn.devices.AudioDeviceManager; -import com.jsyn.devices.AudioDeviceOutputStream; -import com.portaudio.BlockingStream; -import com.portaudio.DeviceInfo; -import com.portaudio.HostApiInfo; -import com.portaudio.PortAudio; -import com.portaudio.StreamParameters; - -public class JPortAudioDevice implements AudioDeviceManager { - private double suggestedOutputLatency = 0.030; - private double suggestedInputLatency = 0.050; - private static final int FRAMES_PER_BUFFER = 128; - - // static Logger logger = Logger.getLogger( JPortAudioDevice.class.getName() ); - - public JPortAudioDevice() { - PortAudio.initialize(); - } - - @Override - public int getDeviceCount() { - return PortAudio.getDeviceCount(); - } - - @Override - public String getDeviceName(int deviceID) { - DeviceInfo deviceInfo = PortAudio.getDeviceInfo(deviceID); - HostApiInfo hostInfo = PortAudio.getHostApiInfo(deviceInfo.hostApi); - return deviceInfo.name + " - " + hostInfo.name; - } - - @Override - public int getDefaultInputDeviceID() { - return PortAudio.getDefaultInputDevice(); - } - - @Override - public int getDefaultOutputDeviceID() { - return PortAudio.getDefaultOutputDevice(); - } - - @Override - public int getMaxInputChannels(int deviceID) { - if (deviceID < 0) { - deviceID = PortAudio.getDefaultInputDevice(); - } - return PortAudio.getDeviceInfo(deviceID).maxInputChannels; - } - - @Override - public int getMaxOutputChannels(int deviceID) { - if (deviceID < 0) { - deviceID = PortAudio.getDefaultOutputDevice(); - } - return PortAudio.getDeviceInfo(deviceID).maxOutputChannels; - } - - @Override - public double getDefaultLowInputLatency(int deviceID) { - if (deviceID < 0) { - deviceID = PortAudio.getDefaultInputDevice(); - } - return PortAudio.getDeviceInfo(deviceID).defaultLowInputLatency; - } - - @Override - public double getDefaultHighInputLatency(int deviceID) { - if (deviceID < 0) { - deviceID = PortAudio.getDefaultInputDevice(); - } - return PortAudio.getDeviceInfo(deviceID).defaultHighInputLatency; - } - - @Override - public double getDefaultLowOutputLatency(int deviceID) { - if (deviceID < 0) { - deviceID = PortAudio.getDefaultOutputDevice(); - } - return PortAudio.getDeviceInfo(deviceID).defaultLowOutputLatency; - } - - @Override - public double getDefaultHighOutputLatency(int deviceID) { - if (deviceID < 0) { - deviceID = PortAudio.getDefaultOutputDevice(); - } - return PortAudio.getDeviceInfo(deviceID).defaultHighOutputLatency; - } - - @Override - public int setSuggestedOutputLatency(double latency) { - suggestedOutputLatency = latency; - return 0; - } - - @Override - public int setSuggestedInputLatency(double latency) { - suggestedInputLatency = latency; - return 0; - } - - @Override - public AudioDeviceOutputStream createOutputStream(int deviceID, int frameRate, - int samplesPerFrame) { - return new JPAOutputStream(deviceID, frameRate, samplesPerFrame); - } - - @Override - public AudioDeviceInputStream createInputStream(int deviceID, int frameRate, int samplesPerFrame) { - return new JPAInputStream(deviceID, frameRate, samplesPerFrame); - } - - private class JPAStream { - BlockingStream blockingStream; - float[] floatBuffer = null; - int samplesPerFrame; - - public void close() { - blockingStream.close(); - } - - public void start() { - blockingStream.start(); - } - - public void stop() { - blockingStream.stop(); - } - - } - - private class JPAOutputStream extends JPAStream implements AudioDeviceOutputStream { - - private JPAOutputStream(int deviceID, int frameRate, int samplesPerFrame) { - this.samplesPerFrame = samplesPerFrame; - StreamParameters streamParameters = new StreamParameters(); - streamParameters.channelCount = samplesPerFrame; - if (deviceID < 0) { - deviceID = PortAudio.getDefaultOutputDevice(); - } - streamParameters.device = deviceID; - streamParameters.suggestedLatency = suggestedOutputLatency; - int flags = 0; - System.out.println("Audio output on " + getDeviceName(deviceID)); - blockingStream = PortAudio.openStream(null, streamParameters, frameRate, - FRAMES_PER_BUFFER, flags); - } - - /** Grossly inefficient. Call the array version instead. */ - @Override - public void write(double value) { - double[] buffer = new double[1]; - buffer[0] = value; - write(buffer, 0, 1); - } - - @Override - public void write(double[] buffer) { - write(buffer, 0, buffer.length); - } - - @Override - public void write(double[] buffer, int start, int count) { - // Allocate float buffer if needed. - if ((floatBuffer == null) || (floatBuffer.length < count)) { - floatBuffer = new float[count]; - } - for (int i = 0; i < count; i++) { - - floatBuffer[i] = (float) buffer[i + start]; - } - blockingStream.write(floatBuffer, count / samplesPerFrame); - } - - @Override - public double getLatency() { - return blockingStream.getInfo().outputLatency; - } - } - - private class JPAInputStream extends JPAStream implements AudioDeviceInputStream { - private JPAInputStream(int deviceID, int frameRate, int samplesPerFrame) { - this.samplesPerFrame = samplesPerFrame; - StreamParameters streamParameters = new StreamParameters(); - streamParameters.channelCount = samplesPerFrame; - if (deviceID < 0) { - deviceID = PortAudio.getDefaultInputDevice(); - } - streamParameters.device = deviceID; - streamParameters.suggestedLatency = suggestedInputLatency; - int flags = 0; - System.out.println("Audio input from " + getDeviceName(deviceID)); - blockingStream = PortAudio.openStream(streamParameters, null, frameRate, - FRAMES_PER_BUFFER, flags); - } - - @Override - public double read() { - double[] buffer = new double[1]; - read(buffer, 0, 1); - return buffer[0]; - } - - @Override - public int read(double[] buffer) { - return read(buffer, 0, buffer.length); - } - - @Override - public int read(double[] buffer, int start, int count) { - // Allocate float buffer if needed. - if ((floatBuffer == null) || (floatBuffer.length < count)) { - floatBuffer = new float[count]; - } - blockingStream.read(floatBuffer, count / samplesPerFrame); - - for (int i = 0; i < count; i++) { - - buffer[i + start] = floatBuffer[i]; - } - return count; - } - - @Override - public double getLatency() { - return blockingStream.getInfo().inputLatency; - } - - @Override - public int available() { - return blockingStream.getReadAvailable() * samplesPerFrame; - } - - } - - @Override - public String getName() { - return "JPortAudio"; - } -} diff --git a/src/com/jsyn/engine/LoadAnalyzer.java b/src/com/jsyn/engine/LoadAnalyzer.java deleted file mode 100644 index cbf7ed5..0000000 --- a/src/com/jsyn/engine/LoadAnalyzer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2009 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.engine; - -/** Measure CPU load. */ -public class LoadAnalyzer { - private long stopTime; - private long previousStopTime; - private long startTime; - private double averageTotalTime; - private double averageOnTime; - - protected LoadAnalyzer() { - stopTime = System.nanoTime(); - } - - /** - * Call this when you stop doing something. Ideally all of the time since start() was spent on - * doing something without interruption. - */ - public void stop() { - previousStopTime = stopTime; - stopTime = System.nanoTime(); - long onTime = stopTime - startTime; - long totalTime = stopTime - previousStopTime; - if (totalTime > 0) { - // Recursive averaging filter. - double rate = 0.01; - averageOnTime = (averageOnTime * (1.0 - rate)) + (onTime * rate); - averageTotalTime = (averageTotalTime * (1.0 - rate)) + (totalTime * rate); - } - } - - /** Call this when you start doing something. */ - public void start() { - startTime = System.nanoTime(); - } - - /** Calculate, on average, how much of the time was spent doing something. */ - public double getAverageLoad() { - if (averageTotalTime > 0.0) { - return averageOnTime / averageTotalTime; - } else { - return 0.0; - } - } -} diff --git a/src/com/jsyn/engine/MultiTable.java b/src/com/jsyn/engine/MultiTable.java deleted file mode 100644 index 6606639..0000000 --- a/src/com/jsyn/engine/MultiTable.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 2009 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.engine; - -/* - * Multiple tables of sawtooth data. - * organized by octaves below the Nyquist Rate. - * used to generate band-limited Sawtooth, Impulse, Pulse, Square and Triangle BL waveforms - * - <pre> - Analysis of octave requirements for tables. - - OctavesIndex Frequency Partials - 0 N/2 11025 1 - 1 N/4 5512 2 - 2 N/8 2756 4 - 3 N/16 1378 8 - 4 N/32 689 16 - 5 N/64 344 32 - 6 N/128 172 64 - 7 N/256 86 128 - </pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class MultiTable { - - public final static int NUM_TABLES = 8; - public final static int CYCLE_SIZE = (1 << 10); - - private static MultiTable instance = new MultiTable(NUM_TABLES, CYCLE_SIZE); - private double phaseScalar; - private float[][] tables; // array of array of tables - - /************************************************************************** - * Initialize sawtooth wavetables. Table[0] should contain a pure sine wave. Succeeding tables - * should have increasing numbers of partials. - */ - public MultiTable(int numTables, int cycleSize) { - int tableSize = cycleSize + 1; - - // Allocate array of arrays. - tables = new float[numTables][tableSize]; - - float[] sineTable = tables[0]; - - phaseScalar = (float) (cycleSize * 0.5); - - /* Fill initial sine table with values for -PI to PI. */ - for (int j = 0; j < tableSize; j++) { - sineTable[j] = (float) Math.sin(((((double) j) / (double) cycleSize) * Math.PI * 2.0) - - Math.PI); - } - - /* - * Build each table from scratch and scale partials by raised cosine* to eliminate Gibbs - * effect. - */ - for (int i = 1; i < numTables; i++) { - int numPartials; - double kGibbs; - float[] table = tables[i]; - - /* Add together partials for this table. */ - numPartials = 1 << i; - kGibbs = Math.PI / (2 * numPartials); - for (int k = 0; k < numPartials; k++) { - double ampl, cGibbs; - int sineIndex = 0; - int partial = k + 1; - cGibbs = Math.cos(k * kGibbs); - /* Calculate amplitude for Nth partial */ - ampl = cGibbs * cGibbs / partial; - - for (int j = 0; j < tableSize; j++) { - table[j] += (float) ampl * sineTable[sineIndex]; - sineIndex += partial; - /* Wrap index at end of table.. */ - if (sineIndex >= cycleSize) { - sineIndex -= cycleSize; - } - } - } - } - - /* Normalize after */ - for (int i = 1; i < numTables; i++) { - normalizeArray(tables[i]); - } - } - - /**************************************************************************/ - public static float normalizeArray(float[] fdata) { - float max, val, gain; - int i; - - // determine maximum value. - max = 0.0f; - for (i = 0; i < fdata.length; i++) { - val = Math.abs(fdata[i]); - if (val > max) - max = val; - } - if (max < 0.0000001f) - max = 0.0000001f; - // scale array - gain = 1.0f / max; - for (i = 0; i < fdata.length; i++) - fdata[i] *= gain; - return gain; - } - - /***************************************************************************** - * When the phaseInc maps to the highest level table, then we start interpolating between the - * highest table and the raw sawtooth value (phase). When phaseInc points to highest table: - * flevel = NUM_TABLES - 1 = -1 - log2(pInc); log2(pInc) = - NUM_TABLES pInc = 2**(-NUM_TABLES) - */ - private final static double LOWEST_PHASE_INC_INV = (1 << NUM_TABLES); - - /**************************************************************************/ - /* Phase ranges from -1.0 to +1.0 */ - public double calculateSawtooth(double currentPhase, double positivePhaseIncrement, - double flevel) { - float[] tableBase; - double val; - double hiSam; /* Use when verticalFraction is 1.0 */ - double loSam; /* Use when verticalFraction is 0.0 */ - double sam1, sam2; - - /* Use Phase to determine sampleIndex into table. */ - double findex = ((phaseScalar * currentPhase) + phaseScalar); - // findex is > 0 so we do not need to call floor(). - int sampleIndex = (int) findex; - double horizontalFraction = findex - sampleIndex; - int tableIndex = (int) flevel; - - if (tableIndex > (NUM_TABLES - 2)) { - /* - * Just use top table and mix with arithmetic sawtooth if below lowest frequency. - * Generate new fraction for interpolating between 0.0 and lowest table frequency. - */ - double fraction = positivePhaseIncrement * LOWEST_PHASE_INC_INV; - tableBase = tables[(NUM_TABLES - 1)]; - - /* Get adjacent samples. Assume guard point present. */ - sam1 = tableBase[sampleIndex]; - sam2 = tableBase[sampleIndex + 1]; - /* Interpolate between adjacent samples. */ - loSam = sam1 + (horizontalFraction * (sam2 - sam1)); - - /* Use arithmetic version for low frequencies. */ - /* fraction is 0.0 at 0 Hz */ - val = currentPhase + (fraction * (loSam - currentPhase)); - } else { - - double verticalFraction = flevel - tableIndex; - - if (tableIndex < 0) { - if (tableIndex < -1) // above Nyquist! - { - val = 0.0; - } else { - /* - * At top of supported range, interpolate between 0.0 and first partial. - */ - tableBase = tables[0]; /* Sine wave table. */ - - /* Get adjacent samples. Assume guard point present. */ - sam1 = tableBase[sampleIndex]; - sam2 = tableBase[sampleIndex + 1]; - - /* Interpolate between adjacent samples. */ - hiSam = sam1 + (horizontalFraction * (sam2 - sam1)); - /* loSam = 0.0 */ - // verticalFraction is 0.0 at Nyquist - val = verticalFraction * hiSam; - } - } else { - /* - * Interpolate between adjacent levels to prevent harmonics from popping. - */ - tableBase = tables[tableIndex + 1]; - - /* Get adjacent samples. Assume guard point present. */ - sam1 = tableBase[sampleIndex]; - sam2 = tableBase[sampleIndex + 1]; - - /* Interpolate between adjacent samples. */ - hiSam = sam1 + (horizontalFraction * (sam2 - sam1)); - - /* Get adjacent samples. Assume guard point present. */ - tableBase = tables[tableIndex]; - sam1 = tableBase[sampleIndex]; - sam2 = tableBase[sampleIndex + 1]; - - /* Interpolate between adjacent samples. */ - loSam = sam1 + (horizontalFraction * (sam2 - sam1)); - - val = loSam + (verticalFraction * (hiSam - loSam)); - } - } - return val; - } - - public double convertPhaseIncrementToLevel(double positivePhaseIncrement) { - if (positivePhaseIncrement < 1.0e-30) { - positivePhaseIncrement = 1.0e-30; - } - return -1.0 - (Math.log(positivePhaseIncrement) / Math.log(2.0)); - } - - public static MultiTable getInstance() { - return instance; - } - -} diff --git a/src/com/jsyn/engine/SynthesisEngine.java b/src/com/jsyn/engine/SynthesisEngine.java deleted file mode 100644 index b49e78e..0000000 --- a/src/com/jsyn/engine/SynthesisEngine.java +++ /dev/null @@ -1,698 +0,0 @@ -/* - * Copyright 2009 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.engine; - -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.logging.Logger; - -import com.jsyn.JSyn; -import com.jsyn.Synthesizer; -import com.jsyn.devices.AudioDeviceFactory; -import com.jsyn.devices.AudioDeviceInputStream; -import com.jsyn.devices.AudioDeviceManager; -import com.jsyn.devices.AudioDeviceOutputStream; -import com.jsyn.unitgen.UnitGenerator; -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.ScheduledQueue; -import com.softsynth.shared.time.TimeStamp; - -//TODO Resolve problem with HearDAHDSR where "Rate" port.set is not reflected in knob. Engine not running. -//TODO new tutorial and docs on website -//TODO AutoStop on DAHDSR -//TODO Test/example SequentialData queueOn and queueOff - -//TODO Abstract device interface. File device! -//TODO Measure thread switching sync, performance for multi-core synthesis. Use 4 core pro. -//TODO Optimize SineOscillatorPhaseModulated -//TODO More circuits. -//TODO DC blocker -//TODO Swing scope probe UIs, auto ranging - -/** - * Internal implementation of JSyn Synthesizer. The public API is in the Synthesizer interface. This - * class might be used directly internally. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see Synthesizer - */ -public class SynthesisEngine implements Synthesizer { - private final static int BLOCKS_PER_BUFFER = 8; - private final static int FRAMES_PER_BUFFER = Synthesizer.FRAMES_PER_BLOCK * BLOCKS_PER_BUFFER; - // I have measured JavaSound taking 1200 msec to close devices. - private static final int MAX_THREAD_STOP_TIME = 2000; - - public static final int DEFAULT_FRAME_RATE = 44100; - - private final AudioDeviceManager audioDeviceManager; - private EngineThread engineThread; - private final ScheduledQueue<ScheduledCommand> commandQueue = new ScheduledQueue<ScheduledCommand>(); - - private InterleavingBuffer inputBuffer; - private InterleavingBuffer outputBuffer; - private double inverseNyquist; - private long frameCount; - private boolean pullDataEnabled = true; - private boolean useRealTime = true; - private boolean started; - private int frameRate = DEFAULT_FRAME_RATE; - private double framePeriod = 1.0 / frameRate; - - // List of all units added to the synth. - private final ArrayList<UnitGenerator> allUnitList = new ArrayList<UnitGenerator>(); - // List of running units. - private final ArrayList<UnitGenerator> runningUnitList = new ArrayList<UnitGenerator>(); - // List of units stopping because of autoStop. - private final ArrayList<UnitGenerator> stoppingUnitList = new ArrayList<UnitGenerator>(); - - private LoadAnalyzer loadAnalyzer; - // private int numOutputChannels; - // private int numInputChannels; - private final CopyOnWriteArrayList<Runnable> audioTasks = new CopyOnWriteArrayList<Runnable>(); - private double mOutputLatency; - private double mInputLatency; - /** A fraction corresponding to exactly -96 dB. */ - public static final double DB96 = (1.0 / 63095.73444801943); - /** A fraction that is approximately -90.3 dB. Defined as 1 bit of an S16. */ - public static final double DB90 = (1.0 / (1 << 15)); - - static Logger logger = Logger.getLogger(SynthesisEngine.class.getName()); - - public SynthesisEngine(AudioDeviceManager audioDeviceManager) { - this.audioDeviceManager = audioDeviceManager; - } - - public SynthesisEngine() { - this(AudioDeviceFactory.createAudioDeviceManager()); - } - - @Override - public String getVersion() { - return JSyn.VERSION; - } - - @Override - public int getVersionCode() { - return JSyn.VERSION_CODE; - } - - @Override - public String toString() { - return "JSyn " + JSyn.VERSION_TEXT; - } - - public boolean isPullDataEnabled() { - return pullDataEnabled; - } - - /** - * If set true then audio data will be pulled from the output ports of connected unit - * generators. The final unit in a tree of units needs to be start()ed. - * - * @param pullDataEnabled - */ - public void setPullDataEnabled(boolean pullDataEnabled) { - this.pullDataEnabled = pullDataEnabled; - } - - private void setupAudioBuffers(int numInputChannels, int numOutputChannels) { - inputBuffer = new InterleavingBuffer(FRAMES_PER_BUFFER, Synthesizer.FRAMES_PER_BLOCK, - numInputChannels); - outputBuffer = new InterleavingBuffer(FRAMES_PER_BUFFER, Synthesizer.FRAMES_PER_BLOCK, - numOutputChannels); - } - - public void terminate() { - } - - class InterleavingBuffer { - private final double[] interleavedBuffer; - ChannelBlockBuffer[] blockBuffers; - - InterleavingBuffer(int framesPerBuffer, int framesPerBlock, int samplesPerFrame) { - interleavedBuffer = new double[framesPerBuffer * samplesPerFrame]; - // Allocate buffers for each channel of synthesis output. - blockBuffers = new ChannelBlockBuffer[samplesPerFrame]; - for (int i = 0; i < blockBuffers.length; i++) { - blockBuffers[i] = new ChannelBlockBuffer(framesPerBlock); - } - } - - int deinterleave(int inIndex) { - for (int jf = 0; jf < Synthesizer.FRAMES_PER_BLOCK; jf++) { - for (int iob = 0; iob < blockBuffers.length; iob++) { - ChannelBlockBuffer buffer = blockBuffers[iob]; - buffer.values[jf] = interleavedBuffer[inIndex++]; - } - } - return inIndex; - } - - int interleave(int outIndex) { - for (int jf = 0; jf < Synthesizer.FRAMES_PER_BLOCK; jf++) { - for (int iob = 0; iob < blockBuffers.length; iob++) { - ChannelBlockBuffer buffer = blockBuffers[iob]; - interleavedBuffer[outIndex++] = buffer.values[jf]; - } - } - return outIndex; - } - - public double[] getChannelBuffer(int i) { - return blockBuffers[i].values; - } - - public void clear() { - for (int i = 0; i < blockBuffers.length; i++) { - blockBuffers[i].clear(); - } - } - } - - class ChannelBlockBuffer { - private final double[] values; - - ChannelBlockBuffer(int framesPerBlock) { - values = new double[framesPerBlock]; - } - - void clear() { - for (int i = 0; i < values.length; i++) { - values[i] = 0.0f; - } - } - } - - @Override - public void start() { - // TODO Use constants. - start(DEFAULT_FRAME_RATE, -1, 0, -1, 2); - } - - @Override - public void start(int frameRate) { - // TODO Use constants. - start(frameRate, -1, 0, -1, 2); - } - - @Override - public synchronized void start(int frameRate, int inputDeviceID, int numInputChannels, - int outputDeviceID, int numOutputChannels) { - if (started) { - logger.info("JSyn already started."); - return; - } - - this.frameRate = frameRate; - this.framePeriod = 1.0 / frameRate; - - setupAudioBuffers(numInputChannels, numOutputChannels); - - logger.info("Pure Java JSyn from www.softsynth.com, rate = " + frameRate + ", " - + (useRealTime ? "RT" : "NON-RealTime") + ", " + JSyn.VERSION_TEXT); - - inverseNyquist = 2.0 / frameRate; - - if (useRealTime) { - engineThread = new EngineThread(inputDeviceID, numInputChannels, - outputDeviceID, numOutputChannels); - logger.fine("Synth thread old priority = " + engineThread.getPriority()); - int engineThreadPriority = engineThread.getPriority() + 2 > Thread.MAX_PRIORITY ? - Thread.MAX_PRIORITY : engineThread.getPriority() + 2; - engineThread.setPriority(engineThreadPriority); - logger.fine("Synth thread new priority = " + engineThread.getPriority()); - engineThread.start(); - } - - started = true; - } - - @Override - public boolean isRunning() { - Thread thread = engineThread; - return (thread != null) && thread.isAlive(); - } - - @Override - public synchronized void stop() { - if (!started) { - logger.info("JSyn already stopped."); - return; - } - - if (useRealTime) { - // Stop audio synthesis and all units. - if (engineThread != null) { - try { - // Interrupt now, otherwise audio thread will wait for audio I/O. - engineThread.requestStop(); - engineThread.join(MAX_THREAD_STOP_TIME); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - synchronized (runningUnitList) { - runningUnitList.clear(); - } - started = false; - } - - private class EngineThread extends Thread - { - private AudioDeviceOutputStream audioOutputStream; - private AudioDeviceInputStream audioInputStream; - private volatile boolean go = true; - - EngineThread(int inputDeviceID, int numInputChannels, - int outputDeviceID, int numOutputChannels) { - if (numInputChannels > 0) { - audioInputStream = audioDeviceManager.createInputStream(inputDeviceID, frameRate, - numInputChannels); - } - if (numOutputChannels > 0) { - audioOutputStream = audioDeviceManager.createOutputStream(outputDeviceID, - frameRate, numOutputChannels); - } - } - - public void requestStop() { - go = false; - interrupt(); - } - - @Override - public void run() { - logger.fine("JSyn synthesis thread starting."); - try { - if (audioInputStream != null) { - logger.finer("JSyn synthesis thread trying to start audio INPUT!"); - audioInputStream.start(); - mInputLatency = audioInputStream.getLatency(); - String msg = String.format("Input Latency in = %5.1f msec", - 1000 * mInputLatency); - logger.fine(msg); - } - if (audioOutputStream != null) { - logger.finer("JSyn synthesis thread trying to start audio OUTPUT!"); - audioOutputStream.start(); - mOutputLatency = audioOutputStream.getLatency(); - String msg = String.format("Output Latency = %5.1f msec", - 1000 * mOutputLatency); - logger.fine(msg); - // Buy some time while we fill the buffer. - audioOutputStream.write(outputBuffer.interleavedBuffer); - } - loadAnalyzer = new LoadAnalyzer(); - while (go) { - boolean throttled = false; - if (audioInputStream != null) { - // This call will block when the input is empty. - audioInputStream.read(inputBuffer.interleavedBuffer); - throttled = true; - } - - loadAnalyzer.start(); - runAudioTasks(); - generateNextBuffer(); - loadAnalyzer.stop(); - - if (audioOutputStream != null) { - // This call will block when the output is full. - audioOutputStream.write(outputBuffer.interleavedBuffer); - throttled = true; - } - if (!throttled && isRealTime()) { - Thread.sleep(2); // avoid spinning and eating up CPU - } - } - - } catch (Throwable e) { - e.printStackTrace(); - go = false; - - } finally { - logger.info("JSyn synthesis thread in finally code."); - // Stop audio system. - if (audioInputStream != null) { - audioInputStream.stop(); - } - if (audioOutputStream != null) { - audioOutputStream.stop(); - } - } - logger.fine("JSyn synthesis thread exiting."); - } - } - - private void runAudioTasks() { - for (Runnable task : audioTasks) { - task.run(); - } - } - - // TODO We need to implement a sharedSleeper like we use in JSyn1. - public void generateNextBuffer() { - int outIndex = 0; - int inIndex = 0; - for (int i = 0; i < BLOCKS_PER_BUFFER; i++) { - if (inputBuffer != null) { - inIndex = inputBuffer.deinterleave(inIndex); - } - - TimeStamp timeStamp = createTimeStamp(); - // Try putting this up here so incoming time-stamped events will get - // scheduled later. - processScheduledCommands(timeStamp); - clearBlockBuffers(); - synthesizeBuffer(); - - if (outputBuffer != null) { - outIndex = outputBuffer.interleave(outIndex); - } - frameCount += Synthesizer.FRAMES_PER_BLOCK; - } - } - - @Override - public double getCurrentTime() { - return frameCount * framePeriod; - } - - @Override - public TimeStamp createTimeStamp() { - return new TimeStamp(getCurrentTime()); - } - - private void processScheduledCommands(TimeStamp timeStamp) { - List<ScheduledCommand> timeList = commandQueue.removeNextList(timeStamp); - - while (timeList != null) { - while (!timeList.isEmpty()) { - ScheduledCommand command = timeList.remove(0); - logger.fine("processing " + command + ", at time " + timeStamp.getTime()); - command.run(); - } - // Get next list of commands at the given time. - timeList = commandQueue.removeNextList(timeStamp); - } - } - - @Override - public void scheduleCommand(TimeStamp timeStamp, ScheduledCommand command) { - if ((Thread.currentThread() == engineThread) && (timeStamp.getTime() <= getCurrentTime())) { - command.run(); - } else { - logger.fine("scheduling " + command + ", at time " + timeStamp.getTime()); - commandQueue.add(timeStamp, command); - } - } - - @Override - public void scheduleCommand(double time, ScheduledCommand command) { - TimeStamp timeStamp = new TimeStamp(time); - scheduleCommand(timeStamp, command); - } - - @Override - public void queueCommand(ScheduledCommand command) { - TimeStamp timeStamp = createTimeStamp(); - scheduleCommand(timeStamp, command); - } - - @Override - public void clearCommandQueue() { - commandQueue.clear(); - } - - private void clearBlockBuffers() { - outputBuffer.clear(); - } - - private void synthesizeBuffer() { - synchronized (runningUnitList) { - ListIterator<UnitGenerator> iterator = runningUnitList.listIterator(); - while (iterator.hasNext()) { - UnitGenerator unit = iterator.next(); - if (pullDataEnabled) { - unit.pullData(getFrameCount(), 0, Synthesizer.FRAMES_PER_BLOCK); - } else { - unit.generate(0, Synthesizer.FRAMES_PER_BLOCK); - } - } - // Remove any units that got auto stopped. - for (UnitGenerator ugen : stoppingUnitList) { - runningUnitList.remove(ugen); - ugen.flattenOutputs(); - } - } - stoppingUnitList.clear(); - } - - public double[] getInputBuffer(int i) { - try { - return inputBuffer.getChannelBuffer(i); - } catch (ArrayIndexOutOfBoundsException e) { - throw new RuntimeException("Audio Input not configured in start() method."); - } - } - - public double[] getOutputBuffer(int i) { - try { - return outputBuffer.getChannelBuffer(i); - } catch (ArrayIndexOutOfBoundsException e) { - throw new RuntimeException("Audio Output not configured in start() method."); - } - } - - private void internalStopUnit(UnitGenerator unit) { - synchronized (runningUnitList) { - runningUnitList.remove(unit); - } - unit.flattenOutputs(); - } - - public void autoStopUnit(UnitGenerator unitGenerator) { - synchronized (stoppingUnitList) { - stoppingUnitList.add(unitGenerator); - } - } - - @Override - public void startUnit(UnitGenerator unit, double time) { - startUnit(unit, new TimeStamp(time)); - } - - @Override - public void stopUnit(UnitGenerator unit, double time) { - stopUnit(unit, new TimeStamp(time)); - } - - @Override - public void startUnit(final UnitGenerator unit, TimeStamp timeStamp) { - // Don't start if it is a component in a circuit because it will be - // executed by the circuit. - if (unit.getCircuit() == null) { - scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - internalStartUnit(unit); - } - }); - } - } - - @Override - public void stopUnit(final UnitGenerator unit, TimeStamp timeStamp) { - scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - internalStopUnit(unit); - } - }); - } - - @Override - public void startUnit(UnitGenerator unit) { - startUnit(unit, createTimeStamp()); - } - - @Override - public void stopUnit(UnitGenerator unit) { - stopUnit(unit, createTimeStamp()); - } - - private void internalStartUnit(UnitGenerator unit) { - // logger.info( "internalStartUnit " + unit + " with circuit " + - // unit.getCircuit() ); - if (unit.getCircuit() == null) { - synchronized (runningUnitList) { - if (!runningUnitList.contains(unit)) { - runningUnitList.add(unit); - } - } - } - // else - // { - // logger.info( - // "internalStartUnit detected race condition !!!! from old JSyn" + unit - // + " with circuit " + unit.getCircuit() ); - // } - } - - public double getInverseNyquist() { - return inverseNyquist; - } - - public double convertTimeToExponentialScaler(double duration) { - // Calculate scaler so that scaler^frames = target/source - double numFrames = duration * getFrameRate(); - return Math.pow(DB90, (1.0 / numFrames)); - } - - @Override - public long getFrameCount() { - return frameCount; - } - - /** - * @return the frameRate - */ - @Override - public int getFrameRate() { - return frameRate; - } - - /** - * @return the inverse of the frameRate for efficiency - */ - @Override - public double getFramePeriod() { - return framePeriod; - } - - /** Convert a short value to a double in the range -1.0 to almost 1.0. */ - public static double convertShortToDouble(short sdata) { - return (sdata * (1.0 / Short.MAX_VALUE)); - } - - /** - * Convert a double value in the range -1.0 to almost 1.0 to a short. Double value is clipped - * before converting. - */ - public static short convertDoubleToShort(double d) { - final double maxValue = ((double) (Short.MAX_VALUE - 1)) / Short.MAX_VALUE; - if (d > maxValue) { - d = maxValue; - } else if (d < -1.0) { - d = -1.0; - } - return (short) (d * Short.MAX_VALUE); - } - - @Override - public void addAudioTask(Runnable blockTask) { - audioTasks.add(blockTask); - } - - @Override - public void removeAudioTask(Runnable blockTask) { - audioTasks.remove(blockTask); - } - - @Override - public double getUsage() { - // use temp so we don't have to synchronize - LoadAnalyzer temp = loadAnalyzer; - if (temp != null) { - return temp.getAverageLoad(); - } else { - return 0.0; - } - } - - @Override - public AudioDeviceManager getAudioDeviceManager() { - return audioDeviceManager; - } - - @Override - public void setRealTime(boolean realTime) { - useRealTime = realTime; - } - - @Override - public boolean isRealTime() { - return useRealTime; - } - - public double getOutputLatency() { - return mOutputLatency; - } - - public double getInputLatency() { - return mInputLatency; - } - - @Override - public void add(UnitGenerator ugen) { - ugen.setSynthesisEngine(this); - allUnitList.add(ugen); - } - - @Override - public void remove(UnitGenerator ugen) { - allUnitList.remove(ugen); - } - - @Override - public void sleepUntil(double time) throws InterruptedException { - double timeToSleep = time - getCurrentTime(); - while (timeToSleep > 0.0) { - if (useRealTime) { - long msecToSleep = (long) (1000 * timeToSleep); - if (msecToSleep <= 0) { - msecToSleep = 1; - } - Thread.sleep(msecToSleep); - } else { - - generateNextBuffer(); - } - timeToSleep = time - getCurrentTime(); - } - } - - @Override - public void sleepFor(double duration) throws InterruptedException { - sleepUntil(getCurrentTime() + duration); - } - - public void printConnections() { - if (pullDataEnabled) { - ListIterator<UnitGenerator> iterator = runningUnitList.listIterator(); - while (iterator.hasNext()) { - UnitGenerator unit = iterator.next(); - unit.printConnections(); - } - } - - } - -} diff --git a/src/com/jsyn/exceptions/ChannelMismatchException.java b/src/com/jsyn/exceptions/ChannelMismatchException.java deleted file mode 100644 index a1554cd..0000000 --- a/src/com/jsyn/exceptions/ChannelMismatchException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.exceptions; - -/** - * This will get thrown if, for example, stereo data is queued to a mono player. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class ChannelMismatchException extends RuntimeException { - - public ChannelMismatchException(String message) { - super(message); - } - - /** - * - */ - private static final long serialVersionUID = -5345224363387498119L; - -} diff --git a/src/com/jsyn/instruments/DrumWoodFM.java b/src/com/jsyn/instruments/DrumWoodFM.java deleted file mode 100644 index ba6cd1b..0000000 --- a/src/com/jsyn/instruments/DrumWoodFM.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.unitgen.Add; -import com.jsyn.unitgen.Circuit; -import com.jsyn.unitgen.EnvelopeAttackDecay; -import com.jsyn.unitgen.Multiply; -import com.jsyn.unitgen.PassThrough; -import com.jsyn.unitgen.SineOscillator; -import com.jsyn.unitgen.SineOscillatorPhaseModulated; -import com.jsyn.unitgen.UnitVoice; -import com.jsyn.util.VoiceDescription; -import com.softsynth.shared.time.TimeStamp; - -/** - * Drum instruments using 2 Operator FM. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class DrumWoodFM extends Circuit implements UnitVoice { - private static final int NUM_PRESETS = 3; - // Declare units and ports. - EnvelopeAttackDecay ampEnv; - SineOscillatorPhaseModulated carrierOsc; - EnvelopeAttackDecay modEnv; - SineOscillator modOsc; - PassThrough freqDistributor; - Add modSummer; - Multiply frequencyMultiplier; - - public UnitInputPort mcratio; - public UnitInputPort index; - public UnitInputPort modRange; - public UnitInputPort frequency; - - public DrumWoodFM() { - // Create unit generators. - add(carrierOsc = new SineOscillatorPhaseModulated()); - add(freqDistributor = new PassThrough()); - add(modSummer = new Add()); - add(ampEnv = new EnvelopeAttackDecay()); - add(modEnv = new EnvelopeAttackDecay()); - add(modOsc = new SineOscillator()); - add(frequencyMultiplier = new Multiply()); - - addPort(mcratio = frequencyMultiplier.inputB, "MCRatio"); - addPort(index = modSummer.inputA, "Index"); - addPort(modRange = modEnv.amplitude, "ModRange"); - addPort(frequency = freqDistributor.input, "Frequency"); - - ampEnv.export(this, "Amp"); - modEnv.export(this, "Mod"); - - freqDistributor.output.connect(carrierOsc.frequency); - freqDistributor.output.connect(frequencyMultiplier.inputA); - - carrierOsc.output.connect(ampEnv.amplitude); - modEnv.output.connect(modSummer.inputB); - modSummer.output.connect(modOsc.amplitude); - modOsc.output.connect(carrierOsc.modulation); - frequencyMultiplier.output.connect(modOsc.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) { - } - - @Override - public void noteOn(double freq, double ampl, TimeStamp timeStamp) { - carrierOsc.amplitude.set(ampl, timeStamp); - ampEnv.input.trigger(timeStamp); - modEnv.input.trigger(timeStamp); - } - - @Override - public UnitOutputPort getOutput() { - return ampEnv.output; - } - - @Override - public void usePreset(int presetIndex) { - mcratio.setup(0.001, 0.6875, 20.0); - ampEnv.attack.setup(0.001, 0.005, 8.0); - modEnv.attack.setup(0.001, 0.005, 8.0); - - int n = presetIndex % NUM_PRESETS; - switch (n) { - case 0: - ampEnv.decay.setup(0.001, 0.293, 8.0); - modEnv.decay.setup(0.001, 0.07, 8.0); - frequency.setup(0.0, 349.0, 3000.0); - index.setup(0.001, 0.05, 10.0); - modRange.setup(0.001, 0.4, 10.0); - break; - case 1: - default: - ampEnv.decay.setup(0.001, 0.12, 8.0); - modEnv.decay.setup(0.001, 0.06, 8.0); - frequency.setup(0.0, 1400.0, 3000.0); - index.setup(0.001, 0.16, 10.0); - modRange.setup(0.001, 0.17, 10.0); - break; - } - } - - static class MyVoiceDescription extends VoiceDescription { - static String[] presetNames = { - "WoodBlockFM", "ClaveFM" - }; - static String[] tags = { - "electronic", "drum" - }; - - public MyVoiceDescription() { - super("DrumWoodFM", presetNames); - } - - @Override - public UnitVoice createUnitVoice() { - return new DrumWoodFM(); - } - - @Override - public String[] getTags(int presetIndex) { - return tags; - } - - @Override - public String getVoiceClassName() { - return DrumWoodFM.class.getName(); - } - } - - public static VoiceDescription getVoiceDescription() { - return new MyVoiceDescription(); - } -} diff --git a/src/com/jsyn/instruments/DualOscillatorSynthVoice.java b/src/com/jsyn/instruments/DualOscillatorSynthVoice.java deleted file mode 100644 index c81041f..0000000 --- a/src/com/jsyn/instruments/DualOscillatorSynthVoice.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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.FilterFourPoles; -import com.jsyn.unitgen.MorphingOscillatorBL; -import com.jsyn.unitgen.Multiply; -import com.jsyn.unitgen.UnitVoice; -import com.jsyn.util.VoiceDescription; -import com.softsynth.math.AudioMath; -import com.softsynth.shared.time.TimeStamp; - -/** - * Synthesizer voice with two morphing oscillators and a four-pole resonant filter. - * Modulate the amplitude and filter using DAHDSR envelopes. - */ -public class DualOscillatorSynthVoice extends Circuit implements UnitVoice { - private Multiply frequencyMultiplier; - private Multiply amplitudeMultiplier; - private Multiply detuneScaler1; - private Multiply detuneScaler2; - private Multiply amplitudeBoost; - private MorphingOscillatorBL osc1; - private MorphingOscillatorBL osc2; - private FilterFourPoles filter; - private EnvelopeDAHDSR ampEnv; - private EnvelopeDAHDSR filterEnv; - private Add cutoffAdder; - - private static MyVoiceDescription voiceDescription; - - 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. Set to 1.0 for no modulation. - */ - public UnitInputPort frequencyScaler; - public UnitInputPort oscShape1; - public UnitInputPort oscShape2; -// public UnitInputPort oscDetune1; -// public UnitInputPort oscDetune2; - public UnitInputPort cutoff; - public UnitInputPort filterEnvDepth; - public UnitInputPort Q; - - public DualOscillatorSynthVoice() { - add(frequencyMultiplier = new Multiply()); - add(amplitudeMultiplier = new Multiply()); - add(amplitudeBoost = new Multiply()); - add(detuneScaler1 = new Multiply()); - add(detuneScaler2 = new Multiply()); - // Add tone generators. - add(osc1 = new MorphingOscillatorBL()); - add(osc2 = new MorphingOscillatorBL()); - - // 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 FilterFourPoles()); - add(cutoffAdder = new Add()); - - filterEnv.output.connect(cutoffAdder.inputA); - cutoffAdder.output.connect(filter.frequency); - frequencyMultiplier.output.connect(detuneScaler1.inputA); - frequencyMultiplier.output.connect(detuneScaler2.inputA); - detuneScaler1.output.connect(osc1.frequency); - detuneScaler2.output.connect(osc2.frequency); - osc1.output.connect(amplitudeMultiplier.inputA); // mix oscillators - osc2.output.connect(amplitudeMultiplier.inputA); - amplitudeMultiplier.output.connect(filter.input); - filter.output.connect(amplitudeBoost.inputA); - amplitudeBoost.output.connect(ampEnv.amplitude); - - addPort(amplitude = amplitudeMultiplier.inputB, PORT_NAME_AMPLITUDE); - addPort(frequency = frequencyMultiplier.inputA, PORT_NAME_FREQUENCY); - addPort(oscShape1 = osc1.shape, "OscShape1"); - addPort(oscShape2 = osc2.shape, "OscShape2"); -// addPort(oscDetune1 = osc1.shape, "OscDetune1"); -// addPort(oscDetune2 = osc2.shape, "OscDetune2"); - addPort(cutoff = cutoffAdder.inputB, PORT_NAME_CUTOFF); - addPortAlias(cutoff, PORT_NAME_TIMBRE); - addPort(Q = filter.Q); - addPort(frequencyScaler = frequencyMultiplier.inputB, PORT_NAME_FREQUENCY_SCALER); - addPort(filterEnvDepth = filterEnv.amplitude, "FilterEnvDepth"); - - filterEnv.export(this, "Filter"); - ampEnv.export(this, "Amp"); - - frequency.setup(osc1.frequency); - frequencyScaler.setup(0.2, 1.0, 4.0); - cutoff.setup(filter.frequency); - // Allow negative filter sweeps - filterEnvDepth.setup(-4000.0, 2000.0, 4000.0); - - // set amplitudes slightly different so that they never entirely cancel - osc1.amplitude.set(0.5); - osc2.amplitude.set(0.4); - // Make the circuit turn off when the envelope finishes to reduce CPU load. - ampEnv.setupAutoDisable(this); - // Add named port for mapping pressure. - amplitudeBoost.inputB.setup(1.0, 1.0, 4.0); - addPortAlias(amplitudeBoost.inputB, PORT_NAME_PRESSURE); - - usePreset(0); - } - - /** - * The first oscillator will be tuned UP by semitoneOffset/2. - * The second oscillator will be tuned DOWN by semitoneOffset/2. - * @param semitoneOffset - */ - private void setDetunePitch(double semitoneOffset) { - double halfOffset = semitoneOffset * 0.5; - setDetunePitch1(halfOffset); - setDetunePitch2(-halfOffset); - } - - /** - * Set the detuning for osc1 in semitones. - * @param semitoneOffset - */ - private void setDetunePitch1(double semitoneOffset) { - double scale = AudioMath.semitonesToFrequencyScaler(semitoneOffset); - detuneScaler1.inputB.set(scale); - } - - /** - * Set the detuning for osc2 in semitones. - * @param semitoneOffset - */ - private void setDetunePitch2(double semitoneOffset) { - double scale = AudioMath.semitonesToFrequencyScaler(semitoneOffset); - detuneScaler2.inputB.set(scale); - } - - @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; - } - - // Reset to basic voice. - public void reset() { - osc1.shape.set(0.0); - osc2.shape.set(0.0); - ampEnv.attack.set(0.005); - ampEnv.decay.set(0.2); - ampEnv.sustain.set(0.5); - ampEnv.release.set(1.0); - filterEnv.attack.set(0.01); - filterEnv.decay.set(0.6); - filterEnv.sustain.set(0.4); - filterEnv.release.set(1.0); - cutoff.set(500.0); - filterEnvDepth.set(3000.0); - filter.reset(); - filter.Q.set(3.9); - setDetunePitch(0.02); - } - - @Override - public void usePreset(int presetIndex) { - reset(); // start from known configuration - int n = presetIndex % presetNames.length; - switch (n) { - case 0: - break; - case 1: - ampEnv.attack.set(0.1); - ampEnv.decay.set(0.9); - ampEnv.sustain.set(0.1); - ampEnv.release.set(0.1); - cutoff.set(500.0); - filterEnvDepth.set(500.0); - filter.Q.set(3.0); - break; - case 2: - ampEnv.attack.set(0.1); - ampEnv.decay.set(0.3); - ampEnv.release.set(0.5); - cutoff.set(2000.0); - filterEnvDepth.set(500.0); - filter.Q.set(2.0); - break; - case 3: - osc1.shape.set(-0.9); - osc2.shape.set(-0.8); - ampEnv.attack.set(0.3); - ampEnv.decay.set(0.8); - ampEnv.release.set(0.2); - filterEnv.sustain.set(0.7); - cutoff.set(500.0); - filterEnvDepth.set(500.0); - filter.Q.set(3.0); - break; - case 4: - osc1.shape.set(1.0); - osc2.shape.set(0.0); - break; - case 5: - osc1.shape.set(1.0); - setDetunePitch1(0.0); - osc2.shape.set(0.9); - setDetunePitch1(7.0); - break; - case 6: - osc1.shape.set(0.6); - osc2.shape.set(-0.2); - setDetunePitch1(0.01); - ampEnv.attack.set(0.005); - ampEnv.decay.set(0.09); - ampEnv.sustain.set(0.0); - ampEnv.release.set(1.0); - filterEnv.attack.set(0.005); - filterEnv.decay.set(0.1); - filterEnv.sustain.set(0.4); - filterEnv.release.set(1.0); - cutoff.set(2000.0); - filterEnvDepth.set(5000.0); - filter.Q.set(7.02); - break; - default: - break; - } - } - - private static final String[] presetNames = { - "FastSaw", "SlowSaw", "BrightSaw", - "SoftSine", "SquareSaw", "SquareFifth", - "Blip" - }; - - static class MyVoiceDescription extends VoiceDescription { - String[] tags = { - "electronic", "filter", "analog", "subtractive" - }; - - public MyVoiceDescription() { - super(DualOscillatorSynthVoice.class.getName(), presetNames); - } - - @Override - public UnitVoice createUnitVoice() { - return new DualOscillatorSynthVoice(); - } - - @Override - public String[] getTags(int presetIndex) { - return tags; - } - - @Override - public String getVoiceClassName() { - return DualOscillatorSynthVoice.class.getName(); - } - } - - public static VoiceDescription getVoiceDescription() { - if (voiceDescription == null) { - voiceDescription = new MyVoiceDescription(); - } - return voiceDescription; - } - - -} diff --git a/src/com/jsyn/instruments/JSynInstrumentLibrary.java b/src/com/jsyn/instruments/JSynInstrumentLibrary.java deleted file mode 100644 index 9f111c3..0000000 --- a/src/com/jsyn/instruments/JSynInstrumentLibrary.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.swing.InstrumentBrowser; -import com.jsyn.util.InstrumentLibrary; -import com.jsyn.util.VoiceDescription; - -/** - * Stock instruments provided with the JSyn distribution. - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see InstrumentBrowser - */ - -public class JSynInstrumentLibrary implements InstrumentLibrary { - static VoiceDescription[] descriptions = { - WaveShapingVoice.getVoiceDescription(), - SubtractiveSynthVoice.getVoiceDescription(), - DualOscillatorSynthVoice.getVoiceDescription(), - NoiseHit.getVoiceDescription(), - DrumWoodFM.getVoiceDescription() - }; - - @Override - public VoiceDescription[] getVoiceDescriptions() { - return descriptions; - } - - @Override - public String getName() { - return "JSynInstruments"; - } -} diff --git a/src/com/jsyn/instruments/NoiseHit.java b/src/com/jsyn/instruments/NoiseHit.java deleted file mode 100644 index b8714fc..0000000 --- a/src/com/jsyn/instruments/NoiseHit.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2009 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.UnitOutputPort; -import com.jsyn.unitgen.Circuit; -import com.jsyn.unitgen.EnvelopeAttackDecay; -import com.jsyn.unitgen.PinkNoise; -import com.jsyn.unitgen.UnitVoice; -import com.jsyn.util.VoiceDescription; -import com.softsynth.shared.time.TimeStamp; - -/** - * Cheap synthetic cymbal sound. - */ -public class NoiseHit extends Circuit implements UnitVoice { - EnvelopeAttackDecay ampEnv; - PinkNoise noise; - private static final int NUM_PRESETS = 3; - - public NoiseHit() { - // Create unit generators. - add(noise = new PinkNoise()); - add(ampEnv = new EnvelopeAttackDecay()); - noise.output.connect(ampEnv.amplitude); - - ampEnv.export(this, "Amp"); - - // Make the circuit turn off when the envelope finishes to reduce CPU load. - ampEnv.setupAutoDisable(this); - - usePreset(0); - } - - @Override - public void noteOff(TimeStamp timeStamp) { - } - - @Override - public void noteOn(double freq, double ampl, TimeStamp timeStamp) { - noise.amplitude.set(ampl, timeStamp); - ampEnv.input.trigger(); - } - - @Override - public UnitOutputPort getOutput() { - return ampEnv.output; - } - - @Override - public void usePreset(int presetIndex) { - int n = presetIndex % NUM_PRESETS; - switch (n) { - case 0: - ampEnv.attack.set(0.001); - ampEnv.decay.set(0.1); - break; - case 1: - ampEnv.attack.set(0.03); - ampEnv.decay.set(1.4); - break; - default: - ampEnv.attack.set(0.9); - ampEnv.decay.set(0.3); - break; - } - } - - static class MyVoiceDescription extends VoiceDescription { - static String[] presetNames = { - "ShortNoiseHit", "LongNoiseHit", "SlowNoiseHit" - }; - static String[] tags = { - "electronic", "noise" - }; - - public MyVoiceDescription() { - super("NoiseHit", presetNames); - } - - @Override - public UnitVoice createUnitVoice() { - return new NoiseHit(); - } - - @Override - public String[] getTags(int presetIndex) { - return tags; - } - - @Override - public String getVoiceClassName() { - return NoiseHit.class.getName(); - } - } - - public static VoiceDescription getVoiceDescription() { - return new MyVoiceDescription(); - } -} diff --git a/src/com/jsyn/instruments/SubtractiveSynthVoice.java b/src/com/jsyn/instruments/SubtractiveSynthVoice.java deleted file mode 100644 index 5cfc4b9..0000000 --- a/src/com/jsyn/instruments/SubtractiveSynthVoice.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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(); - } - -} diff --git a/src/com/jsyn/instruments/WaveShapingVoice.java b/src/com/jsyn/instruments/WaveShapingVoice.java deleted file mode 100644 index 5044f21..0000000 --- a/src/com/jsyn/instruments/WaveShapingVoice.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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(); - } - -} diff --git a/src/com/jsyn/io/AudioFifo.java b/src/com/jsyn/io/AudioFifo.java deleted file mode 100644 index 0c563e4..0000000 --- a/src/com/jsyn/io/AudioFifo.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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.io; - -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * FIFO that implements AudioInputStream, AudioOutputStream interfaces. This can be used to send - * audio data between different threads. The reads or writes may or may not wait based on flags. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class AudioFifo implements AudioInputStream, AudioOutputStream { - // These indices run double the FIFO size so that we can tell empty from full. - private volatile int readIndex; - private volatile int writeIndex; - private volatile double[] buffer; - // Used to mask the index into range when accessing the buffer array. - private int accessMask; - // Used to mask the index so it wraps around. - private int sizeMask; - private boolean writeWaitEnabled = true; - private boolean readWaitEnabled = true; - final Lock lock = new ReentrantLock(); - final Condition notFull = lock.newCondition(); - final Condition notEmpty = lock.newCondition(); - - /** - * @param size Number of doubles in the FIFO. Must be a power of 2. Eg. 1024. - */ - public void allocate(int size) { - if (!isPowerOfTwo(size)) { - throw new IllegalArgumentException("Size must be a power of two."); - } - buffer = new double[size]; - accessMask = size - 1; - sizeMask = (size * 2) - 1; - } - - public int size() { - return buffer.length; - } - - public static boolean isPowerOfTwo(int size) { - return ((size & (size - 1)) == 0); - } - - /** How many samples are available for reading without blocking? */ - @Override - public int available() { - return (writeIndex - readIndex) & sizeMask; - } - - @Override - public void close() { - // TODO Maybe we should tell any thread that is waiting that the FIFO is closed. - } - - @Override - public double read() { - double value = Double.NaN; - if (readWaitEnabled) { - lock.lock(); - try { - while (available() < 1) { - try { - notEmpty.await(); - } catch (InterruptedException e) { - return Double.NaN; - } - } - value = readOneInternal(); - } finally { - lock.unlock(); - } - - } else { - if (readIndex != writeIndex) { - value = readOneInternal(); - } - } - - if (writeWaitEnabled) { - lock.lock(); - notFull.signal(); - lock.unlock(); - } - - return value; - } - - private double readOneInternal() { - double value = buffer[readIndex & accessMask]; - readIndex = (readIndex + 1) & sizeMask; - return value; - } - - @Override - public void write(double value) { - if (writeWaitEnabled) { - lock.lock(); - try { - while (available() == buffer.length) - { - try { - notFull.await(); - } catch (InterruptedException e) { - return; // Silently fail - } - } - writeOneInternal(value); - } finally { - lock.unlock(); - } - - } else { - if (available() != buffer.length) { - writeOneInternal(value); - } - } - - if (readWaitEnabled) { - lock.lock(); - notEmpty.signal(); - lock.unlock(); - } - } - - private void writeOneInternal(double value) { - buffer[writeIndex & accessMask] = value; - writeIndex = (writeIndex + 1) & sizeMask; - } - - @Override - public int read(double[] buffer) { - return read(buffer, 0, buffer.length); - } - - @Override - public int read(double[] buffer, int start, int count) { - if (readWaitEnabled) { - for (int i = 0; i < count; i++) { - buffer[i + start] = read(); - } - } else { - if (available() < count) { - count = available(); - } else { - for (int i = 0; i < count; i++) { - buffer[i + start] = read(); - } - } - } - return count; - } - - @Override - public void write(double[] buffer) { - write(buffer, 0, buffer.length); - } - - @Override - public void write(double[] buffer, int start, int count) { - for (int i = 0; i < count; i++) { - write(buffer[i + start]); - } - } - - /** If true then a subsequent write call will wait if there is no room to write. */ - public void setWriteWaitEnabled(boolean enabled) { - writeWaitEnabled = enabled; - - } - - /** If true then a subsequent read call will wait if there is no data to read. */ - public void setReadWaitEnabled(boolean enabled) { - readWaitEnabled = enabled; - - } - - public boolean isWriteWaitEnabled() { - return writeWaitEnabled; - } - - public boolean isReadWaitEnabled() { - return readWaitEnabled; - } -} diff --git a/src/com/jsyn/io/AudioInputStream.java b/src/com/jsyn/io/AudioInputStream.java deleted file mode 100644 index f233ff1..0000000 --- a/src/com/jsyn/io/AudioInputStream.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2009 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.io; - -public interface AudioInputStream { - public double read(); - - /** - * Try to fill the entire buffer. - * - * @param buffer - * @return number of samples read - */ - public int read(double[] buffer); - - /** - * Read from the stream. Block until some data is available. - * - * @param buffer - * @param start index of first sample in buffer - * @param count number of samples to read, for example count=8 for 4 stereo frames - * @return number of samples read - */ - public int read(double[] buffer, int start, int count); - - public void close(); - - /** - * @return number of samples currently available to read without blocking - */ - public int available(); -} diff --git a/src/com/jsyn/io/AudioOutputStream.java b/src/com/jsyn/io/AudioOutputStream.java deleted file mode 100644 index dada577..0000000 --- a/src/com/jsyn/io/AudioOutputStream.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2009 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.io; - -import java.io.IOException; - -public interface AudioOutputStream { - public void write(double value) throws IOException; - - public void write(double[] buffer) throws IOException; - - public void write(double[] buffer, int start, int count) throws IOException; - - public void close() throws IOException; -} diff --git a/src/com/jsyn/midi/MessageParser.java b/src/com/jsyn/midi/MessageParser.java deleted file mode 100644 index d0f5d4d..0000000 --- a/src/com/jsyn/midi/MessageParser.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.midi; - -/** - * Parse the message and call the appropriate method to handle it. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class MessageParser { - private int[] parameterIndices = new int[MidiConstants.MAX_CHANNELS]; - private int[] parameterValues = new int[MidiConstants.MAX_CHANNELS]; - private int BIT_NON_RPM = 1 << 14; - private int MASK_14BIT = (1 << 14) - 1; - - public void parse(byte[] message) { - int status = message[0]; - int command = status & 0xF0; - int channel = status & 0x0F; - - switch (command) { - case MidiConstants.NOTE_ON: - int velocity = message[2]; - if (velocity == 0) { - noteOff(channel, message[1], velocity); - } else { - noteOn(channel, message[1], velocity); - } - break; - - case MidiConstants.NOTE_OFF: - noteOff(channel, message[1], message[2]); - break; - - case MidiConstants.POLYPHONIC_AFTERTOUCH: - polyphonicAftertouch(channel, message[1], message[2]); - break; - - case MidiConstants.CHANNEL_PRESSURE: - channelPressure(channel, message[1]); - break; - - case MidiConstants.CONTROL_CHANGE: - rawControlChange(channel, message[1], message[2]); - break; - - case MidiConstants.PROGRAM_CHANGE: - programChange(channel, message[1]); - break; - - case MidiConstants.PITCH_BEND: - int bend = (message[2] << 7) + message[1]; - pitchBend(channel, bend); - break; - } - - } - - public void rawControlChange(int channel, int index, int value) { - int paramIndex; - int paramValue; - switch(index) { - case MidiConstants.CONTROLLER_DATA_ENTRY: - parameterValues[channel] = value << 7; - fireParameterChange(channel); - break; - case MidiConstants.CONTROLLER_DATA_ENTRY_LSB: - paramValue = parameterValues[channel] & ~0x7F; - paramValue |= value; - parameterValues[channel] = paramValue; - fireParameterChange(channel); - break; - case MidiConstants.CONTROLLER_NRPN_LSB: - paramIndex = parameterIndices[channel] & ~0x7F; - paramIndex |= value | BIT_NON_RPM; - parameterIndices[channel] = paramIndex; - break; - case MidiConstants.CONTROLLER_NRPN_MSB: - parameterIndices[channel] = (value << 7) | BIT_NON_RPM;; - break; - case MidiConstants.CONTROLLER_RPN_LSB: - paramIndex = parameterIndices[channel] & ~0x7F; - paramIndex |= value; - parameterIndices[channel] = paramIndex; - break; - case MidiConstants.CONTROLLER_RPN_MSB: - parameterIndices[channel] = value << 7; - break; - default: - controlChange(channel, index, value); - break; - - } - } - - private void fireParameterChange(int channel) { - int paramIndex; - paramIndex = parameterIndices[channel]; - if ((paramIndex & BIT_NON_RPM) == 0) { - registeredParameter(channel, paramIndex, parameterValues[channel]); - } else { - nonRegisteredParameter(channel, paramIndex & MASK_14BIT, parameterValues[channel]); - } - } - - public void nonRegisteredParameter(int channel, int index14, int value14) { - } - - public void registeredParameter(int channel, int index14, int value14) { - } - - public void pitchBend(int channel, int bend) { - } - - public void programChange(int channel, int program) { - } - - public void polyphonicAftertouch(int channel, int pitch, int pressure) { - } - - public void channelPressure(int channel, int pressure) { - } - - public void controlChange(int channel, int index, int value) { - } - - public void noteOn(int channel, int pitch, int velocity) { - } - - // If a NOTE_ON with zero velocity is received then noteOff will be called. - public void noteOff(int channel, int pitch, int velocity) { - } -} diff --git a/src/com/jsyn/midi/MidiConstants.java b/src/com/jsyn/midi/MidiConstants.java deleted file mode 100644 index 8c92119..0000000 --- a/src/com/jsyn/midi/MidiConstants.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.midi; - -/** - * Constants that define the MIDI standard. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class MidiConstants { - - public static final int MAX_CHANNELS = 16; - // Basic commands. - public static final int NOTE_OFF = 0x80; - public static final int NOTE_ON = 0x90; - public static final int POLYPHONIC_AFTERTOUCH = 0xA0; - public static final int CONTROL_CHANGE = 0xB0; - public static final int PROGRAM_CHANGE = 0xC0; - public static final int CHANNEL_AFTERTOUCH = 0xD0; - public static final int CHANNEL_PRESSURE = CHANNEL_AFTERTOUCH; - public static final int PITCH_BEND = 0xE0; - public static final int SYSTEM_COMMON = 0xF0; - - public static final int PITCH_BEND_CENTER = 0x2000; - - public static final int CONTROLLER_BANK_SELECT = 0; - public static final int CONTROLLER_MOD_WHEEL = 1; - public static final int CONTROLLER_BREATH = 2; - public static final int CONTROLLER_DATA_ENTRY = 6; - public static final int CONTROLLER_VOLUME = 7; - public static final int CONTROLLER_PAN = 10; - - public static final int CONTROLLER_LSB_OFFSET = 32; - public static final int CONTROLLER_DATA_ENTRY_LSB = CONTROLLER_DATA_ENTRY + CONTROLLER_LSB_OFFSET; - - public static final int CONTROLLER_TIMBRE = 74; // Often used by MPE for Y axis control. - - public static final int CONTROLLER_DATA_INCREMENT = 96; - public static final int CONTROLLER_DATA_DECREMENT = 97; - public static final int CONTROLLER_NRPN_LSB = 98; - public static final int CONTROLLER_NRPN_MSB = 99; - public static final int CONTROLLER_RPN_LSB = 100; - public static final int CONTROLLER_RPN_MSB = 101; - - public static final int RPN_BEND_RANGE = 0; - public static final int RPN_FINE_TUNING = 1; - - public static final String PITCH_NAMES[] = { - "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" - }; - - /** - * Calculate frequency in Hertz based on MIDI pitch. Middle C is 60.0. You can use fractional - * pitches so 60.5 would give you a pitch half way between C and C#. - */ - static final double CONCERT_A_FREQUENCY = 440.0; - static final double CONCERT_A_PITCH = 69.0; - - public static double convertPitchToFrequency(double pitch) { - return CONCERT_A_FREQUENCY * Math.pow(2.0, ((pitch - CONCERT_A_PITCH) / 12.0)); - } - - /** - * Calculate MIDI pitch based on frequency in Hertz. Middle C is 60.0. - */ - public static double convertFrequencyToPitch(double frequency) { - return CONCERT_A_PITCH + (12 * Math.log(frequency / CONCERT_A_FREQUENCY) / Math.log(2.0)); - } - -} diff --git a/src/com/jsyn/midi/MidiSynthesizer.java b/src/com/jsyn/midi/MidiSynthesizer.java deleted file mode 100644 index 30204b0..0000000 --- a/src/com/jsyn/midi/MidiSynthesizer.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2016 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.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. - * - * <pre><code> - 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); - </code></pre> - * - * See the example UseMidiKeyboard.java - * - * @author Phil Burk (C) 2016 Mobileer Inc - */ -public class MidiSynthesizer extends MessageParser { - - private MultiChannelSynthesizer multiSynth; - - public MidiSynthesizer(MultiChannelSynthesizer multiSynth) { - this.multiSynth = multiSynth; - } - - @Override - public void controlChange(int channel, int index, int value) { - //System.out.println("controlChange(" + channel + ", " + index + ", " + value + ")"); - double normalized = value * (1.0 / 127.0); - switch (index) { - case MidiConstants.CONTROLLER_MOD_WHEEL: - double vibratoDepth = 0.1 * normalized; - System.out.println( "vibratoDepth = " + vibratoDepth ); - multiSynth.setVibratoDepth(channel, vibratoDepth); - break; - case MidiConstants.CONTROLLER_TIMBRE: - multiSynth.setTimbre(channel, normalized); - break; - case MidiConstants.CONTROLLER_VOLUME: - multiSynth.setVolume(channel, normalized); - break; - case MidiConstants.CONTROLLER_PAN: - // convert to -1 to +1 range - multiSynth.setPan(channel, (normalized * 2.0) - 1.0); - break; - } - } - - @Override - public void registeredParameter(int channel, int index14, int value14) { - switch(index14) { - case MidiConstants.RPN_BEND_RANGE: - int semitones = value14 >> 7; - int cents = value14 & 0x7F; - double bendRange = semitones + (cents * 0.01); - multiSynth.setBendRange(channel, bendRange); - break; - default: - break; - } - } - - @Override - public void programChange(int channel, int program) { - multiSynth.programChange(channel, program); - } - - @Override - public void channelPressure(int channel, int value) { - double normalized = value * (1.0 / 127.0); - multiSynth.setPressure(channel, normalized); - } - - @Override - public void noteOff(int channel, int noteNumber, int velocity) { - multiSynth.noteOff(channel, noteNumber, velocity); - } - - @Override - public void noteOn(int channel, int noteNumber, int velocity) { - multiSynth.noteOn(channel, noteNumber, velocity); - } - - @Override - public void pitchBend(int channel, int bend) { - double offset = (bend - MidiConstants.PITCH_BEND_CENTER) - * (1.0 / (MidiConstants.PITCH_BEND_CENTER)); - multiSynth.setPitchBend(channel, offset); - } - - public void onReceive(byte[] bytes, int i, int length) { - parse(bytes); // TODO - } - -} diff --git a/src/com/jsyn/package.html b/src/com/jsyn/package.html deleted file mode 100644 index cd73832..0000000 --- a/src/com/jsyn/package.html +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<title>JSyn Package</title> -</head> -<body> -JSyn is a music and audio synthesis API for Java. The basic sequence of operations is: -<ul> -<li>Use the JSyn class to create a synthesizer.</li> -<li>Create unit generators and add them to the synthesizer.</li> -<li>Connect unit generators so that audio signals can flow between them.</li> -<li>Start an output generator. It will pull data from the connected units.</li> -<li>Set port values and queue sample and envelope data to change the sound.</li> -</ul> -</body> -</html>
\ No newline at end of file diff --git a/src/com/jsyn/ports/ConnectableInput.java b/src/com/jsyn/ports/ConnectableInput.java deleted file mode 100644 index 3dae876..0000000 --- a/src/com/jsyn/ports/ConnectableInput.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.ports; - -/** - * This interface lets you pass either an input port, or a single part of an input port. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public interface ConnectableInput { - public void connect(ConnectableOutput other); - - public void disconnect(ConnectableOutput other); - - /** - * This is used internally by PortBlockPart to make a connection between specific parts of a - * port. - * - * @return - */ - public PortBlockPart getPortBlockPart(); - - public void pullData(long frameCount, int start, int limit); -} diff --git a/src/com/jsyn/ports/ConnectableOutput.java b/src/com/jsyn/ports/ConnectableOutput.java deleted file mode 100644 index f42a799..0000000 --- a/src/com/jsyn/ports/ConnectableOutput.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2009 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.ports; - -public interface ConnectableOutput { - public void connect(ConnectableInput other); - - public void disconnect(ConnectableInput other); -} diff --git a/src/com/jsyn/ports/GettablePort.java b/src/com/jsyn/ports/GettablePort.java deleted file mode 100644 index aabf5ca..0000000 --- a/src/com/jsyn/ports/GettablePort.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2009 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.ports; - -public interface GettablePort { - String getName(); - - int getNumParts(); - - double getValue(int partNum); - - Object getUnitGenerator(); -} diff --git a/src/com/jsyn/ports/InputMixingBlockPart.java b/src/com/jsyn/ports/InputMixingBlockPart.java deleted file mode 100644 index 5b54b99..0000000 --- a/src/com/jsyn/ports/InputMixingBlockPart.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import java.io.PrintStream; - -import com.jsyn.Synthesizer; -import com.jsyn.unitgen.UnitGenerator; - -/** - * A UnitInputPort has an array of these, one for each part. - * - * @author Phil Burk 2009 Mobileer Inc - */ - -public class InputMixingBlockPart extends PortBlockPart { - private double[] mixer = new double[Synthesizer.FRAMES_PER_BLOCK]; - private double current; - private UnitInputPort unitInputPort; - - InputMixingBlockPart(UnitInputPort unitInputPort, double defaultValue) { - super(unitInputPort, defaultValue); - this.unitInputPort = unitInputPort; - } - - @Override - public double getValue() { - return current; - } - - @Override - protected void setValue(double value) { - current = value; - super.setValue(value); - } - - @Override - public double[] getValues() { - double[] result; - int numConnections = getConnectionCount(); - // System.out.println("numConnection = " + numConnections + " for " + - // this ); - if (numConnections == 0) { - // No connection so just use our own data. - result = super.getValues(); - } else { - // Mix all of the connected ports. - double[] inputs; - int jCon = 0; - PortBlockPart otherPart; - // Choose value to initialize the mixer array. - if (unitInputPort.isValueAdded()) { - inputs = super.getValues(); // prime mixer with the set() values - jCon = 0; - } else { - otherPart = getConnection(jCon); - inputs = otherPart.getValues(); // prime mixer with first connected - jCon = 1; - } - for (int i = 0; i < mixer.length; i++) { - mixer[i] = inputs[i]; - } - // Now mix in the remaining inputs. - for (; jCon < numConnections; jCon++) { - otherPart = getConnection(jCon); - inputs = otherPart.getValues(); - for (int i = 0; i < mixer.length; i++) { - mixer[i] += inputs[i]; - } - } - result = mixer; - } - current = result[0]; - return result; - } - - private void printIndentation(PrintStream out, int level) { - for (int i = 0; i < level; i++) { - out.print(" "); - } - } - - private String portToString(UnitBlockPort port) { - UnitGenerator ugen = port.getUnitGenerator(); - return ugen.getClass().getSimpleName() + "." + port.getName(); - } - - public void printConnections(PrintStream out, int level) { - for (int i = 0; i < getConnectionCount(); i++) { - PortBlockPart part = getConnection(i); - - printIndentation(out, level); - out.println(portToString(getPort()) + " <--- " + portToString(part.getPort())); - - part.getPort().getUnitGenerator().printConnections(out, level + 1); - } - } -} diff --git a/src/com/jsyn/ports/PortBlockPart.java b/src/com/jsyn/ports/PortBlockPart.java deleted file mode 100644 index ad75211..0000000 --- a/src/com/jsyn/ports/PortBlockPart.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import java.util.ArrayList; - -import com.jsyn.Synthesizer; -import com.jsyn.engine.SynthesisEngine; -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -/** - * Part of a multi-part port, for example, the left side of a stereo port. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class PortBlockPart implements ConnectableOutput, ConnectableInput { - private double[] values = new double[Synthesizer.FRAMES_PER_BLOCK]; - private ArrayList<PortBlockPart> connections = new ArrayList<PortBlockPart>(); - private UnitBlockPort unitBlockPort; - - protected PortBlockPart(UnitBlockPort unitBlockPort, double defaultValue) { - this.unitBlockPort = unitBlockPort; - setValue(defaultValue); - } - - public double[] getValues() { - return values; - } - - public double getValue() { - return values[0]; - } - - public double get() { - return values[0]; - } - - protected void setValue(double value) { - for (int i = 0; i < values.length; i++) { - values[i] = value; - } - } - - protected boolean isConnected() { - return (connections.size() > 0); - } - - private void addConnection(PortBlockPart otherPart) { - // System.out.println("addConnection from " + this + " to " + otherPart - // ); - if (connections.contains(otherPart)) { - System.out.println("addConnection already had connection from " + this + " to " - + otherPart); - } else { - connections.add(otherPart); - } - } - - private void removeConnection(PortBlockPart otherPart) { - // System.out.println("removeConnection from " + this + " to " + - // otherPart ); - connections.remove(otherPart); - } - - private void connectNow(PortBlockPart otherPart) { - addConnection(otherPart); - otherPart.addConnection(this); - } - - private void disconnectNow(PortBlockPart otherPart) { - removeConnection(otherPart); - otherPart.removeConnection(this); - } - - private void disconnectAllNow() { - for (PortBlockPart part : connections) { - part.removeConnection(this); - } - connections.clear(); - } - - public PortBlockPart getConnection(int i) { - return connections.get(i); - } - - public int getConnectionCount() { - return connections.size(); - } - - /** Set all values to the last value. */ - protected void flatten() { - double lastValue = values[values.length - 1]; - for (int i = 0; i < values.length - 1; i++) { - values[i] = lastValue; - } - } - - protected UnitBlockPort getPort() { - return unitBlockPort; - } - - private void checkConnection(PortBlockPart destination) { - SynthesisEngine sourceSynth = unitBlockPort.getSynthesisEngine(); - SynthesisEngine destSynth = destination.unitBlockPort.getSynthesisEngine(); - if ((sourceSynth != destSynth) && (sourceSynth != null) && (destSynth != null)) { - throw new RuntimeException("Connection between units on different synths."); - } - } - - protected void connect(final PortBlockPart destination) { - checkConnection(destination); - unitBlockPort.queueCommand(new ScheduledCommand() { - @Override - public void run() { - connectNow(destination); - } - }); - } - - protected void connect(final PortBlockPart destination, TimeStamp timeStamp) { - unitBlockPort.scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - connectNow(destination); - } - }); - } - - protected void disconnect(final PortBlockPart destination) { - unitBlockPort.queueCommand(new ScheduledCommand() { - @Override - public void run() { - disconnectNow(destination); - } - }); - } - - protected void disconnect(final PortBlockPart destination, TimeStamp timeStamp) { - unitBlockPort.scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - disconnectNow(destination); - } - }); - } - - protected void disconnectAll() { - unitBlockPort.queueCommand(new ScheduledCommand() { - @Override - public void run() { - disconnectAllNow(); - } - }); - } - - @Override - public void connect(ConnectableInput other) { - connect(other.getPortBlockPart()); - } - - @Override - public void connect(ConnectableOutput other) { - other.connect(this); - } - - @Override - public void disconnect(ConnectableOutput other) { - other.disconnect(this); - } - - @Override - public void disconnect(ConnectableInput other) { - disconnect(other.getPortBlockPart()); - } - - /** To implement ConnectableInput */ - @Override - public PortBlockPart getPortBlockPart() { - return this; - } - - @Override - public void pullData(long frameCount, int start, int limit) { - for (int i = 0; i < getConnectionCount(); i++) { - PortBlockPart part = getConnection(i); - part.getPort().getUnitGenerator().pullData(frameCount, start, limit); - } - } - -} diff --git a/src/com/jsyn/ports/QueueDataCommand.java b/src/com/jsyn/ports/QueueDataCommand.java deleted file mode 100644 index c23fbcd..0000000 --- a/src/com/jsyn/ports/QueueDataCommand.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.data.SequentialData; -import com.softsynth.shared.time.ScheduledCommand; - -/** - * A command that can be used to queue SequentialData to a UnitDataQueuePort. Here is an example of - * queuing data with a callback using this command. - * - * <pre> - * <code> - * // Queue an envelope with a completion callback. - * QueueDataCommand command = envelopePlayer.dataQueue.createQueueDataCommand( envelope, 0, - * envelope.getNumFrames() ); - * // Create an object to be called when the queued data is done. - * TestQueueCallback callback = new TestQueueCallback(); - * command.setCallback( callback ); - * command.setNumLoops( 2 ); - * envelopePlayer.rate.set( 0.2 ); - * synth.queueCommand( command ); - * </code> - * </pre> - * - * The callback will be passed QueueDataEvents. - * - * <pre> - * <code> - * class TestQueueCallback implements UnitDataQueueCallback - * { - * public void started( QueueDataEvent event ) - * { - * System.out.println("CALLBACK: Envelope started."); - * } - * - * public void looped( QueueDataEvent event ) - * { - * System.out.println("CALLBACK: Envelope looped."); - * } - * - * public void finished( QueueDataEvent event ) - * { - * System.out.println("CALLBACK: Envelope finished."); - * } - * } - * </code> - * </pre> - * - * @author Phil Burk 2009 Mobileer Inc - */ -public abstract class QueueDataCommand extends QueueDataEvent implements ScheduledCommand { - - protected SequentialDataCrossfade crossfadeData; - protected SequentialData currentData; - - private static final long serialVersionUID = -1185274459972359536L; - private UnitDataQueueCallback callback; - - public QueueDataCommand(UnitDataQueuePort port, SequentialData sequentialData, int startFrame, - int numFrames) { - super(port); - - if ((startFrame + numFrames) > sequentialData.getNumFrames()) { - throw new IllegalArgumentException("tried to queue past end of data, " + (startFrame + numFrames)); - } else if (startFrame < 0) { - throw new IllegalArgumentException("tried to queue before start of data, " + startFrame); - } - this.sequentialData = sequentialData; - this.currentData = sequentialData; - crossfadeData = new SequentialDataCrossfade(); - this.startFrame = startFrame; - this.numFrames = numFrames; - } - - @Override - public abstract void run(); - - /** - * If true then this item will be skipped if other items are queued after it. This flag allows - * you to queue lots of small pieces of sound without making the queue very long. - * - * @param skipIfOthers - */ - public void setSkipIfOthers(boolean skipIfOthers) { - this.skipIfOthers = skipIfOthers; - } - - /** - * If true then the queue will be cleared and this item will be started immediately. It is - * better to use this flag than to clear the queue from the application because there could be a - * gap before the next item is available. This is most useful when combined with - * setCrossFadeIn(). - * - * @param immediate - */ - public void setImmediate(boolean immediate) { - this.immediate = immediate; - } - - public UnitDataQueueCallback getCallback() { - return callback; - } - - public void setCallback(UnitDataQueueCallback callback) { - this.callback = callback; - } - - public SequentialDataCrossfade getCrossfadeData() { - return crossfadeData; - } - - public void setCrossfadeData(SequentialDataCrossfade crossfadeData) { - this.crossfadeData = crossfadeData; - } - - public SequentialData getCurrentData() { - return currentData; - } - - public void setCurrentData(SequentialData currentData) { - this.currentData = currentData; - } - - /** - * Stop the unit that contains this port after this command has finished. - * - * @param autoStop - */ - public void setAutoStop(boolean autoStop) { - this.autoStop = autoStop; - } - - /** - * Set how many time the block should be repeated after the first time. For example, if you set - * numLoops to zero the block will only be played once. If you set numLoops to one the block - * will be played twice. - * - * @param numLoops number of times to loop back - */ - public void setNumLoops(int numLoops) { - this.numLoops = numLoops; - } - - /** - * Number of frames to cross fade from the previous block to this block. This can be used to - * avoid pops when making abrupt transitions. There must be frames available after the end of - * the previous block to use for crossfading. The crossfade is linear. - * - * @param size - */ - public void setCrossFadeIn(int size) { - this.crossFadeIn = size; - } - -} diff --git a/src/com/jsyn/ports/QueueDataEvent.java b/src/com/jsyn/ports/QueueDataEvent.java deleted file mode 100644 index 2b93fab..0000000 --- a/src/com/jsyn/ports/QueueDataEvent.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import java.util.EventObject; - -import com.jsyn.data.SequentialData; - -/** - * An event that is passed to a UnitDataQueueCallback when the element in the queue is played.. - * - * @author Phil Burk 2009 Mobileer Inc - */ -public class QueueDataEvent extends EventObject { - private static final long serialVersionUID = 176846633064538053L; - protected SequentialData sequentialData; - protected int startFrame; - protected int numFrames; - protected int numLoops; - protected int loopsLeft; - protected int crossFadeIn; - protected boolean skipIfOthers; - protected boolean autoStop; - protected boolean immediate; - - public QueueDataEvent(Object arg0) { - super(arg0); - } - - public boolean isSkipIfOthers() { - return skipIfOthers; - } - - public boolean isImmediate() { - return immediate; - } - - public SequentialData getSequentialData() { - return sequentialData; - } - - public int getCrossFadeIn() { - return crossFadeIn; - } - - public int getStartFrame() { - return startFrame; - } - - public int getNumFrames() { - return numFrames; - } - - public int getNumLoops() { - return numLoops; - } - - public int getLoopsLeft() { - return loopsLeft; - } - - public boolean isAutoStop() { - return autoStop; - } - -} diff --git a/src/com/jsyn/ports/SequentialDataCrossfade.java b/src/com/jsyn/ports/SequentialDataCrossfade.java deleted file mode 100644 index 25e1fd9..0000000 --- a/src/com/jsyn/ports/SequentialDataCrossfade.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.data.SequentialData; -import com.jsyn.data.SequentialDataCommon; - -/** - * A SequentialData object that will crossfade between two other SequentialData objects. The - * crossfade is linear. This could, for example, be used to create a smooth transition between two - * samples, or between two arbitrary regions in one sample. As an example, consider a sample that - * has a length of 200000 frames. You could specify a sample loop that started arbitrarily at frame - * 50000 and with a size of 30000 frames. Unless you got lucky with the zero crossings, it is likely - * that you will hear a pop when this sample loops. To prevent the pop you could crossfade the - * beginning of the loop with the region immediately after the end of the loop. To crossfade with - * 5000 samples after the loop: - * - * <pre> - * SequentialDataCrossfade xfade = new SequentialDataCrossfade(sample, (50000 + 30000), 5000, sample, - * 50000, 30000); - * </pre> - * - * After the crossfade you will hear the rest of the target at full volume. There are two regions - * that determine what is returned from readDouble() - * <ol> - * <li>Crossfade region with size crossFadeFrames. It fades smoothly from source to target.</li> - * <li>Steady region that is simply the target values with size (numFrames-crossFadeFrames).</li> - * </ol> - * - * <pre> - * "Crossfade Region" "Steady Region" - * |-- source fading out --| - * |-- target fading in --|-- remainder of target at original volume --| - * </pre> - * - * @author Phil Burk - */ -class SequentialDataCrossfade extends SequentialDataCommon { - private SequentialData source; - private int sourceStartIndex; - - private SequentialData target; - private int targetStartIndex; - - private int crossFadeFrames; - private double frameScaler; - - /** - * @param source SequentialData that will be at full volume at the beginning of the crossfade - * region. - * @param sourceStartFrame Frame in source to begin the crossfade. - * @param crossFadeFrames Number of frames in the crossfaded region. - * @param target SequentialData that will be at full volume at the end of the crossfade region. - * @param targetStartFrame Frame in target to begin the crossfade. - * @param numFrames total number of frames in this data object. - */ - public void setup(SequentialData source, int sourceStartFrame, int crossFadeFrames, - SequentialData target, int targetStartFrame, int numFrames) { - - assert ((sourceStartFrame + crossFadeFrames) <= source.getNumFrames()); - assert ((targetStartFrame + numFrames) <= target.getNumFrames()); - - // System.out.println( "WARNING! sourceStartFrame = " + sourceStartFrame - // + ", crossFadeFrames = " + crossFadeFrames + ", maxFrame = " - // + source.getNumFrames() + ", source = " + source ); - // System.out.println( " targetStartFrame = " + targetStartFrame - // + ", numFrames = " + numFrames + ", maxFrame = " - // + target.getNumFrames() + ", target = " + target ); - - // There is a danger that we might nest SequentialDataCrossfades deeply - // as source. If past crossfade region then pull out the target. - if (source instanceof SequentialDataCrossfade) { - SequentialDataCrossfade crossfade = (SequentialDataCrossfade) source; - // If we are starting past the crossfade region then just use the - // target. - if (sourceStartFrame >= crossfade.crossFadeFrames) { - source = crossfade.target; - sourceStartFrame += crossfade.targetStartIndex / source.getChannelsPerFrame(); - } - } - - if (target instanceof SequentialDataCrossfade) { - SequentialDataCrossfade crossfade = (SequentialDataCrossfade) target; - target = crossfade.target; - targetStartFrame += crossfade.targetStartIndex / target.getChannelsPerFrame(); - } - - this.source = source; - this.target = target; - this.sourceStartIndex = sourceStartFrame * source.getChannelsPerFrame(); - this.crossFadeFrames = crossFadeFrames; - this.targetStartIndex = targetStartFrame * target.getChannelsPerFrame(); - - frameScaler = (crossFadeFrames == 0) ? 1.0 : (1.0 / crossFadeFrames); - this.numFrames = numFrames; - } - - @Override - public void writeDouble(int index, double value) { - } - - @Override - public double readDouble(int index) { - int frame = index / source.getChannelsPerFrame(); - if (frame < crossFadeFrames) { - double factor = frame * frameScaler; - double value = (1.0 - factor) * source.readDouble(index + sourceStartIndex); - value += (factor * target.readDouble(index + targetStartIndex)); - return value; - } else { - return target.readDouble(index + targetStartIndex); - } - } - - @Override - public double getRateScaler(int index, double synthesisRate) { - return target.getRateScaler(index, synthesisRate); - } - - @Override - public int getChannelsPerFrame() { - return target.getChannelsPerFrame(); - } - -} diff --git a/src/com/jsyn/ports/SettablePort.java b/src/com/jsyn/ports/SettablePort.java deleted file mode 100644 index e0db05c..0000000 --- a/src/com/jsyn/ports/SettablePort.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.softsynth.shared.time.TimeStamp; - -/** - * Port whose parts can be set. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public interface SettablePort extends GettablePort { - void set(int partNum, double value, TimeStamp timeStamp); -} diff --git a/src/com/jsyn/ports/UnitBlockPort.java b/src/com/jsyn/ports/UnitBlockPort.java deleted file mode 100644 index d7fc82f..0000000 --- a/src/com/jsyn/ports/UnitBlockPort.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2009 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.ports; - -/** - * A port that contains multiple parts with blocks of data. - * - * @author Phil Burk 2009 Mobileer Inc - */ -public class UnitBlockPort extends UnitPort { - PortBlockPart[] parts; - - public UnitBlockPort(int numParts, String name, double defaultValue) { - super(name); - makeParts(numParts, defaultValue); - } - - public UnitBlockPort(String name) { - this(1, name, 0.0); - } - - protected void makeParts(int numParts, double defaultValue) { - parts = new PortBlockPart[numParts]; - for (int i = 0; i < numParts; i++) { - parts[i] = new PortBlockPart(this, defaultValue); - } - } - - @Override - public int getNumParts() { - return parts.length; - } - - /** - * Convenience call to get(0). - * - * @return value of 0th part as set - */ - public double get() { - return get(0); - } - - public double getValue() { - return getValue(0); - } - - /** - * This is used inside UnitGenerators to get the current values for a port. It works regardless - * of whether the port is connected or not. - * - * @return - */ - public double[] getValues() { - return parts[0].getValues(); - } - - /** Only for use in the audio thread when implementing UnitGenerators. */ - public double[] getValues(int partNum) { - return parts[partNum].getValues(); - } - - /** Get the immediate current value of the port. */ - public double getValue(int partNum) { - return parts[partNum].getValue(); - } - - public double get(int partNum) { - return parts[partNum].get(); - } - - /** Only for use in the audio thread when implementing UnitGenerators. */ - protected void setValueInternal(int partNum, double value) { - parts[partNum].setValue(value); - } - - /** Only for use in the audio thread when implementing UnitGenerators. */ - public void setValueInternal(double value) { - setValueInternal(0, value); - } - - public boolean isConnected() { - return isConnected(0); - } - - public boolean isConnected(int partNum) { - return parts[partNum].isConnected(); - } - - public void disconnectAll(int partNum) { - parts[partNum].disconnectAll(); - } - - public void disconnectAll() { - disconnectAll(0); - } -} diff --git a/src/com/jsyn/ports/UnitDataQueueCallback.java b/src/com/jsyn/ports/UnitDataQueueCallback.java deleted file mode 100644 index dca4adc..0000000 --- a/src/com/jsyn/ports/UnitDataQueueCallback.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.ports; - -/** - * This is called when a block of data that is queued to a UnitDataQueuePort starts, loops, or - * finishes. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public interface UnitDataQueueCallback { - public void started(QueueDataEvent event); - - public void looped(QueueDataEvent event); - - public void finished(QueueDataEvent event); -} diff --git a/src/com/jsyn/ports/UnitDataQueuePort.java b/src/com/jsyn/ports/UnitDataQueuePort.java deleted file mode 100644 index 5487589..0000000 --- a/src/com/jsyn/ports/UnitDataQueuePort.java +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import java.util.LinkedList; - -import com.jsyn.data.SequentialData; -import com.jsyn.exceptions.ChannelMismatchException; -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -/** - * Queue for SequentialData, samples or envelopes - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class UnitDataQueuePort extends UnitPort { - private final LinkedList<QueuedBlock> blocks = new LinkedList<QueuedBlock>(); - private QueueDataCommand currentBlock; - private int frameIndex; - private int numChannels = 1; - private double normalizedRate; - private long framesMoved; - private boolean autoStopPending; - private boolean targetValid; - private QueueDataCommand finishingBlock; - private QueueDataCommand loopingBlock; - public static final int LOOP_IF_LAST = -1; - - public UnitDataQueuePort(String name) { - super(name); - } - - /** Hold a reference to part of a sample. */ - @SuppressWarnings("serial") - private class QueuedBlock extends QueueDataCommand { - - public QueuedBlock(SequentialData queueableData, int startFrame, int numFrames) { - super(UnitDataQueuePort.this, queueableData, startFrame, numFrames); - } - - @Override - public void run() { - synchronized (blocks) { - // Remove last block if it can be skipped. - if (blocks.size() > 0) { - QueueDataEvent lastBlock = blocks.getLast(); - if (lastBlock.isSkipIfOthers()) { - blocks.removeLast(); - } - } - - // If we are crossfading then figure out where to crossfade - // from. - if (getCrossFadeIn() > 0) { - if (isImmediate()) { - // Queue will be cleared so fade in from current. - if (currentBlock != null) { - setupCrossFade(currentBlock, frameIndex, this); - } - // else nothing is playing so don't crossfade. - } else { - QueueDataCommand endBlock = getEndBlock(); - if (endBlock != null) { - setupCrossFade(endBlock, - endBlock.getStartFrame() + endBlock.getNumFrames(), this); - } - } - } - - if (isImmediate()) { - clearQueue(); - } - - blocks.add(this); - } - } - } - - // FIXME - determine crossfade on any transition between blocks or when looping back. - - protected void setupCrossFade(QueueDataCommand sourceCommand, int sourceStartIndex, - QueueDataCommand targetCommand) { - int crossFrames = targetCommand.getCrossFadeIn(); - SequentialData sourceData = sourceCommand.getCurrentData(); - SequentialData targetData = targetCommand.getCurrentData(); - int remainingSource = sourceData.getNumFrames() - sourceStartIndex; - // clip to end of source - if (crossFrames > remainingSource) - crossFrames = remainingSource; - if (crossFrames > 0) { - // The SequentialDataCrossfade should continue to the end of the target - // so that we can crossfade from it to the target. - int remainingTarget = targetData.getNumFrames() - targetCommand.getStartFrame(); - targetCommand.crossfadeData.setup(sourceData, sourceStartIndex, crossFrames, - targetData, targetCommand.getStartFrame(), remainingTarget); - targetCommand.currentData = targetCommand.crossfadeData; - targetCommand.startFrame = 0; - } - } - - public QueueDataCommand createQueueDataCommand(SequentialData queueableData) { - return createQueueDataCommand(queueableData, 0, queueableData.getNumFrames()); - } - - public QueueDataCommand createQueueDataCommand(SequentialData queueableData, int startFrame, - int numFrames) { - if (queueableData.getChannelsPerFrame() != UnitDataQueuePort.this.numChannels) { - throw new ChannelMismatchException("Tried to queue " - + queueableData.getChannelsPerFrame() + " channel data to a " + numChannels - + " channel port."); - } - return new QueuedBlock(queueableData, startFrame, numFrames); - } - - public QueueDataCommand getEndBlock() { - if (blocks.size() > 0) { - return blocks.getLast(); - } else if (currentBlock != null) { - return currentBlock; - } else { - return null; - } - } - - public void setCurrentBlock(QueueDataCommand currentBlock) { - this.currentBlock = currentBlock; - } - - public void firePendingCallbacks() { - if (loopingBlock != null) { - if (loopingBlock.getCallback() != null) { - loopingBlock.getCallback().looped(currentBlock); - } - loopingBlock = null; - } - if (finishingBlock != null) { - if (finishingBlock.getCallback() != null) { - finishingBlock.getCallback().finished(currentBlock); // FIXME - Should this pass - // finishingBlock?! - } - finishingBlock = null; - } - } - - public boolean hasMore() { - return (currentBlock != null) || (blocks.size() > 0); - } - - private void checkBlock() { - if (currentBlock == null) { - synchronized (blocks) { - setCurrentBlock(blocks.remove()); - frameIndex = currentBlock.getStartFrame(); - currentBlock.loopsLeft = currentBlock.getNumLoops(); - if (currentBlock.getCallback() != null) { - currentBlock.getCallback().started(currentBlock); - } - } - } - } - - private void advanceFrameIndex() { - frameIndex += 1; - framesMoved += 1; - // Are we done with this block? - if (frameIndex >= (currentBlock.getStartFrame() + currentBlock.getNumFrames())) { - // Should we loop on this block based on a counter? - if (currentBlock.loopsLeft > 0) { - currentBlock.loopsLeft -= 1; - loopToStart(); - } - // Should we loop forever on this block? - else if ((blocks.size() == 0) && (currentBlock.loopsLeft < 0)) { - loopToStart(); - } - // We are done. - else { - if (currentBlock.isAutoStop()) { - autoStopPending = true; - } - finishingBlock = currentBlock; - setCurrentBlock(null); - // System.out.println("advanceFrameIndex: currentBlock set null"); - } - } - } - - private void loopToStart() { - if (currentBlock.getCrossFadeIn() > 0) { - setupCrossFade(currentBlock, frameIndex, currentBlock); - } - frameIndex = currentBlock.getStartFrame(); - loopingBlock = currentBlock; - } - - public double getNormalizedRate() { - return normalizedRate; - } - - public double readCurrentChannelDouble(int channelIndex) { - return currentBlock.currentData.readDouble((frameIndex * numChannels) + channelIndex); - } - - public void writeCurrentChannelDouble(int channelIndex, double value) { - currentBlock.currentData.writeDouble((frameIndex * numChannels) + channelIndex, value); - } - - public void beginFrame(double synthesisPeriod) { - checkBlock(); - normalizedRate = currentBlock.currentData.getRateScaler(frameIndex, synthesisPeriod); - } - - public void endFrame() { - advanceFrameIndex(); - targetValid = true; - } - - public double readNextMonoDouble(double synthesisPeriod) { - beginFrame(synthesisPeriod); - double value = currentBlock.currentData.readDouble(frameIndex); - endFrame(); - return value; - } - - /** Write directly to the port queue. This is only called by unit tests! */ - protected void addQueuedBlock(QueueDataEvent block) { - blocks.add((QueuedBlock) block); - } - - /** Clear the queue. Internal use only. */ - protected void clearQueue() { - synchronized (blocks) { - blocks.clear(); - setCurrentBlock(null); - targetValid = false; - autoStopPending = false; - } - } - - class ClearQueueCommand implements ScheduledCommand { - @Override - public void run() { - clearQueue(); - } - } - - /** Queue the data to the port at a future time. */ - public void queue(SequentialData queueableData, int startFrame, int numFrames, - TimeStamp timeStamp) { - QueueDataCommand command = createQueueDataCommand(queueableData, startFrame, numFrames); - scheduleCommand(timeStamp, command); - } - - /** - * Queue the data to the port at a future time. Command will clear the queue before executing. - */ - public void queueImmediate(SequentialData queueableData, int startFrame, int numFrames, - TimeStamp timeStamp) { - QueueDataCommand command = createQueueDataCommand(queueableData, startFrame, numFrames); - command.setImmediate(true); - scheduleCommand(timeStamp, command); - } - - /** Queue the data to the port at a future time. */ - public void queueLoop(SequentialData queueableData, int startFrame, int numFrames, - TimeStamp timeStamp) { - queueLoop(queueableData, startFrame, numFrames, LOOP_IF_LAST, timeStamp); - } - - /** - * Queue the data to the port at a future time with a specified number of loops. - */ - public void queueLoop(SequentialData queueableData, int startFrame, int numFrames, - int numLoops, TimeStamp timeStamp) { - QueueDataCommand command = createQueueDataCommand(queueableData, startFrame, numFrames); - command.setNumLoops(numLoops); - scheduleCommand(timeStamp, command); - } - - /** Queue the entire data object for looping. */ - public void queueLoop(SequentialData queueableData) { - queueLoop(queueableData, 0, queueableData.getNumFrames()); - } - - /** Queue the data to the port for immediate use. */ - public void queueLoop(SequentialData queueableData, int startFrame, int numFrames) { - queueLoop(queueableData, startFrame, numFrames, LOOP_IF_LAST); - } - - /** - * Queue the data to the port for immediate use with a specified number of loops. - */ - public void queueLoop(SequentialData queueableData, int startFrame, int numFrames, int numLoops) { - QueueDataCommand command = createQueueDataCommand(queueableData, startFrame, numFrames); - command.setNumLoops(numLoops); - queueCommand(command); - } - - /** - * Queue the data to the port at a future time. Request that the unit stop when this block is - * finished. - */ - public void queueStop(SequentialData queueableData, int startFrame, int numFrames, - TimeStamp timeStamp) { - QueueDataCommand command = createQueueDataCommand(queueableData, startFrame, numFrames); - command.setAutoStop(true); - scheduleCommand(timeStamp, command); - } - - /** Queue the data to the port through the command queue ASAP. */ - public void queue(SequentialData queueableData, int startFrame, int numFrames) { - QueueDataCommand command = createQueueDataCommand(queueableData, startFrame, numFrames); - queueCommand(command); - } - - /** - * Queue entire amount of data with no options. - * - * @param queueableData - */ - public void queue(SequentialData queueableData) { - queue(queueableData, 0, queueableData.getNumFrames()); - } - - /** Schedule queueOn now! */ - public void queueOn(SequentialData queueableData) { - queueOn(queueableData, getSynthesisEngine().createTimeStamp()); - } - - /** Schedule queueOff now! */ - public void queueOff(SequentialData queueableData) { - queueOff(queueableData, false); - } - - /** Schedule queueOff now! */ - public void queueOff(SequentialData queueableData, boolean ifStop) { - queueOff(queueableData, ifStop, getSynthesisEngine().createTimeStamp()); - } - - /** - * Convenience method that will queue the attack portion of a channelData and the sustain loop - * if it exists. This could be used to implement a NoteOn method. - */ - public void queueOn(SequentialData queueableData, TimeStamp timeStamp) { - - if (queueableData.getSustainBegin() < 0) { - // no sustain loop, handle release - if (queueableData.getReleaseBegin() < 0) { - // No loops - queueImmediate(queueableData, 0, queueableData.getNumFrames(), timeStamp); - } else { - queueImmediate(queueableData, 0, queueableData.getReleaseEnd(), timeStamp); - int size = queueableData.getReleaseEnd() - queueableData.getReleaseBegin(); - queueLoop(queueableData, queueableData.getReleaseBegin(), size, timeStamp); - } - } else { - // yes sustain loop - if (queueableData.getSustainEnd() > 0) { - int frontSize = queueableData.getSustainBegin(); - int loopSize = queueableData.getSustainEnd() - queueableData.getSustainBegin(); - // Is there an initial portion before the sustain loop? - if (frontSize > 0) { - queueImmediate(queueableData, 0, frontSize, timeStamp); - } - loopSize = queueableData.getSustainEnd() - queueableData.getSustainBegin(); - if (loopSize > 0) { - queueLoop(queueableData, queueableData.getSustainBegin(), loopSize, timeStamp); - } - } - - } - } - - /** - * Convenience method that will queue the decay portion of a SequentialData object, or the gap - * and release loop portions if they exist. This could be used to implement a NoteOff method. - * - * @param ifStop Will setAutostop(true) if release portion queued without a release loop. This will - * stop execution of the unit. - */ - public void queueOff(SequentialData queueableData, boolean ifStop, TimeStamp timeStamp) { - if (queueableData.getSustainBegin() >= 0) /* Sustain loop? */ - { - int relSize = queueableData.getReleaseEnd() - queueableData.getReleaseBegin(); - if (queueableData.getReleaseBegin() < 0) { /* Sustain loop, no release loop. */ - int susEnd = queueableData.getSustainEnd(); - int size = queueableData.getNumFrames() - susEnd; - // System.out.println("queueOff: size = " + size ); - if (size <= 0) { - // always queue something so that we can stop the loop - // 20001117 - size = 1; - susEnd = queueableData.getNumFrames() - 1; - } - if (ifStop) { - queueStop(queueableData, susEnd, size, timeStamp); - } else { - queue(queueableData, susEnd, size, timeStamp); - } - } else if (queueableData.getReleaseBegin() > queueableData.getSustainEnd()) { - // Queue gap between sustain and release loop. - queue(queueableData, queueableData.getSustainEnd(), queueableData.getReleaseEnd() - - queueableData.getSustainEnd(), timeStamp); - if (relSize > 0) - queueLoop(queueableData, queueableData.getReleaseBegin(), relSize, timeStamp); - } else if (relSize > 0) { - // No gap between sustain and release. - queueLoop(queueableData, queueableData.getReleaseBegin(), relSize, timeStamp); - } - } - /* If no sustain loop, then nothing to do. */ - } - - public void clear(TimeStamp timeStamp) { - ScheduledCommand command = new ClearQueueCommand(); - scheduleCommand(timeStamp, command); - } - - public void clear() { - ScheduledCommand command = new ClearQueueCommand(); - queueCommand(command); - } - - public void writeNextDouble(double value) { - checkBlock(); - currentBlock.currentData.writeDouble(frameIndex, value); - advanceFrameIndex(); - } - - public long getFrameCount() { - return framesMoved; - } - - public boolean testAndClearAutoStop() { - boolean temp = autoStopPending; - autoStopPending = false; - return temp; - } - - public boolean isTargetValid() { - return targetValid; - } - - public void setNumChannels(int numChannels) { - this.numChannels = numChannels; - } - - public int getNumChannels() { - return numChannels; - } -} diff --git a/src/com/jsyn/ports/UnitFunctionPort.java b/src/com/jsyn/ports/UnitFunctionPort.java deleted file mode 100644 index e45241a..0000000 --- a/src/com/jsyn/ports/UnitFunctionPort.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.data.Function; - -/** - * Port for holding a Function object. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class UnitFunctionPort extends UnitPort { - private static NullFunction nullFunction = new NullFunction(); - private Function function = nullFunction; - - private static class NullFunction implements Function { - @Override - public double evaluate(double input) { - return 0.0; - } - } - - public UnitFunctionPort(String name) { - super(name); - } - - public void set(Function function) { - this.function = function; - } - - public Function get() { - return function; - } -} diff --git a/src/com/jsyn/ports/UnitGatePort.java b/src/com/jsyn/ports/UnitGatePort.java deleted file mode 100644 index 700aef8..0000000 --- a/src/com/jsyn/ports/UnitGatePort.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.unitgen.UnitGenerator; -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -public class UnitGatePort extends UnitInputPort { - private boolean autoDisableEnabled = false; - private boolean triggered = false; - private boolean off = true; - private UnitGenerator gatedUnit; - public static final double THRESHOLD = 0.01; - - public UnitGatePort(String name) { - super(name); - } - - public void on() { - setOn(true); - } - - public void off() { - setOn(false); - } - - public void off(TimeStamp timeStamp) { - setOn(false, timeStamp); - } - - public void on(TimeStamp timeStamp) { - setOn(true, timeStamp); - } - - private void setOn(final boolean on) { - queueCommand(new ScheduledCommand() { - @Override - public void run() { - setOnInternal(on); - } - }); - } - - private void setOn(final boolean on, TimeStamp timeStamp) { - scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - setOnInternal(on); - } - }); - } - - private void setOnInternal(boolean on) { - if (on) { - triggerInternal(); - } - setValueInternal(on ? 1.0 : 0.0); - } - - private void triggerInternal() { - getGatedUnit().setEnabled(true); - triggered = true; - } - - public void trigger() { - queueCommand(new ScheduledCommand() { - @Override - public void run() { - triggerInternal(); - } - }); - } - - public void trigger(TimeStamp timeStamp) { - scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - triggerInternal(); - } - }); - } - - /** - * This is called by UnitGenerators. It sets the off value that can be tested using isOff(). - * - * @param i - * @return true if triggered by a positive edge. - */ - public boolean checkGate(int i) { - double[] inputs = getValues(); - boolean result = triggered; - triggered = false; - if (off) { - if (inputs[i] >= THRESHOLD) { - result = true; - off = false; - } - } else { - if (inputs[i] < THRESHOLD) { - off = true; - } - } - return result; - } - - public boolean isOff() { - return off; - } - - public boolean isAutoDisableEnabled() { - return autoDisableEnabled; - } - - /** - * Request the containing UnitGenerator be disabled when checkAutoDisabled() is called. This can - * be used to reduce CPU load. - * - * @param autoDisableEnabled - */ - public void setAutoDisableEnabled(boolean autoDisableEnabled) { - this.autoDisableEnabled = autoDisableEnabled; - } - - /** - * Called by UnitGenerator when an envelope reaches the end of its contour. - */ - public void checkAutoDisable() { - if (autoDisableEnabled) { - getGatedUnit().setEnabled(false); - } - } - - private UnitGenerator getGatedUnit() { - return (gatedUnit == null) ? getUnitGenerator() : gatedUnit; - } - - public void setupAutoDisable(UnitGenerator unit) { - gatedUnit = unit; - setAutoDisableEnabled(true); - // Start off disabled so we don't immediately swamp the CPU. - gatedUnit.setEnabled(false); - } -} diff --git a/src/com/jsyn/ports/UnitInputPort.java b/src/com/jsyn/ports/UnitInputPort.java deleted file mode 100644 index 3eda1f6..0000000 --- a/src/com/jsyn/ports/UnitInputPort.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import java.io.PrintStream; - -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -/** - * A port that is used to pass values into a UnitGenerator. - * - * @author Phil Burk 2009 Mobileer Inc - */ -public class UnitInputPort extends UnitBlockPort implements ConnectableInput, SettablePort { - private double minimum = 0.0; - private double maximum = 1.0; - private double defaultValue = 0.0; - private double[] setValues; - private boolean valueAdded = false; - - /** - * @param numParts typically 1, use 2 for stereo ports - * @param name name that may be used in GUIs - * @param defaultValue - */ - public UnitInputPort(int numParts, String name, double defaultValue) { - super(numParts, name, defaultValue); - setDefault(defaultValue); - setValues = new double[numParts]; - for (int i = 0; i < numParts; i++) { - setValues[i] = defaultValue; - } - } - - public UnitInputPort(String name, double defaultValue) { - this(1, name, defaultValue); - } - - public UnitInputPort(String name) { - this(1, name, 0.0); - } - - public UnitInputPort(int numParts, String name) { - this(numParts, name, 0.0); - } - - @Override - protected void makeParts(int numParts, double defaultValue) { - parts = new InputMixingBlockPart[numParts]; - for (int i = 0; i < numParts; i++) { - parts[i] = new InputMixingBlockPart(this, defaultValue); - } - } - - /** - * This is used internally by the SynthesisEngine to execute units based on their connections. - * - * @param frameCount - * @param start - * @param limit - */ - @Override - public void pullData(long frameCount, int start, int limit) { - for (PortBlockPart part : parts) { - ((InputMixingBlockPart) part).pullData(frameCount, start, limit); - } - } - - @Override - protected void setValueInternal(int partNum, double value) { - super.setValueInternal(partNum, value); - setValues[partNum] = value; - } - - public void set(double value) { - set(0, value); - } - - public void set(final int partNum, final double value) { - // Trigger exception now if out of range. - setValues[partNum] = value; - queueCommand(new ScheduledCommand() { - @Override - public void run() { - setValueInternal(partNum, value); - } - }); - } - - public void set(double value, TimeStamp time) { - set(0, value, time); - } - - public void set(double value, double time) { - set(0, value, time); - } - - public void set(int partNum, double value, double time) { - set(partNum, value, new TimeStamp(time)); - } - - @Override - public void set(final int partNum, final double value, TimeStamp timeStamp) { - // Trigger exception now if out of range. - getValue(partNum); - scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - setValueInternal(partNum, value); - } - }); - } - - /** - * Value of a port based on the set() calls. Not affected by connected ports. - * - * @param partNum - * @return value as set - */ - @Override - public double get(int partNum) { - return setValues[partNum]; - } - - public double getMaximum() { - return maximum; - } - - /** - * The minimum and maximum are only used when setting up knobs or other control systems. The - * internal values are not clipped to this range. - * - * @param maximum - */ - public void setMaximum(double maximum) { - this.maximum = maximum; - } - - public double getMinimum() { - return minimum; - } - - public void setMinimum(double minimum) { - this.minimum = minimum; - } - - public double getDefault() { - return defaultValue; - } - - public void setDefault(double defaultValue) { - this.defaultValue = defaultValue; - } - - /** - * Convenience function for setting limits on a port. These limits are recommended values when - * setting up a GUI. It is possible to set a port to a value outside these limits. - * - * @param minimum - * @param value default value, will be clipped to min/max - * @param maximum - */ - public void setup(double minimum, double value, double maximum) { - setMinimum(minimum); - setMaximum(maximum); - setDefault(value); - set(value); - } - - // Grab min, max, default from another port. - public void setup(UnitInputPort other) { - setup(other.getMinimum(), other.getDefault(), other.getMaximum()); - } - - public boolean isValueAdded() { - return valueAdded; - } - - /** - * If set false then the set() value will be ignored when other ports are connected to this port. - * The sum of the connected port values will be used instead. - * - * If set true then the set() value will be added to the sum of the connected port values. - * This is useful when you want to modulate the set value. - * - * The default is false. - * - * @param valueAdded - */ - public void setValueAdded(boolean valueAdded) { - this.valueAdded = valueAdded; - } - - public void connect(int thisPartNum, UnitOutputPort otherPort, int otherPartNum, - TimeStamp timeStamp) { - otherPort.connect(otherPartNum, this, thisPartNum, timeStamp); - } - - /** Connect an input to an output port. */ - public void connect(int thisPartNum, UnitOutputPort otherPort, int otherPartNum) { - // Typically connections are made from output to input because it is - // more intuitive. - otherPort.connect(otherPartNum, this, thisPartNum); - } - - public void connect(UnitOutputPort otherPort) { - connect(0, otherPort, 0); - } - - @Override - public void connect(ConnectableOutput other) { - other.connect(this); - } - - public void disconnect(int thisPartNum, UnitOutputPort otherPort, int otherPartNum) { - otherPort.disconnect(otherPartNum, this, thisPartNum); - } - - @Override - public PortBlockPart getPortBlockPart() { - return parts[0]; - } - - public ConnectableInput getConnectablePart(int i) { - return parts[i]; - } - - @Override - public void disconnect(ConnectableOutput other) { - other.disconnect(this); - } - - public void printConnections(PrintStream out, int level) { - for (PortBlockPart part : parts) { - ((InputMixingBlockPart) part).printConnections(out, level); - } - } - -} diff --git a/src/com/jsyn/ports/UnitOutputPort.java b/src/com/jsyn/ports/UnitOutputPort.java deleted file mode 100644 index 6fcd758..0000000 --- a/src/com/jsyn/ports/UnitOutputPort.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.unitgen.UnitSink; -import com.softsynth.shared.time.TimeStamp; - -/** - * Units write to their output port blocks. Other multiple connected input ports read from them. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ - -public class UnitOutputPort extends UnitBlockPort implements ConnectableOutput, GettablePort { - public UnitOutputPort() { - this("Output"); - } - - public UnitOutputPort(String name) { - this(1, name, 0.0); - } - - public UnitOutputPort(int numParts, String name) { - this(numParts, name, 0.0); - } - - public UnitOutputPort(int numParts, String name, double defaultValue) { - super(numParts, name, defaultValue); - } - - public void flatten() { - for (PortBlockPart part : parts) { - part.flatten(); - } - } - - public void connect(int thisPartNum, UnitInputPort otherPort, int otherPartNum) { - PortBlockPart source = parts[thisPartNum]; - PortBlockPart destination = otherPort.parts[otherPartNum]; - source.connect(destination); - } - - public void connect(int thisPartNum, UnitInputPort otherPort, int otherPartNum, - TimeStamp timeStamp) { - PortBlockPart source = parts[thisPartNum]; - PortBlockPart destination = otherPort.parts[otherPartNum]; - source.connect(destination, timeStamp); - } - - public void connect(UnitInputPort input) { - connect(0, input, 0); - } - - @Override - public void connect(ConnectableInput input) { - parts[0].connect(input); - } - - public void connect(UnitSink sink) { - connect(0, sink.getInput(), 0); - } - - public void disconnect(int thisPartNum, UnitInputPort otherPort, int otherPartNum) { - PortBlockPart source = parts[thisPartNum]; - PortBlockPart destination = otherPort.parts[otherPartNum]; - source.disconnect(destination); - } - - public void disconnect(int thisPartNum, UnitInputPort otherPort, int otherPartNum, - TimeStamp timeStamp) { - PortBlockPart source = parts[thisPartNum]; - PortBlockPart destination = otherPort.parts[otherPartNum]; - source.disconnect(destination, timeStamp); - } - - public void disconnect(UnitInputPort otherPort) { - disconnect(0, otherPort, 0); - } - - @Override - public void disconnect(ConnectableInput input) { - parts[0].disconnect(input); - } - - public ConnectableOutput getConnectablePart(int i) { - return parts[i]; - } - -} diff --git a/src/com/jsyn/ports/UnitPort.java b/src/com/jsyn/ports/UnitPort.java deleted file mode 100644 index a652e68..0000000 --- a/src/com/jsyn/ports/UnitPort.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.engine.SynthesisEngine; -import com.jsyn.unitgen.UnitGenerator; -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -/** - * Basic audio port for JSyn unit generators. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class UnitPort { - private String name; - private UnitGenerator unit; - - public UnitPort(String name) { - this.name = name; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setUnitGenerator(UnitGenerator unit) { - // If a port is in a circuit then we want to just use the lower level - // unit that instantiated the circuit. - if (this.unit == null) { - this.unit = unit; - } - } - - public UnitGenerator getUnitGenerator() { - return unit; - } - - SynthesisEngine getSynthesisEngine() { - if (unit == null) { - return null; - } - return unit.getSynthesisEngine(); - } - - public int getNumParts() { - return 1; - } - - public void scheduleCommand(TimeStamp timeStamp, ScheduledCommand scheduledCommand) { - if (getSynthesisEngine() == null) { - scheduledCommand.run(); - } else { - getSynthesisEngine().scheduleCommand(timeStamp, scheduledCommand); - } - } - - public void queueCommand(ScheduledCommand scheduledCommand) { - if (getSynthesisEngine() == null) { - scheduledCommand.run(); - } else { - getSynthesisEngine().scheduleCommand(getSynthesisEngine().createTimeStamp(), - scheduledCommand); - } - } - -} diff --git a/src/com/jsyn/ports/UnitSpectralInputPort.java b/src/com/jsyn/ports/UnitSpectralInputPort.java deleted file mode 100644 index bdf0ff5..0000000 --- a/src/com/jsyn/ports/UnitSpectralInputPort.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.data.Spectrum; - -public class UnitSpectralInputPort extends UnitPort implements ConnectableInput { - private UnitSpectralOutputPort other; - - private Spectrum spectrum; - - public UnitSpectralInputPort() { - this("Output"); - } - - public UnitSpectralInputPort(String name) { - super(name); - } - - public void setSpectrum(Spectrum spectrum) { - this.spectrum = spectrum; - } - - public Spectrum getSpectrum() { - if (other == null) { - return spectrum; - } else { - return other.getSpectrum(); - } - } - - @Override - public void connect(ConnectableOutput other) { - if (other instanceof UnitSpectralOutputPort) { - this.other = (UnitSpectralOutputPort) other; - } else { - throw new RuntimeException( - "Can only connect UnitSpectralOutputPort to UnitSpectralInputPort!"); - } - } - - @Override - public void disconnect(ConnectableOutput other) { - if (this.other == other) { - this.other = null; - } - } - - @Override - public PortBlockPart getPortBlockPart() { - return null; - } - - @Override - public void pullData(long frameCount, int start, int limit) { - if (other != null) { - other.getUnitGenerator().pullData(frameCount, start, limit); - } - } - - public boolean isAvailable() { - if (other != null) { - return other.isAvailable(); - } else { - return (spectrum != null); - } - } - -} diff --git a/src/com/jsyn/ports/UnitSpectralOutputPort.java b/src/com/jsyn/ports/UnitSpectralOutputPort.java deleted file mode 100644 index 51633ce..0000000 --- a/src/com/jsyn/ports/UnitSpectralOutputPort.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.jsyn.data.Spectrum; - -public class UnitSpectralOutputPort extends UnitPort implements ConnectableOutput { - private Spectrum spectrum; - private boolean available; - - public UnitSpectralOutputPort() { - this("Output"); - } - - public UnitSpectralOutputPort(int size) { - this("Output", size); - } - - public UnitSpectralOutputPort(String name) { - super(name); - spectrum = new Spectrum(); - } - - public UnitSpectralOutputPort(String name, int size) { - super(name); - spectrum = new Spectrum(size); - } - - public void setSize(int size) { - spectrum.setSize(size); - } - - public Spectrum getSpectrum() { - return spectrum; - } - - public void advance() { - available = true; - } - - @Override - public void connect(ConnectableInput other) { - other.connect(this); - } - - @Override - public void disconnect(ConnectableInput other) { - other.disconnect(this); - } - - public boolean isAvailable() { - return available; - } - -} diff --git a/src/com/jsyn/ports/UnitVariablePort.java b/src/com/jsyn/ports/UnitVariablePort.java deleted file mode 100644 index 60b64fd..0000000 --- a/src/com/jsyn/ports/UnitVariablePort.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2009 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.ports; - -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -public class UnitVariablePort extends UnitPort implements SettablePort { - private double value; - - public UnitVariablePort(String name, double defaultValue) { - super(name); - value = defaultValue; - } - - public UnitVariablePort(String name) { - super(name); - } - - public void setValue(double value) { - this.value = value; - } - - public void set(double value) { - this.value = value; - } - - public double get() { - return value; - } - - public double getValue() { - return value; - } - - @Override - public double getValue(int partNum) { - return value; - } - - @Override - public void set(int partNum, final double value, TimeStamp timeStamp) { - scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - set(value); - } - }); - } -} diff --git a/src/com/jsyn/ports/package.html b/src/com/jsyn/ports/package.html deleted file mode 100644 index 3547618..0000000 --- a/src/com/jsyn/ports/package.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<title>JSyn Ports</title> -</head> -<body> -<p>Ports are used to pass audio data in and out of UnitGenerators. -They can also be used to connect UnitGenerators together so that signals can flow between them. -The UnitDataQueuePort contains a FIFO that will accept envelope and sample data. -</p> -</body> -</html>
\ No newline at end of file diff --git a/src/com/jsyn/scope/AudioScope.java b/src/com/jsyn/scope/AudioScope.java deleted file mode 100644 index 7b2a98c..0000000 --- a/src/com/jsyn/scope/AudioScope.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.scope; - -import com.jsyn.Synthesizer; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.scope.swing.AudioScopeView; - -// TODO Auto and Manual triggers. -// TODO Auto scaling of vertical. -// TODO Fixed size Y scale knobs. -// TODO Pan back and forth around trigger. -// TODO Continuous capture -/** - * Digital oscilloscope for JSyn. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class AudioScope { - public enum TriggerMode { - AUTO, NORMAL // , MANUAL - } - - public enum ViewMode { - WAVEFORM, SPECTRUM - } - - private AudioScopeView audioScopeView = null; - private AudioScopeModel audioScopeModel; - - public AudioScope(Synthesizer synth) { - audioScopeModel = new AudioScopeModel(synth); - } - - public AudioScopeProbe addProbe(UnitOutputPort output) { - return addProbe(output, 0); - } - - public AudioScopeProbe addProbe(UnitOutputPort output, int partIndex) { - return audioScopeModel.addProbe(output, partIndex); - } - - public void start() { - audioScopeModel.start(); - } - - public void stop() { - audioScopeModel.stop(); - } - - public AudioScopeModel getModel() { - return audioScopeModel; - } - - public AudioScopeView getView() { - if (audioScopeView == null) { - audioScopeView = new AudioScopeView(); - audioScopeView.setModel(audioScopeModel); - } - return audioScopeView; - } - - public void setTriggerMode(TriggerMode triggerMode) { - audioScopeModel.setTriggerMode(triggerMode); - } - - public void setTriggerSource(AudioScopeProbe probe) { - audioScopeModel.setTriggerSource(probe); - } - - public void setTriggerLevel(double level) { - getModel().getTriggerModel().getLevelModel().setDoubleValue(level); - } - - public double getTriggerLevel() { - return getModel().getTriggerModel().getLevelModel().getDoubleValue(); - } - - /** - * Not yet implemented. - * @param viewMode - */ - public void setViewMode(ViewMode viewMode) { - // TODO Auto-generated method stub - } - -} diff --git a/src/com/jsyn/scope/AudioScopeModel.java b/src/com/jsyn/scope/AudioScopeModel.java deleted file mode 100644 index 85c4413..0000000 --- a/src/com/jsyn/scope/AudioScopeModel.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2009 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.scope; - -import java.util.ArrayList; -import java.util.concurrent.CopyOnWriteArrayList; - -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.jsyn.Synthesizer; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.scope.AudioScope.TriggerMode; - -public class AudioScopeModel implements Runnable { - private static final int PRE_TRIGGER_SIZE = 32; - private Synthesizer synthesisEngine; - private ArrayList<AudioScopeProbe> probes = new ArrayList<AudioScopeProbe>(); - private CopyOnWriteArrayList<ChangeListener> changeListeners = new CopyOnWriteArrayList<ChangeListener>(); - private MultiChannelScopeProbeUnit probeUnit; - private double timeToArm; - private double period = 0.2; - private TriggerModel triggerModel; - - public AudioScopeModel(Synthesizer synth) { - this.synthesisEngine = synth; - triggerModel = new TriggerModel(); - } - - public AudioScopeProbe addProbe(UnitOutputPort output, int partIndex) { - AudioScopeProbe probe = new AudioScopeProbe(this, output, partIndex); - DefaultWaveTraceModel waveTraceModel = new DefaultWaveTraceModel(this, probes.size()); - probe.setWaveTraceModel(waveTraceModel); - probes.add(probe); - if (triggerModel.getSource() == null) { - triggerModel.setSource(probe); - } - return probe; - } - - public void start() { - stop(); - probeUnit = new MultiChannelScopeProbeUnit(probes.size(), triggerModel); - synthesisEngine.add(probeUnit); - for (int i = 0; i < probes.size(); i++) { - AudioScopeProbe probe = probes.get(i); - probe.getSource().connect(probe.getPartIndex(), probeUnit.input, i); - } - // Connect trigger signal to input of probe. - triggerModel.getSource().getSource() - .connect(triggerModel.getSource().getPartIndex(), probeUnit.trigger, 0); - probeUnit.start(); - - // Get synthesizer time in seconds. - timeToArm = synthesisEngine.getCurrentTime(); - probeUnit.arm(timeToArm, this); - } - - public void stop() { - if (probeUnit != null) { - for (int i = 0; i < probes.size(); i++) { - probeUnit.input.disconnectAll(i); - } - probeUnit.trigger.disconnectAll(); - probeUnit.stop(); - synthesisEngine.remove(probeUnit); - probeUnit = null; - } - } - - public AudioScopeProbe[] getProbes() { - return probes.toArray(new AudioScopeProbe[0]); - } - - public Synthesizer getSynthesizer() { - return synthesisEngine; - } - - @Override - public void run() { - fireChangeListeners(); - timeToArm = synthesisEngine.getCurrentTime(); - timeToArm += period; - probeUnit.arm(timeToArm, this); - } - - private void fireChangeListeners() { - ChangeEvent changeEvent = new ChangeEvent(this); - for (ChangeListener listener : changeListeners) { - listener.stateChanged(changeEvent); - } - // debug(); - } - - public void addChangeListener(ChangeListener changeListener) { - changeListeners.add(changeListener); - } - - public void removeChangeListener(ChangeListener changeListener) { - changeListeners.remove(changeListener); - } - - public void setTriggerMode(TriggerMode triggerMode) { - triggerModel.getModeModel().setSelectedItem(triggerMode); - } - - public void setTriggerSource(AudioScopeProbe probe) { - triggerModel.setSource(probe); - } - - public double getSample(int bufferIndex, int i) { - return probeUnit.getSample(bufferIndex, i); - } - - public int getFramesPerBuffer() { - return probeUnit.getFramesPerBuffer(); - } - - public int getFramesCaptured() { - return probeUnit.getFramesCaptured(); - } - - public int getVisibleSize() { - int size = 0; - if (probeUnit != null) { - size = probeUnit.getPostTriggerSize() + PRE_TRIGGER_SIZE; - if (size > getFramesCaptured()) { - size = getFramesCaptured(); - } - } - return size; - } - - public int getStartIndex() { - // TODO Add pan support here. - return getFramesCaptured() - getVisibleSize(); - } - - public TriggerModel getTriggerModel() { - return triggerModel; - } - -} diff --git a/src/com/jsyn/scope/AudioScopeProbe.java b/src/com/jsyn/scope/AudioScopeProbe.java deleted file mode 100644 index f1aad65..0000000 --- a/src/com/jsyn/scope/AudioScopeProbe.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.scope; - -import java.awt.Color; - -import javax.swing.JToggleButton.ToggleButtonModel; - -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.swing.ExponentialRangeModel; - -/** - * Collect data from the source and make it available to the scope. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class AudioScopeProbe { - // private UnitOutputPort output; - private WaveTraceModel waveTraceModel; - private AudioScopeModel audioScopeModel; - private UnitOutputPort source; - private int partIndex; - private Color color; - private ExponentialRangeModel verticalScaleModel; - private ToggleButtonModel autoScaleButtonModel; - private double MIN_RANGE = 0.01; - private double MAX_RANGE = 100.0; - - public AudioScopeProbe(AudioScopeModel audioScopeModel, UnitOutputPort source, int partIndex) { - this.audioScopeModel = audioScopeModel; - this.source = source; - this.partIndex = partIndex; - - verticalScaleModel = new ExponentialRangeModel("VScale", 1000, MIN_RANGE, MAX_RANGE, - MIN_RANGE); - autoScaleButtonModel = new ToggleButtonModel(); - autoScaleButtonModel.setSelected(true); - } - - public WaveTraceModel getWaveTraceModel() { - return waveTraceModel; - } - - public void setWaveTraceModel(WaveTraceModel waveTraceModel) { - this.waveTraceModel = waveTraceModel; - } - - public UnitOutputPort getSource() { - return source; - } - - public int getPartIndex() { - return partIndex; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public void setAutoScaleEnabled(boolean enabled) { - autoScaleButtonModel.setSelected(enabled); - } - - public void setVerticalScale(double max) { - verticalScaleModel.setDoubleValue(max); - } - - public ExponentialRangeModel getVerticalScaleModel() { - return verticalScaleModel; - } - - public ToggleButtonModel getAutoScaleButtonModel() { - return autoScaleButtonModel; - } - -} diff --git a/src/com/jsyn/scope/DefaultWaveTraceModel.java b/src/com/jsyn/scope/DefaultWaveTraceModel.java deleted file mode 100644 index a123c0b..0000000 --- a/src/com/jsyn/scope/DefaultWaveTraceModel.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2009 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.scope; - -public class DefaultWaveTraceModel implements WaveTraceModel { - private AudioScopeModel audioScopeModel; - private int bufferIndex; - - public DefaultWaveTraceModel(AudioScopeModel audioScopeModel, int bufferIndex) { - this.audioScopeModel = audioScopeModel; - this.bufferIndex = bufferIndex; - } - - @Override - public double getSample(int i) { - return audioScopeModel.getSample(bufferIndex, i); - } - - @Override - public int getSize() { - return audioScopeModel.getFramesCaptured(); - } - - @Override - public int getStartIndex() { - return audioScopeModel.getStartIndex(); - } - - @Override - public int getVisibleSize() { - return audioScopeModel.getVisibleSize(); - } - -} diff --git a/src/com/jsyn/scope/MultiChannelScopeProbeUnit.java b/src/com/jsyn/scope/MultiChannelScopeProbeUnit.java deleted file mode 100644 index 5be19f0..0000000 --- a/src/com/jsyn/scope/MultiChannelScopeProbeUnit.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2009 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.scope; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.scope.AudioScope.TriggerMode; -import com.jsyn.unitgen.UnitGenerator; -import com.softsynth.shared.time.ScheduledCommand; - -/** - * Multi-channel scope probe with an independent trigger input. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class MultiChannelScopeProbeUnit extends UnitGenerator { - // Signal that is captured. - public UnitInputPort input; - // Signal that triggers the probe. - public UnitInputPort trigger; - - // I am using ints instead of an enum for performance reasons. - private static final int STATE_IDLE = 0; - private static final int STATE_ARMED = 1; - private static final int STATE_READY = 2; - private static final int STATE_TRIGGERED = 3; - private int state = STATE_IDLE; - - private int numChannels; - private double[][] inputValues; - private static final int FRAMES_PER_BUFFER = 4096; // must be power of two - private static final int FRAMES_PER_BUFFER_MASK = FRAMES_PER_BUFFER - 1; - private Runnable callback; - - private TriggerModel triggerModel; - private int autoCountdown; - private int countdown; - private int postTriggerSize = 512; - SignalBuffer captureBuffer; - SignalBuffer displayBuffer; - - // Use double buffers. One for capture, one for display. - class SignalBuffer { - float[][] buffers; - private int writeCursor; - private int triggerIndex; - private int framesCaptured; - - SignalBuffer(int numChannels) { - buffers = new float[numChannels][]; - for (int j = 0; j < numChannels; j++) { - buffers[j] = new float[FRAMES_PER_BUFFER]; - } - } - - void reset() { - writeCursor = 0; - triggerIndex = 0; - framesCaptured = 0; - } - - public void saveChannelValue(int j, float value) { - buffers[j][writeCursor] = value; - } - - public void markTrigger() { - triggerIndex = writeCursor; - } - - public void bumpCursor() { - writeCursor = (writeCursor + 1) & FRAMES_PER_BUFFER_MASK; - if (writeCursor >= FRAMES_PER_BUFFER) { - writeCursor = 0; - } - if (framesCaptured < FRAMES_PER_BUFFER) { - framesCaptured += 1; - } - } - - private int convertInternalToExternalIndex(int internalIndex) { - if (framesCaptured < FRAMES_PER_BUFFER) { - return internalIndex; - } else { - return (internalIndex - writeCursor) & (FRAMES_PER_BUFFER_MASK); - } - } - - private int convertExternalToInternalIndex(int externalIndex) { - if (framesCaptured < FRAMES_PER_BUFFER) { - return externalIndex; - } else { - return (externalIndex + writeCursor) & (FRAMES_PER_BUFFER_MASK); - } - } - - public int getTriggerIndex() { - return convertInternalToExternalIndex(triggerIndex); - } - - public int getFramesCaptured() { - return framesCaptured; - } - - public float getSample(int bufferIndex, int sampleIndex) { - int index = convertExternalToInternalIndex(sampleIndex); - return buffers[bufferIndex][index]; - } - } - - public MultiChannelScopeProbeUnit(int numChannels, TriggerModel triggerModel) { - this.numChannels = numChannels; - captureBuffer = new SignalBuffer(numChannels); - displayBuffer = new SignalBuffer(numChannels); - this.triggerModel = triggerModel; - addPort(trigger = new UnitInputPort(numChannels, "Trigger")); - addPort(input = new UnitInputPort(numChannels, "Input")); - inputValues = new double[numChannels][]; - } - - private synchronized void switchBuffers() { - SignalBuffer temp = captureBuffer; - captureBuffer = displayBuffer; - displayBuffer = temp; - } - - private void internalArm(Runnable callback) { - this.callback = callback; - state = STATE_ARMED; - captureBuffer.reset(); - } - - class ScheduledArm implements ScheduledCommand { - private Runnable callback; - - ScheduledArm(Runnable callback) { - this.callback = callback; - } - - @Override - public void run() { - internalArm(this.callback); - } - } - - /** Arm the probe at a future time. */ - public void arm(double time, Runnable callback) { - ScheduledArm command = new ScheduledArm(callback); - getSynthesisEngine().scheduleCommand(time, command); - } - - @Override - public void generate(int start, int limit) { - if (state != STATE_IDLE) { - TriggerMode triggerMode = triggerModel.getMode(); - double triggerLevel = triggerModel.getTriggerLevel(); - double[] triggerValues = trigger.getValues(); - - for (int j = 0; j < numChannels; j++) { - inputValues[j] = input.getValues(j); - } - - for (int i = start; i < limit; i++) { - // Capture one sample from each channel. - for (int j = 0; j < numChannels; j++) { - captureBuffer.saveChannelValue(j, (float) inputValues[j][i]); - } - captureBuffer.bumpCursor(); - - switch (state) { - case STATE_ARMED: - if (triggerValues[i] <= triggerLevel) { - state = STATE_READY; - autoCountdown = 44100; - } - break; - - case STATE_READY: { - boolean triggered = false; - if (triggerValues[i] > triggerLevel) { - triggered = true; - } else if (triggerMode.equals(TriggerMode.AUTO)) { - if (--autoCountdown == 0) { - triggered = true; - } - } - if (triggered) { - captureBuffer.markTrigger(); - state = STATE_TRIGGERED; - countdown = postTriggerSize; - } - } - break; - - case STATE_TRIGGERED: - countdown -= 1; - if (countdown <= 0) { - state = STATE_IDLE; - switchBuffers(); - fireCallback(); - } - break; - } - } - } - } - - private void fireCallback() { - if (callback != null) { - callback.run(); - } - } - - public float getSample(int bufferIndex, int sampleIndex) { - return displayBuffer.getSample(bufferIndex, sampleIndex); - } - - public int getTriggerIndex() { - return displayBuffer.getTriggerIndex(); - } - - public int getFramesCaptured() { - return displayBuffer.getFramesCaptured(); - } - - public int getFramesPerBuffer() { - return FRAMES_PER_BUFFER; - } - - public int getPostTriggerSize() { - return postTriggerSize; - } - -} diff --git a/src/com/jsyn/scope/TriggerModel.java b/src/com/jsyn/scope/TriggerModel.java deleted file mode 100644 index 0367d71..0000000 --- a/src/com/jsyn/scope/TriggerModel.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2009 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.scope; - -import javax.swing.DefaultComboBoxModel; - -import com.jsyn.scope.AudioScope.TriggerMode; -import com.jsyn.swing.ExponentialRangeModel; - -public class TriggerModel { - private ExponentialRangeModel levelModel; - private DefaultComboBoxModel<AudioScope.TriggerMode> modeModel; - private AudioScopeProbe source; - - public TriggerModel() { - modeModel = new DefaultComboBoxModel<AudioScope.TriggerMode>(); - modeModel.addElement(TriggerMode.AUTO); - modeModel.addElement(TriggerMode.NORMAL); - levelModel = new ExponentialRangeModel("TriggerLevel", 1000, 0.01, 2.0, 0.04); - } - - public AudioScopeProbe getSource() { - return source; - } - - public void setSource(AudioScopeProbe source) { - this.source = source; - } - - public ExponentialRangeModel getLevelModel() { - return levelModel; - } - - public void setLevelModel(ExponentialRangeModel levelModel) { - this.levelModel = levelModel; - } - - public DefaultComboBoxModel<TriggerMode> getModeModel() { - return modeModel; - } - - public void setModeModel(DefaultComboBoxModel<TriggerMode> modeModel) { - this.modeModel = modeModel; - } - - public double getTriggerLevel() { - return levelModel.getDoubleValue(); - } - - public TriggerMode getMode() { - return (TriggerMode) modeModel.getSelectedItem(); - } -} diff --git a/src/com/jsyn/scope/WaveTraceModel.java b/src/com/jsyn/scope/WaveTraceModel.java deleted file mode 100644 index e9d8bf9..0000000 --- a/src/com/jsyn/scope/WaveTraceModel.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2009 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.scope; - -public interface WaveTraceModel { - int getSize(); - - int getVisibleSize(); - - int getStartIndex(); - - double getSample(int i); -} diff --git a/src/com/jsyn/scope/swing/AudioScopeProbeView.java b/src/com/jsyn/scope/swing/AudioScopeProbeView.java deleted file mode 100644 index 59526e1..0000000 --- a/src/com/jsyn/scope/swing/AudioScopeProbeView.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.scope.swing; - -import com.jsyn.scope.AudioScopeProbe; - -/** - * Wave display associated with a probe. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class AudioScopeProbeView { - private AudioScopeProbe probeModel; - private WaveTraceView waveTrace; - - public AudioScopeProbeView(AudioScopeProbe probeModel) { - this.probeModel = probeModel; - waveTrace = new WaveTraceView(probeModel.getAutoScaleButtonModel(), - probeModel.getVerticalScaleModel()); - waveTrace.setModel(probeModel.getWaveTraceModel()); - } - - public WaveTraceView getWaveTraceView() { - return waveTrace; - } - - public AudioScopeProbe getModel() { - return probeModel; - } - -} diff --git a/src/com/jsyn/scope/swing/AudioScopeView.java b/src/com/jsyn/scope/swing/AudioScopeView.java deleted file mode 100644 index ec1afa3..0000000 --- a/src/com/jsyn/scope/swing/AudioScopeView.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2009 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.scope.swing; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.util.ArrayList; - -import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.jsyn.scope.AudioScopeModel; -import com.jsyn.scope.AudioScopeProbe; - -public class AudioScopeView extends JPanel { - private static final long serialVersionUID = -7507986850757860853L; - private AudioScopeModel audioScopeModel; - private ArrayList<AudioScopeProbeView> probeViews = new ArrayList<AudioScopeProbeView>(); - private MultipleWaveDisplay multipleWaveDisplay; - private boolean showControls = false; - private ScopeControlPanel controlPanel = null; - - public AudioScopeView() { - setBackground(Color.GREEN); - } - - public void setModel(AudioScopeModel audioScopeModel) { - this.audioScopeModel = audioScopeModel; - // Create a view for each probe. - probeViews.clear(); - for (AudioScopeProbe probeModel : audioScopeModel.getProbes()) { - AudioScopeProbeView audioScopeProbeView = new AudioScopeProbeView(probeModel); - probeViews.add(audioScopeProbeView); - } - setupGUI(); - - // Listener for signal change events. - audioScopeModel.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - multipleWaveDisplay.repaint(); - } - }); - - } - - private void setupGUI() { - removeAll(); - setLayout(new BorderLayout()); - multipleWaveDisplay = new MultipleWaveDisplay(); - - for (AudioScopeProbeView probeView : probeViews) { - multipleWaveDisplay.addWaveTrace(probeView.getWaveTraceView()); - probeView.getModel().setColor(probeView.getWaveTraceView().getColor()); - } - - add(multipleWaveDisplay, BorderLayout.CENTER); - - setMinimumSize(new Dimension(400, 200)); - setPreferredSize(new Dimension(600, 250)); - setMaximumSize(new Dimension(1200, 300)); - } - - /** @deprecated Use setControlsVisible() instead. */ - @Deprecated - public void setShowControls(boolean show) { - setControlsVisible(show); - } - - public void setControlsVisible(boolean show) { - if (this.showControls) { - if (!show && (controlPanel != null)) { - remove(controlPanel); - } - } else { - if (show) { - if (controlPanel == null) { - controlPanel = new ScopeControlPanel(this); - } - add(controlPanel, BorderLayout.EAST); - validate(); - } - } - - this.showControls = show; - } - - public AudioScopeModel getModel() { - return audioScopeModel; - } - - public AudioScopeProbeView[] getProbeViews() { - return probeViews.toArray(new AudioScopeProbeView[0]); - } - -} diff --git a/src/com/jsyn/scope/swing/MultipleWaveDisplay.java b/src/com/jsyn/scope/swing/MultipleWaveDisplay.java deleted file mode 100644 index 0259850..0000000 --- a/src/com/jsyn/scope/swing/MultipleWaveDisplay.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.scope.swing; - -import java.awt.Color; -import java.awt.Graphics; -import java.util.ArrayList; - -import javax.swing.JPanel; - -/** - * Display multiple waveforms together in different colors. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class MultipleWaveDisplay extends JPanel { - private static final long serialVersionUID = -5157397030540800373L; - - private ArrayList<WaveTraceView> waveTraceViews = new ArrayList<WaveTraceView>(); - private Color[] defaultColors = { - Color.BLUE, Color.RED, Color.BLACK, Color.MAGENTA, Color.GREEN, Color.ORANGE - }; - - public MultipleWaveDisplay() { - setBackground(Color.WHITE); - } - - public void addWaveTrace(WaveTraceView waveTraceView) { - if (waveTraceView.getColor() == null) { - waveTraceView.setColor(defaultColors[waveTraceViews.size() % defaultColors.length]); - } - waveTraceViews.add(waveTraceView); - } - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - int width = getWidth(); - int height = getHeight(); - for (WaveTraceView waveTraceView : waveTraceViews.toArray(new WaveTraceView[0])) { - waveTraceView.drawWave(g, width, height); - } - } -} diff --git a/src/com/jsyn/scope/swing/ScopeControlPanel.java b/src/com/jsyn/scope/swing/ScopeControlPanel.java deleted file mode 100644 index 7f3a026..0000000 --- a/src/com/jsyn/scope/swing/ScopeControlPanel.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2009 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.scope.swing; - -import java.awt.GridLayout; - -import javax.swing.JPanel; - -import com.jsyn.scope.AudioScopeModel; - -public class ScopeControlPanel extends JPanel { - private static final long serialVersionUID = 7738305116057614812L; - private AudioScopeModel audioScopeModel; - private ScopeTriggerPanel triggerPanel; - private JPanel probeRows; - - public ScopeControlPanel(AudioScopeView audioScopeView) { - setLayout(new GridLayout(0, 1)); - this.audioScopeModel = audioScopeView.getModel(); - triggerPanel = new ScopeTriggerPanel(audioScopeModel); - add(triggerPanel); - - probeRows = new JPanel(); - probeRows.setLayout(new GridLayout(1, 0)); - add(probeRows); - for (AudioScopeProbeView probeView : audioScopeView.getProbeViews()) { - ScopeProbePanel probePanel = new ScopeProbePanel(probeView); - probeRows.add(probePanel); - } - } - -} diff --git a/src/com/jsyn/scope/swing/ScopeProbePanel.java b/src/com/jsyn/scope/swing/ScopeProbePanel.java deleted file mode 100644 index 9cb82af..0000000 --- a/src/com/jsyn/scope/swing/ScopeProbePanel.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2009 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.scope.swing; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.BorderFactory; -import javax.swing.JCheckBox; -import javax.swing.JPanel; -import javax.swing.JToggleButton.ToggleButtonModel; - -import com.jsyn.scope.AudioScopeProbe; -import com.jsyn.swing.RotaryTextController; - -public class ScopeProbePanel extends JPanel { - private static final long serialVersionUID = 4511589171299298548L; - private AudioScopeProbeView audioScopeProbeView; - private AudioScopeProbe audioScopeProbe; - private RotaryTextController verticalScaleKnob; - private JCheckBox autoBox; - private ToggleButtonModel autoScaleModel; - - public ScopeProbePanel(AudioScopeProbeView probeView) { - this.audioScopeProbeView = probeView; - setLayout(new BorderLayout()); - - setBorder(BorderFactory.createLineBorder(Color.GRAY, 3)); - - // Add a colored box to match the waveform color. - JPanel colorPanel = new JPanel(); - colorPanel.setMinimumSize(new Dimension(40, 40)); - audioScopeProbe = probeView.getModel(); - colorPanel.setBackground(audioScopeProbe.getColor()); - add(colorPanel, BorderLayout.NORTH); - - // Knob for tweaking vertical range. - verticalScaleKnob = new RotaryTextController(audioScopeProbeView.getWaveTraceView() - .getVerticalRangeModel(), 5); - add(verticalScaleKnob, BorderLayout.CENTER); - verticalScaleKnob.setTitle("YScale"); - - // Auto ranging checkbox. - autoBox = new JCheckBox("Auto"); - autoScaleModel = audioScopeProbeView.getWaveTraceView().getAutoButtonModel(); - autoScaleModel.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ToggleButtonModel model = (ToggleButtonModel) e.getSource(); - boolean enabled = !model.isSelected(); - System.out.println("Knob enabled = " + enabled); - verticalScaleKnob.setEnabled(!model.isSelected()); - } - }); - autoBox.setModel(autoScaleModel); - add(autoBox, BorderLayout.SOUTH); - - verticalScaleKnob.setEnabled(!autoScaleModel.isSelected()); - - setMinimumSize(new Dimension(80, 100)); - setPreferredSize(new Dimension(80, 150)); - setMaximumSize(new Dimension(120, 200)); - } - -} diff --git a/src/com/jsyn/scope/swing/ScopeTriggerPanel.java b/src/com/jsyn/scope/swing/ScopeTriggerPanel.java deleted file mode 100644 index 9c22aa1..0000000 --- a/src/com/jsyn/scope/swing/ScopeTriggerPanel.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2009 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.scope.swing; - -import java.awt.BorderLayout; - -import javax.swing.DefaultComboBoxModel; -import javax.swing.JComboBox; -import javax.swing.JPanel; - -import com.jsyn.scope.AudioScopeModel; -import com.jsyn.scope.TriggerModel; -import com.jsyn.scope.AudioScope.TriggerMode; -import com.jsyn.swing.RotaryTextController; - -public class ScopeTriggerPanel extends JPanel { - private static final long serialVersionUID = 4511589171299298548L; - private JComboBox<DefaultComboBoxModel<TriggerMode>> triggerModeComboBox; - private RotaryTextController triggerLevelKnob; - - public ScopeTriggerPanel(AudioScopeModel audioScopeModel) { - setLayout(new BorderLayout()); - TriggerModel triggerModel = audioScopeModel.getTriggerModel(); - triggerModeComboBox = new JComboBox(triggerModel.getModeModel()); - add(triggerModeComboBox, BorderLayout.NORTH); - - triggerLevelKnob = new RotaryTextController(triggerModel.getLevelModel(), 5); - - add(triggerLevelKnob, BorderLayout.CENTER); - triggerLevelKnob.setTitle("Trigger Level"); - } - -} diff --git a/src/com/jsyn/scope/swing/WaveTraceView.java b/src/com/jsyn/scope/swing/WaveTraceView.java deleted file mode 100644 index 849a6f4..0000000 --- a/src/com/jsyn/scope/swing/WaveTraceView.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2009 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.scope.swing; - -import java.awt.Color; -import java.awt.Graphics; - -import javax.swing.JToggleButton.ToggleButtonModel; - -import com.jsyn.scope.WaveTraceModel; -import com.jsyn.swing.ExponentialRangeModel; - -public class WaveTraceView { - private static final double AUTO_DECAY = 0.95; - private WaveTraceModel waveTraceModel; - private Color color; - private ExponentialRangeModel verticalScaleModel; - private ToggleButtonModel autoScaleButtonModel; - - private double xScaler; - private double yScalar; - private int centerY; - - public WaveTraceView(ToggleButtonModel autoButtonModel, ExponentialRangeModel verticalRangeModel) { - this.verticalScaleModel = verticalRangeModel; - this.autoScaleButtonModel = autoButtonModel; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public ExponentialRangeModel getVerticalRangeModel() { - return verticalScaleModel; - } - - public ToggleButtonModel getAutoButtonModel() { - return autoScaleButtonModel; - } - - public void setModel(WaveTraceModel waveTraceModel) { - this.waveTraceModel = waveTraceModel; - } - - public int convertRealToY(double r) { - return centerY - (int) (yScalar * r); - } - - public void drawWave(Graphics g, int width, int height) { - double sampleMax = 0.0; - double sampleMin = 0.0; - g.setColor(color); - int numSamples = waveTraceModel.getVisibleSize(); - if (numSamples > 0) { - xScaler = (double) width / numSamples; - // Scale by 0.5 because it is bipolar. - yScalar = 0.5 * height / verticalScaleModel.getDoubleValue(); - centerY = height / 2; - - // Calculate position of first point. - int x1 = 0; - int offset = waveTraceModel.getStartIndex(); - double value = waveTraceModel.getSample(offset); - int y1 = convertRealToY(value); - - // Draw lines to remaining points. - for (int i = 1; i < numSamples; i++) { - int x2 = (int) (i * xScaler); - value = waveTraceModel.getSample(offset + i); - int y2 = convertRealToY(value); - g.drawLine(x1, y1, x2, y2); - x1 = x2; - y1 = y2; - // measure min and max for auto - if (value > sampleMax) { - sampleMax = value; - } else if (value < sampleMin) { - sampleMin = value; - } - } - - autoScaleRange(sampleMax); - } - } - - // Autoscale the vertical range. - private void autoScaleRange(double sampleMax) { - if (autoScaleButtonModel.isSelected()) { - double scaledMax = sampleMax * 1.1; - double current = verticalScaleModel.getDoubleValue(); - if (scaledMax > current) { - verticalScaleModel.setDoubleValue(scaledMax); - } else { - double decayed = current * AUTO_DECAY; - if (decayed > verticalScaleModel.getMinimum()) { - if (scaledMax < decayed) { - verticalScaleModel.setDoubleValue(decayed); - } - } - } - } - } - -} diff --git a/src/com/jsyn/swing/ASCIIMusicKeyboard.java b/src/com/jsyn/swing/ASCIIMusicKeyboard.java deleted file mode 100644 index f1379d8..0000000 --- a/src/com/jsyn/swing/ASCIIMusicKeyboard.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2012 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.swing; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.util.HashSet; - -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; - -/** - * Support for playing musical scales on the ASCII keyboard of a computer. Has a Sustain checkbox - * that simulates a sustain pedal. Auto-repeat keys are detected and suppressed. - * - * @author Phil Burk (C) 2012 Mobileer Inc - */ -@SuppressWarnings("serial") -public abstract class ASCIIMusicKeyboard extends JPanel { - private final JCheckBox sustainBox; - private final JButton focusButton; - public static final String PENTATONIC_KEYS = "zxcvbasdfgqwert12345"; - public static final String SEPTATONIC_KEYS = "zxcvbnmasdfghjqwertyu1234567890"; - private String keyboardLayout = SEPTATONIC_KEYS; /* default music keyboard layout */ - private int basePitch = 48; - private final KeyListener keyListener; - private final JLabel countLabel; - private int onCount; - private int offCount; - private int pressedCount; - private int releasedCount; - private final HashSet<Integer> pressedKeys = new HashSet<Integer>(); - private final HashSet<Integer> onKeys = new HashSet<Integer>(); - - public ASCIIMusicKeyboard() { - focusButton = new JButton("Click here to play ASCII keys."); - focusButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - } - }); - keyListener = new KeyListener() { - - @Override - public void keyPressed(KeyEvent e) { - int key = e.getKeyChar(); - int idx = keyboardLayout.indexOf(key); - System.out.println("keyPressed " + idx); - if (idx >= 0) { - if (!pressedKeys.contains(idx)) { - keyOn(convertIndexToPitch(idx)); - onCount++; - pressedKeys.add(idx); - onKeys.add(idx); - } - } - pressedCount++; - updateCountLabel(); - } - - @Override - public void keyReleased(KeyEvent e) { - int key = e.getKeyChar(); - int idx = keyboardLayout.indexOf(key); - System.out.println("keyReleased " + idx); - if (idx >= 0) { - if (!sustainBox.isSelected()) { - noteOffInternal(idx); - onKeys.remove(idx); - } - pressedKeys.remove(idx); - } - releasedCount++; - updateCountLabel(); - } - - @Override - public void keyTyped(KeyEvent arg0) { - } - }; - focusButton.addKeyListener(keyListener); - add(focusButton); - - sustainBox = new JCheckBox("sustain"); - sustainBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - if (!sustainBox.isSelected()) { - for (Integer noteIndex : onKeys) { - noteOffInternal(noteIndex); - } - onKeys.clear(); - } - } - }); - add(sustainBox); - sustainBox.addKeyListener(keyListener); - - countLabel = new JLabel("0"); - add(countLabel); - } - - private void noteOffInternal(int idx) { - keyOff(convertIndexToPitch(idx)); - offCount++; - } - - protected void updateCountLabel() { - countLabel.setText(onCount + "/" + offCount + ", " + pressedCount + "/" + releasedCount); - } - - /** - * Convert index to a MIDI noteNumber in a major scale. Result will be offset by the basePitch. - */ - public int convertIndexToPitch(int keyIndex) { - int scale[] = { - 0, 2, 4, 5, 7, 9, 11 - }; - int octave = keyIndex / scale.length; - int idx = keyIndex % scale.length; - int pitch = (octave * 12) + scale[idx]; - return pitch + basePitch; - } - - /** - * This will be called when a key is released. It may also be called for sustaining notes when - * the Sustain check box is turned off. - * - * @param keyIndex - */ - public abstract void keyOff(int keyIndex); - - /** - * This will be called when a key is pressed. - * - * @param keyIndex - */ - public abstract void keyOn(int keyIndex); - - public String getKeyboardLayout() { - return keyboardLayout; - } - - /** - * Specify the keys that will be active for music. - * For example "qwertyui". - * If the first character in the layout is - * pressed then keyOn() will be called with 0. Default is SEPTATONIC_KEYS. - * - * @param keyboardLayout defines order of playable keys - */ - public void setKeyboardLayout(String keyboardLayout) { - this.keyboardLayout = keyboardLayout; - } - - public int getBasePitch() { - return basePitch; - } - - /** - * Define offset used by convertIndexToPitch(). - * - * @param basePitch - */ - public void setBasePitch(int basePitch) { - this.basePitch = basePitch; - } - - /** - * @return - */ - public KeyListener getKeyListener() { - return keyListener; - } -} diff --git a/src/com/jsyn/swing/DoubleBoundedRangeModel.java b/src/com/jsyn/swing/DoubleBoundedRangeModel.java deleted file mode 100644 index 647e8da..0000000 --- a/src/com/jsyn/swing/DoubleBoundedRangeModel.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2002 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.swing; - -import javax.swing.DefaultBoundedRangeModel; - -/** - * Double precision data model for sliders and knobs. Maps integer range info to a double value. - * - * @author Phil Burk, (C) 2002 SoftSynth.com, PROPRIETARY and CONFIDENTIAL - */ -public class DoubleBoundedRangeModel extends DefaultBoundedRangeModel { - private static final long serialVersionUID = 284361767102120148L; - protected String name; - private double dmin; - private double dmax; - - public DoubleBoundedRangeModel(String name, int resolution, double dmin, double dmax, - double dval) { - this.name = name; - this.dmin = dmin; - this.dmax = dmax; - setMinimum(0); - setMaximum(resolution); - setDoubleValue(dval); - } - - public boolean equivalentTo(Object other) { - if (!(other instanceof DoubleBoundedRangeModel)) - return false; - DoubleBoundedRangeModel otherModel = (DoubleBoundedRangeModel) other; - return (getValue() == otherModel.getValue()); - } - - /** Set name of value. This may be used in labels or when saving the value. */ - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public double getDoubleMinimum() { - return dmin; - } - - public double getDoubleMaximum() { - return dmax; - } - - public double sliderToDouble(int sliderValue) { - double doubleMin = getDoubleMinimum(); - return doubleMin + ((getDoubleMaximum() - doubleMin) * sliderValue / getMaximum()); - } - - public int doubleToSlider(double dval) { - double doubleMin = getDoubleMinimum(); - // TODO consider using Math.floor() instead of (int) if not too slow. - return (int) Math.round(getMaximum() * (dval - doubleMin) - / (getDoubleMaximum() - doubleMin)); - } - - public double getDoubleValue() { - return sliderToDouble(getValue()); - } - - public void setDoubleValue(double dval) { - setValue(doubleToSlider(dval)); - } - -} diff --git a/src/com/jsyn/swing/DoubleBoundedRangeSlider.java b/src/com/jsyn/swing/DoubleBoundedRangeSlider.java deleted file mode 100644 index 3642221..0000000 --- a/src/com/jsyn/swing/DoubleBoundedRangeSlider.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2002 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.swing; - -import java.util.Hashtable; - -import javax.swing.BorderFactory; -import javax.swing.JLabel; -import javax.swing.JSlider; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.jsyn.util.NumericOutput; - -/** - * Slider that takes a DoubleBoundedRangeModel. It displays the current value in a titled border. - * - * @author Phil Burk, (C) 2002 SoftSynth.com, PROPRIETARY and CONFIDENTIAL - */ - -public class DoubleBoundedRangeSlider extends JSlider { - /**
- *
- */ - private static final long serialVersionUID = -440390322602838998L; - /** Places after decimal point for display. */ - private int places; - - public DoubleBoundedRangeSlider(DoubleBoundedRangeModel model) { - this(model, 5); - } - - public DoubleBoundedRangeSlider(DoubleBoundedRangeModel model, int places) { - super(model); - this.places = places; - setBorder(BorderFactory.createTitledBorder(generateTitleText())); - model.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - updateTitle(); - } - }); - } - - protected void updateTitle() { - TitledBorder border = (TitledBorder) getBorder(); - if (border != null) { - border.setTitle(generateTitleText()); - repaint(); - } - } - - String generateTitleText() { - DoubleBoundedRangeModel model = (DoubleBoundedRangeModel) getModel(); - double val = model.getDoubleValue(); - String valText = NumericOutput.doubleToString(val, 0, places); - return model.getName() + " = " + valText; - } - - public void makeStandardLabels(int labelSpacing) { - setMajorTickSpacing(labelSpacing / 2); - setLabelTable(createStandardLabels(labelSpacing)); - setPaintTicks(true); - setPaintLabels(true); - } - - public double nextLabelValue(double current, double delta) { - return current + delta; - } - - public void makeLabels(double start, double delta, int places) { - DoubleBoundedRangeModel model = (DoubleBoundedRangeModel) getModel(); - // Create the label table - Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>(); - double dval = start; - while (dval <= model.getDoubleMaximum()) { - int sliderValue = model.doubleToSlider(dval); - String text = NumericOutput.doubleToString(dval, 0, places); - labelTable.put(new Integer(sliderValue), new JLabel(text)); - dval = nextLabelValue(dval, delta); - } - setLabelTable(labelTable); - setPaintLabels(true); - } - -} diff --git a/src/com/jsyn/swing/DoubleBoundedTextField.java b/src/com/jsyn/swing/DoubleBoundedTextField.java deleted file mode 100644 index 3301bb1..0000000 --- a/src/com/jsyn/swing/DoubleBoundedTextField.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2000 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.swing; - -import java.awt.Color; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; - -import javax.swing.JTextField; -import javax.swing.SwingConstants; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -/** - * TextField that turns pink when modified, and white when the value is entered. - * - * @author (C) 2000-2010 Phil Burk, Mobileer Inc - * @version 16 - */ - -public class DoubleBoundedTextField extends JTextField { - private static final long serialVersionUID = 6882779668177620812L; - boolean modified = false; - int numCharacters; - private DoubleBoundedRangeModel model; - - public DoubleBoundedTextField(DoubleBoundedRangeModel pModel, int numCharacters) { - super(numCharacters); - this.model = pModel; - this.numCharacters = numCharacters; - setHorizontalAlignment(SwingConstants.LEADING); - setValue(model.getDoubleValue()); - addKeyListener(new KeyAdapter() { - @Override - public void keyTyped(KeyEvent e) { - if (e.getKeyChar() == '\n') { - model.setDoubleValue(getValue()); - } else { - markDirty(); - } - } - }); - model.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - setValue(model.getDoubleValue()); - } - }); - } - - private void markDirty() { - modified = true; - setBackground(Color.pink); - repaint(); - } - - private void markClean() { - modified = false; - setBackground(Color.white); - setCaretPosition(0); - repaint(); - } - - @Override - public void setText(String text) { - markDirty(); - super.setText(text); - } - - private double getValue() throws NumberFormatException { - double val = Double.valueOf(getText()).doubleValue(); - markClean(); - return val; - } - - private void setValue(double value) { - super.setText(String.format("%6.4f", value)); - markClean(); - } -} diff --git a/src/com/jsyn/swing/EnvelopeEditorBox.java b/src/com/jsyn/swing/EnvelopeEditorBox.java deleted file mode 100644 index aab5762..0000000 --- a/src/com/jsyn/swing/EnvelopeEditorBox.java +++ /dev/null @@ -1,573 +0,0 @@ -/* - * 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.swing; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.util.ArrayList; - -import com.jsyn.data.SegmentedEnvelope; -import com.jsyn.unitgen.VariableRateDataReader; - -/** - * Edit a list of ordered duration,value pairs suitable for use with a SegmentedEnvelope. - * - * @author (C) 1997-2013 Phil Burk, SoftSynth.com - * @see EnvelopePoints - * @see SegmentedEnvelope - * @see VariableRateDataReader - */ - -/* ========================================================================== */ -public class EnvelopeEditorBox extends XYController implements MouseListener, MouseMotionListener { - EnvelopePoints points; - ArrayList<EditListener> listeners = new ArrayList<EditListener>(); - int dragIndex = -1; - double dragLowLimit; - double dragHighLimit; - double draggedPoint[]; - double xBefore; // WX value before point - double xPicked; // WX value of picked point - double dragWX; - double dragWY; - int maxPoints = Integer.MAX_VALUE; - int radius = 4; - double verticalBarSpacing = 1.0; - boolean verticalBarsEnabled = false; - double maximumXRange = Double.MAX_VALUE; - double minimumXRange = 0.1; - int rangeStart = -1; // gx coordinates - int rangeEnd = -1; - int mode = EDIT_POINTS; - public final static int EDIT_POINTS = 0; - public final static int SELECT_SUSTAIN = 1; - public final static int SELECT_RELEASE = 2; - - Color rangeColor = Color.RED; - Color sustainColor = Color.BLUE; - Color releaseColor = Color.YELLOW; - Color overlapColor = Color.GREEN; - Color firstLineColor = Color.GRAY; - - public interface EditListener { - public void objectEdited(Object editor, Object edited); - } - - public EnvelopeEditorBox() { - addMouseListener(this); - addMouseMotionListener(this); - } - - public void setMaximumXRange(double maxXRange) { - maximumXRange = maxXRange; - } - - public double getMaximumXRange() { - return maximumXRange; - } - - public void setMinimumXRange(double minXRange) { - minimumXRange = minXRange; - } - - public double getMinimumXRange() { - return minimumXRange; - } - - public void setSelection(int start, int end) { - switch (mode) { - case SELECT_SUSTAIN: - points.setSustainLoop(start, end); - break; - case SELECT_RELEASE: - points.setReleaseLoop(start, end); - break; - } - // System.out.println("start = " + start + ", end = " + end ); - } - - /** Set mode to either EDIT_POINTS or SELECT_SUSTAIN, SELECT_RELEASE; */ - public void setMode(int mode) { - this.mode = mode; - } - - public int getMode() { - return mode; - } - - /** - * Add a listener to receive edit events. Listener will be passed the editor object and the - * edited object. - */ - public void addEditListener(EditListener listener) { - listeners.add(listener); - } - - public void removeEditListener(EditListener listener) { - listeners.remove(listener); - } - - /** Send event to every subscribed listener. */ - public void fireObjectEdited() { - for (EditListener listener : listeners) { - listener.objectEdited(this, points); - } - } - - public void setMaxPoints(int maxPoints) { - this.maxPoints = maxPoints; - } - - public int getMaxPoints() { - return maxPoints; - } - - public int getNumPoints() { - return points.size(); - } - - public void setPoints(EnvelopePoints points) { - this.points = points; - setMaxWorldY(points.getMaximumValue()); - } - - public EnvelopePoints getPoints() { - return points; - } - - /** - * Return index of point before this X position. - */ - private int findPointBefore(double wx) { - int pnt = -1; - double px = 0.0; - xBefore = 0.0; - for (int i = 0; i < points.size(); i++) { - px += points.getDuration(i); - if (px > wx) - break; - pnt = i; - xBefore = px; - } - return pnt; - } - - private int pickPoint(double wx, double wxAperture, double wy, double wyAperture) { - double px = 0.0; - double wxLow = wx - wxAperture; - double wxHigh = wx + wxAperture; - // System.out.println("wxLow = " + wxLow + ", wxHigh = " + wxHigh ); - double wyLow = wy - wyAperture; - double wyHigh = wy + wyAperture; - // System.out.println("wyLow = " + wyLow + ", wyHigh = " + wyHigh ); - double wxScale = 1.0 / wxAperture; // only divide once, then multiply - double wyScale = 1.0 / wyAperture; - int bestPoint = -1; - double bestDistance = Double.MAX_VALUE; - for (int i = 0; i < points.size(); i++) { - double dar[] = points.getPoint(i); - px += dar[0]; - double py = dar[1]; - // System.out.println("px = " + px + ", py = " + py ); - if ((px > wxLow) && (px < wxHigh) && (py > wyLow) && (py < wyHigh)) { - /* Inside pick range. Calculate distance squared. */ - double ndx = (px - wx) * wxScale; - double ndy = (py - wy) * wyScale; - double dist = (ndx * ndx) + (ndy * ndy); - // System.out.println("dist = " + dist ); - if (dist < bestDistance) { - bestPoint = i; - bestDistance = dist; - xPicked = px; - } - } - } - return bestPoint; - } - - private void clickDownRange(boolean shiftDown, int gx, int gy) { - setSelection(-1, -1); - rangeStart = rangeEnd = gx; - repaint(); - } - - private void dragRange(int gx, int gy) { - rangeEnd = gx; - repaint(); - } - - private void clickUpRange(int gx, int gy) { - dragRange(gx, gy); - if (rangeEnd < rangeStart) { - int temp = rangeEnd; - rangeEnd = rangeStart; - rangeStart = temp; - } - // System.out.println("clickUpRange: gx = " + gx + ", rangeStart = " + - // rangeStart ); - double wx = convertGXtoWX(rangeStart); - int i0 = findPointBefore(wx); - wx = convertGXtoWX(rangeEnd); - int i1 = findPointBefore(wx); - - if (i1 == i0) { - // set single point at zero so there is nothing played for queueOn() - if (gx < 0) { - setSelection(0, 0); - } - // else clear any existing loop - } else if (i1 == (i0 + 1)) { - setSelection(i1 + 1, i1 + 1); // set to a single point - } else if (i1 > (i0 + 1)) { - setSelection(i0 + 1, i1 + 1); // set to a range of two or more - } - - rangeStart = -1; - rangeEnd = -1; - fireObjectEdited(); - } - - private void clickDownPoints(boolean shiftDown, int gx, int gy) { - dragIndex = -1; - double wx = convertGXtoWX(gx); - double wy = convertGYtoWY(gy); - // calculate world values for aperture - double wxAp = convertGXtoWX(radius + 2) - convertGXtoWX(0); - // System.out.println("wxAp = " + wxAp ); - double wyAp = convertGYtoWY(0) - convertGYtoWY(radius + 2); - // System.out.println("wyAp = " + wyAp ); - int pnt = pickPoint(wx, wxAp, wy, wyAp); - // System.out.println("pickPoint = " + pnt); - if (shiftDown) { - if (pnt >= 0) { - points.removePoint(pnt); - repaint(); - } - } else { - if (pnt < 0) // didn't hit one so look for point to left of click - { - if (points.size() < maxPoints) // add if room - { - pnt = findPointBefore(wx); - // System.out.println("pointBefore = " + pnt); - dragIndex = pnt + 1; - if (pnt == (points.size() - 1)) { - points.add(wx - xBefore, wy); - } else { - points.insert(dragIndex, wx - xBefore, wy); - } - dragLowLimit = xBefore; - dragHighLimit = wx + (maximumXRange - points.getTotalDuration()); - repaint(); - } - } else - // hit one so drag it - { - dragIndex = pnt; - if (dragIndex <= 0) - dragLowLimit = 0.0; // FIXME envelope drag limit - else - dragLowLimit = xPicked - points.getPoint(dragIndex)[0]; - dragHighLimit = xPicked + (maximumXRange - points.getTotalDuration()); - // System.out.println("dragLowLimit = " + dragLowLimit ); - } - } - // Set up drag point if we are dragging. - if (dragIndex >= 0) { - draggedPoint = points.getPoint(dragIndex); - } - - } - - private void dragPoint(int gx, int gy) { - if (dragIndex < 0) - return; - - double wx = convertGXtoWX(gx); - if (wx < dragLowLimit) - wx = dragLowLimit; - else if (wx > dragHighLimit) - wx = dragHighLimit; - draggedPoint[0] = wx - dragLowLimit; // duration - - double wy = convertGYtoWY(gy); - wy = clipWorldY(wy); - draggedPoint[1] = wy; - dragWY = wy; - dragWX = wx; - points.setDirty(true); - repaint(); - } - - private void clickUpPoints(int gx, int gy) { - dragPoint(gx, gy); - fireObjectEdited(); - dragIndex = -1; - } - - // Implement the MouseMotionListener interface for AWT 1.1 - @Override - public void mouseDragged(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - if (points == null) - return; - if (mode == EDIT_POINTS) { - dragPoint(x, y); - } else { - dragRange(x, y); - } - } - - @Override - public void mouseMoved(MouseEvent e) { - } - - // Implement the MouseListener interface for AWT 1.1 - @Override - public void mousePressed(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - if (points == null) - return; - if (mode == EDIT_POINTS) { - clickDownPoints(e.isShiftDown(), x, y); - } else { - clickDownRange(e.isShiftDown(), x, y); - } - } - - @Override - public void mouseClicked(MouseEvent e) { - } - - @Override - public void mouseReleased(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - if (points == null) - return; - if (mode == EDIT_POINTS) { - clickUpPoints(x, y); - } else { - clickUpRange(x, y); - } - } - - @Override - public void mouseEntered(MouseEvent e) { - } - - @Override - public void mouseExited(MouseEvent e) { - } - - /** - * Draw selected range. - */ - private void drawRange(Graphics g) { - if (rangeStart >= 0) { - int height = getHeight(); - int gx0 = 0, gx1 = 0; - - if (rangeEnd < rangeStart) { - gx0 = rangeEnd; - gx1 = rangeStart; - } else { - gx0 = rangeStart; - gx1 = rangeEnd; - } - g.setColor(rangeColor); - g.fillRect(gx0, 0, gx1 - gx0, height); - } - } - - private void drawUnderSelection(Graphics g, int start, int end) { - if (start >= 0) { - int height = getHeight(); - int gx0 = 0, gx1 = radius; - double wx = 0.0; - for (int i = 0; i <= (end - 1); i++) { - double dar[] = (double[]) points.elementAt(i); - wx += dar[0]; - if (start == (i + 1)) { - gx0 = convertWXtoGX(wx) + radius; - } - if (end == (i + 1)) { - gx1 = convertWXtoGX(wx) + radius; - } - } - if (gx0 == gx1) - gx0 = gx0 - radius; - g.fillRect(gx0, 0, gx1 - gx0, height); - } - } - - private void drawSelections(Graphics g) { - int sus0 = points.getSustainBegin(); - int sus1 = points.getSustainEnd(); - int rel0 = points.getReleaseBegin(); - int rel1 = points.getReleaseEnd(); - - g.setColor(sustainColor); - drawUnderSelection(g, sus0, sus1); - g.setColor(releaseColor); - drawUnderSelection(g, rel0, rel1); - // draw overlapping sustain and release region - if (sus1 >= rel0) { - int sel1 = (rel1 < sus1) ? rel1 : sus1; - g.setColor(overlapColor); - drawUnderSelection(g, rel0, sel1); - } - } - - /** - * Override this to draw a grid or other stuff under the envelope. - */ - public void drawUnderlay(Graphics g) { - if (dragIndex < 0) { - drawSelections(g); - drawRange(g); - } - if (verticalBarsEnabled) - drawVerticalBars(g); - } - - public void setVerticalBarsEnabled(boolean flag) { - verticalBarsEnabled = flag; - } - - public boolean areVerticalBarsEnabled() { - return verticalBarsEnabled; - } - - /** - * Set spacing in world coordinates. - */ - public void setVerticalBarSpacing(double spacing) { - verticalBarSpacing = spacing; - } - - public double getVerticalBarSpacing() { - return verticalBarSpacing; - } - - /** - * Draw vertical lines. - */ - private void drawVerticalBars(Graphics g) { - int width = getWidth(); - int height = getHeight(); - double wx = verticalBarSpacing; - int gx; - - // g.setColor( getBackground().darker() ); - g.setColor(Color.lightGray); - while (true) { - gx = convertWXtoGX(wx); - if (gx > width) - break; - g.drawLine(gx, 0, gx, height); - wx += verticalBarSpacing; - } - } - - public void drawPoints(Graphics g, Color lineColor) { - double wx = 0.0; - int gx1 = 0; - int gy1 = getHeight(); - for (int i = 0; i < points.size(); i++) { - double dar[] = (double[]) points.elementAt(i); - wx += dar[0]; - double wy = dar[1]; - int gx2 = convertWXtoGX(wx); - int gy2 = convertWYtoGY(wy); - if (i == 0) { - g.setColor(isEnabled() ? firstLineColor : firstLineColor.darker()); - g.drawLine(gx1, gy1, gx2, gy2); - g.setColor(isEnabled() ? lineColor : lineColor.darker()); - } else if (i > 0) { - g.drawLine(gx1, gy1, gx2, gy2); - } - int diameter = (2 * radius) + 1; - g.fillOval(gx2 - radius, gy2 - radius, diameter, diameter); - gx1 = gx2; - gy1 = gy2; - } - } - - public void drawAllPoints(Graphics g) { - drawPoints(g, getForeground()); - } - - /* Override default paint action. */ - @Override - public void paint(Graphics g) { - double wx = 0.0; - int width = getWidth(); - int height = getHeight(); - - // draw background and erase all values - g.setColor(isEnabled() ? getBackground() : getBackground().darker()); - g.fillRect(0, 0, width, height); - - if (points == null) { - g.setColor(getForeground()); - g.drawString("No EnvelopePoints", 10, 30); - return; - } - - // Determine total duration. - if (points.size() > 0) { - wx = points.getTotalDuration(); - // Adjust max X so that we see entire circle of last point. - double radiusWX = this.convertGXtoWX(radius) - this.getMinWorldX(); - double wxFar = wx + radiusWX; - if (wxFar > getMaxWorldX()) { - if (wx > maximumXRange) - wxFar = maximumXRange; - setMaxWorldX(wxFar); - } else if (wx < (getMaxWorldX() * 0.7)) { - double newMax = wx / 0.7001; // make slightly larger to prevent - // endless jitter, FIXME - still - // needed after repaint() - // removed from setMaxWorldX? - // System.out.println("newMax = " + newMax ); - if (newMax < minimumXRange) - newMax = minimumXRange; - setMaxWorldX(newMax); - } - } - // System.out.println("total X = " + wx ); - - drawUnderlay(g); - - drawAllPoints(g); - - /* Show X,Y,TotalX as text. */ - g.drawString(points.getName() + ", len=" + String.format("%7.3f", wx), 5, 15); - if ((draggedPoint != null) && (dragIndex >= 0)) { - String s = "i=" + dragIndex + ", dur=" - + String.format("%7.3f", draggedPoint[0]) + ", y = " - + String.format("%8.4f", draggedPoint[1]); - g.drawString(s, 5, 30); - } - } -} diff --git a/src/com/jsyn/swing/EnvelopeEditorPanel.java b/src/com/jsyn/swing/EnvelopeEditorPanel.java deleted file mode 100644 index dc9f2cd..0000000 --- a/src/com/jsyn/swing/EnvelopeEditorPanel.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2009 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.swing; - -import java.awt.BorderLayout; -import java.awt.Button; -import java.awt.Checkbox; -import java.awt.CheckboxGroup; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Label; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -public class EnvelopeEditorPanel extends JPanel { - EnvelopeEditorBox editor; - Checkbox pointsBox; - Checkbox sustainBox; - Checkbox releaseBox; - Checkbox autoBox; - Button onButton; - Button offButton; - Button clearButton; - Button yUpButton; - Button yDownButton; - DoubleBoundedTextField zoomField; - - public EnvelopeEditorPanel(EnvelopePoints points, int maxFrames) { - setSize(600, 300); - - setLayout(new BorderLayout()); - editor = new EnvelopeEditorBox(); - editor.setMaxPoints(maxFrames); - editor.setBackground(Color.cyan); - editor.setPoints(points); - editor.setMinimumSize(new Dimension(500, 300)); - - add(editor, "Center"); - - JPanel buttonPanel = new JPanel(); - add(buttonPanel, "South"); - - CheckboxGroup cbg = new CheckboxGroup(); - pointsBox = new Checkbox("points", cbg, true); - pointsBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - editor.setMode(EnvelopeEditorBox.EDIT_POINTS); - } - }); - buttonPanel.add(pointsBox); - - sustainBox = new Checkbox("onLoop", cbg, false); - sustainBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - editor.setMode(EnvelopeEditorBox.SELECT_SUSTAIN); - } - }); - buttonPanel.add(sustainBox); - - releaseBox = new Checkbox("offLoop", cbg, false); - releaseBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - editor.setMode(EnvelopeEditorBox.SELECT_RELEASE); - } - }); - buttonPanel.add(releaseBox); - - autoBox = new Checkbox("AutoStop", false); - /* - * buttonPanel.add( onButton = new Button( "On" ) ); onButton.addActionListener( module ); - * buttonPanel.add( offButton = new Button( "Off" ) ); offButton.addActionListener( module - * ); buttonPanel.add( clearButton = new Button( "Clear" ) ); clearButton.addActionListener( - * module ); - */ - buttonPanel.add(yUpButton = new Button("Y*2")); - yUpButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - scaleEnvelopeValues(2.0); - } - }); - - buttonPanel.add(yDownButton = new Button("Y/2")); - yDownButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - scaleEnvelopeValues(0.5); - } - }); - - /* Add a TextField for setting the Y scale. */ - double max = getMaxEnvelopeValue(editor.getPoints()); - editor.setMaxWorldY(max); - buttonPanel.add(new Label("YMax =")); - final DoubleBoundedRangeModel model = new DoubleBoundedRangeModel("YMax", 100000, 1.0, - 100001.0, 1.0); - buttonPanel.add(zoomField = new DoubleBoundedTextField(model, 8)); - model.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - try { - double val = model.getDoubleValue(); - editor.setMaxWorldY(val); - editor.repaint(); - } catch (NumberFormatException exp) { - zoomField.setText("ERROR"); - zoomField.selectAll(); - } - } - }); - - validate(); - } - - /** - * Multiply all the values in the envelope by scalar. - */ - double getMaxEnvelopeValue(EnvelopePoints points) { - double max = 1.0; - for (int i = 0; i < points.size(); i++) { - double value = points.getValue(i); - if (value > max) { - max = value; - } - } - return max; - } - - /** - * Multiply all the values in the envelope by scalar. - */ - void scaleEnvelopeValues(double scalar) { - EnvelopePoints points = editor.getPoints(); - for (int i = 0; i < points.size(); i++) { - double[] dar = points.getPoint(i); - dar[1] = dar[1] * scalar; // scale value - } - points.setDirty(true); - editor.repaint(); - } -} diff --git a/src/com/jsyn/swing/EnvelopePoints.java b/src/com/jsyn/swing/EnvelopePoints.java deleted file mode 100644 index ab4ed03..0000000 --- a/src/com/jsyn/swing/EnvelopePoints.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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.swing; - -import java.util.Vector; - -import com.jsyn.data.SegmentedEnvelope; - -/** - * Vector that contains duration,value pairs. Used by EnvelopeEditor - * - * @author (C) 1997 Phil Burk, SoftSynth.com - */ - -/* ========================================================================== */ -public class EnvelopePoints extends Vector { - private String name = ""; - private double maximumValue = 1.0; - private int sustainBegin = -1; - private int sustainEnd = -1; - private int releaseBegin = -1; - private int releaseEnd = -1; - private boolean dirty = false; - - /** - * Update only if points or loops were modified. - */ - public void updateEnvelopeIfDirty(SegmentedEnvelope envelope) { - if (dirty) { - updateEnvelope(envelope); - } - } - - /** - * The editor works on a vector of points, not a real envelope. The data must be written to a - * real SynthEnvelope in order to use it. - */ - public void updateEnvelope(SegmentedEnvelope envelope) { - int numFrames = size(); - for (int i = 0; i < numFrames; i++) { - envelope.write(i, getPoint(i), 0, 1); - } - envelope.setSustainBegin(getSustainBegin()); - envelope.setSustainEnd(getSustainEnd()); - envelope.setReleaseBegin(getReleaseBegin()); - envelope.setReleaseEnd(getReleaseEnd()); - envelope.setNumFrames(numFrames); - dirty = false; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setMaximumValue(double maximumValue) { - this.maximumValue = maximumValue; - } - - public double getMaximumValue() { - return maximumValue; - } - - public void add(double dur, double value) { - double dar[] = { - dur, value - }; - addElement(dar); - dirty = true; - } - - /** - * Insert point without changing total duration by reducing next points duration. - */ - public void insert(int index, double dur, double y) { - double dar[] = { - dur, y - }; - if (index < size()) { - ((double[]) elementAt(index))[0] -= dur; - } - insertElementAt(dar, index); - - if (index <= sustainBegin) - sustainBegin += 1; - if (index <= sustainEnd) - sustainEnd += 1; - if (index <= releaseBegin) - releaseBegin += 1; - if (index <= releaseEnd) - releaseEnd += 1; - dirty = true; - } - - /** - * Remove indexed point and update sustain and release loops if necessary. Did not name this - * "remove()" because of conflicts with new JDK 1.3 method with the same name. - */ - public void removePoint(int index) { - super.removeElementAt(index); - // move down loop if points below or inside loop removed - if (index < sustainBegin) - sustainBegin -= 1; - if (index <= sustainEnd) - sustainEnd -= 1; - if (index < releaseBegin) - releaseBegin -= 1; - if (index <= releaseEnd) - releaseEnd -= 1; - - // was entire loop removed? - if (sustainBegin > sustainEnd) { - sustainBegin = -1; - sustainEnd = -1; - } - // was entire loop removed? - if (releaseBegin > releaseEnd) { - releaseBegin = -1; - releaseEnd = -1; - } - dirty = true; - } - - public double getDuration(int index) { - return ((double[]) elementAt(index))[0]; - } - - public double getValue(int index) { - return ((double[]) elementAt(index))[1]; - } - - public double[] getPoint(int index) { - return (double[]) elementAt(index); - } - - public double getTotalDuration() { - double sum = 0.0; - for (int i = 0; i < size(); i++) { - double dar[] = (double[]) elementAt(i); - sum += dar[0]; - } - return sum; - } - - /** - * Set location of Sustain Loop in units of Frames. Set SustainBegin to -1 if no Sustain Loop. - * SustainEnd value is the frame index of the frame just past the end of the loop. The number of - * frames included in the loop is (SustainEnd - SustainBegin). - */ - public void setSustainLoop(int startFrame, int endFrame) { - this.sustainBegin = startFrame; - this.sustainEnd = endFrame; - dirty = true; - } - - /*** - * @return Beginning of sustain loop or -1 if no loop. - */ - public int getSustainBegin() { - return this.sustainBegin; - } - - /*** - * @return End of sustain loop or -1 if no loop. - */ - public int getSustainEnd() { - return this.sustainEnd; - } - - /*** - * @return Size of sustain loop in frames, 0 if no loop. - */ - public int getSustainSize() { - return (this.sustainEnd - this.sustainBegin); - } - - /** - * Set location of Release Loop in units of Frames. Set ReleaseBegin to -1 if no ReleaseLoop. - * ReleaseEnd value is the frame index of the frame just past the end of the loop. The number of - * frames included in the loop is (ReleaseEnd - ReleaseBegin). - */ - public void setReleaseLoop(int startFrame, int endFrame) { - this.releaseBegin = startFrame; - this.releaseEnd = endFrame; - dirty = true; - } - - /*** - * @return Beginning of release loop or -1 if no loop. - */ - public int getReleaseBegin() { - return this.releaseBegin; - } - - /*** - * @return End of release loop or -1 if no loop. - */ - public int getReleaseEnd() { - return this.releaseEnd; - } - - /*** - * @return Size of release loop in frames, 0 if no loop. - */ - public int getReleaseSize() { - return (this.releaseEnd - this.releaseBegin); - } - - public boolean isDirty() { - return dirty; - } - - public void setDirty(boolean b) { - dirty = b; - } - -} diff --git a/src/com/jsyn/swing/ExponentialRangeModel.java b/src/com/jsyn/swing/ExponentialRangeModel.java deleted file mode 100644 index 4411947..0000000 --- a/src/com/jsyn/swing/ExponentialRangeModel.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.swing; - -/** - * Maps integer range info to a double value along an exponential scale. - * - * <pre> - * - * x = ival / resolution
- * f(x) = a*(rootˆcx) + b
- * f(0.0) = dmin
- * f(1.0) = dmax
- * b = dmin - a
- * a = (dmax - dmin) / (rootˆc - 1)
- *
- * Inverse function:
- * x = log( (y-b)/a ) / log(root) - * - * </pre> - * - * @author Phil Burk, (C) 2011 Mobileer Inc - */ -public class ExponentialRangeModel extends DoubleBoundedRangeModel { - private static final long serialVersionUID = -142785624892302160L; - double a = 1.0; - double b = -1.0; - double span = 1.0; - double root = 10.0; - - /** Use default root of 10.0 and span of 1.0. */ - public ExponentialRangeModel(String name, int resolution, double dmin, double dmax, double dval) { - this(name, resolution, dmin, dmax, dval, 1.0); - } - - /** Set span before setting double value so it is translated correctly. */ - ExponentialRangeModel(String name, int resolution, double dmin, double dmax, double dval, - double span) { - super(name, resolution, dmin, dmax, dval); - setRoot(10.0); - setSpan(span); - /* Set again after coefficients setup. */ - setDoubleValue(dval); - } - - private void updateCoefficients() { - a = (getDoubleMaximum() - getDoubleMinimum()) / (Math.pow(root, span) - 1.0); - b = getDoubleMinimum() - a; - } - - private void setRoot(double w) { - root = w; - updateCoefficients(); - } - - public double getRoot() { - return root; - } - - public void setSpan(double c) { - this.span = c; - updateCoefficients(); - } - - public double getSpan() { - return span; - } - - @Override - public double sliderToDouble(int sliderValue) { - updateCoefficients(); // TODO optimize when we call this - double x = (double) sliderValue / getMaximum(); - double y = (a * Math.pow(root, span * x)) + b; - return y; - } - - @Override - public int doubleToSlider(double dval) { - updateCoefficients(); // TODO optimize when we call this - double z = (dval - b) / a; - double x = Math.log(z) / (span * Math.log(root)); - return (int) Math.round(x * getMaximum()); - } - - public void test(int sliderValue) { - double dval = sliderToDouble(sliderValue); - int ival = doubleToSlider(dval); - System.out.println(sliderValue + " => " + dval + " => " + ival); - } - -} diff --git a/src/com/jsyn/swing/InstrumentBrowser.java b/src/com/jsyn/swing/InstrumentBrowser.java deleted file mode 100644 index 55575a3..0000000 --- a/src/com/jsyn/swing/InstrumentBrowser.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2012 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.swing; - -import java.awt.Dimension; -import java.awt.GridLayout; -import java.util.ArrayList; - -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.ListSelectionModel; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; - -import com.jsyn.util.InstrumentLibrary; -import com.jsyn.util.VoiceDescription; - -/** - * Display a list of VoiceDescriptions and their associated presets. Notify PresetSelectionListeners - * when a preset is selected. - * - * @author Phil Burk (C) 2012 Mobileer Inc - */ -@SuppressWarnings("serial") -public class InstrumentBrowser extends JPanel { - private InstrumentLibrary library; - private JScrollPane listScroller2; - private VoiceDescription voiceDescription; - private ArrayList<PresetSelectionListener> listeners = new ArrayList<PresetSelectionListener>(); - - public InstrumentBrowser(InstrumentLibrary library) { - this.library = library; - JPanel horizontalPanel = new JPanel(); - horizontalPanel.setLayout(new GridLayout(1, 2)); - - final JList<VoiceDescription> instrumentList = new JList<VoiceDescription>(library.getVoiceDescriptions()); - setupList(instrumentList); - instrumentList.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - if (e.getValueIsAdjusting() == false) { - int n = instrumentList.getSelectedIndex(); - if (n >= 0) { - showPresetList(n); - } - } - } - }); - - JScrollPane listScroller1 = new JScrollPane(instrumentList); - listScroller1.setPreferredSize(new Dimension(250, 120)); - add(listScroller1); - - instrumentList.setSelectedIndex(0); - } - - public void addPresetSelectionListener(PresetSelectionListener listener) { - listeners.add(listener); - } - - public void removePresetSelectionListener(PresetSelectionListener listener) { - listeners.remove(listener); - } - - private void firePresetSelectionListeners(VoiceDescription voiceDescription, int presetIndex) { - for (PresetSelectionListener listener : listeners) { - listener.presetSelected(voiceDescription, presetIndex); - } - } - - private void showPresetList(int n) { - if (listScroller2 != null) { - remove(listScroller2); - } - voiceDescription = library.getVoiceDescriptions()[n]; - final JList<String> presetList = new JList<String>(voiceDescription.getPresetNames()); - setupList(presetList); - presetList.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - if (e.getValueIsAdjusting() == false) { - int n = presetList.getSelectedIndex(); - if (n >= 0) { - firePresetSelectionListeners(voiceDescription, n); - } - } - } - }); - - listScroller2 = new JScrollPane(presetList); - listScroller2.setPreferredSize(new Dimension(250, 120)); - add(listScroller2); - presetList.setSelectedIndex(0); - validate(); - } - - private void setupList(@SuppressWarnings("rawtypes") JList list) { - list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); - list.setLayoutOrientation(JList.VERTICAL); - list.setVisibleRowCount(-1); - } -} diff --git a/src/com/jsyn/swing/JAppletFrame.java b/src/com/jsyn/swing/JAppletFrame.java deleted file mode 100644 index 53bd65b..0000000 --- a/src/com/jsyn/swing/JAppletFrame.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.swing; - -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.JApplet; -import javax.swing.JFrame; - -/** - * Frame that allows a program to be run as either an Application or an Applet. Used by JSyn example - * programs. - * - * @author (C) 1997 Phil Burk, SoftSynth.com - */ - -public class JAppletFrame extends JFrame { - private static final long serialVersionUID = -6047247494856379114L; - JApplet applet; - - public JAppletFrame(String frameTitle, final JApplet pApplet) { - super(frameTitle); - this.applet = pApplet; - getContentPane().add(applet); - repaint(); - - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - applet.stop(); - applet.destroy(); - try { - System.exit(0); - } catch (SecurityException exc) { - System.err.println("System.exit(0) not allowed by Java VM."); - } - } - - @Override - public void windowClosed(WindowEvent e) { - } - }); - } - - public void test() { - applet.init(); - applet.start(); - } - -} diff --git a/src/com/jsyn/swing/PortBoundedRangeModel.java b/src/com/jsyn/swing/PortBoundedRangeModel.java deleted file mode 100644 index a5cf841..0000000 --- a/src/com/jsyn/swing/PortBoundedRangeModel.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.swing; - -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.jsyn.ports.UnitInputPort; - -/** - * A bounded range model that drives a UnitInputPort. The range of the model is set based on the min - * and max of the port. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class PortBoundedRangeModel extends DoubleBoundedRangeModel { - private static final long serialVersionUID = -8011867146560305808L; - private UnitInputPort port; - - public PortBoundedRangeModel(UnitInputPort pPort) { - super(pPort.getName(), 10000, pPort.getMinimum(), pPort.getMaximum(), pPort.getValue()); - this.port = pPort; - addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - port.set(getDoubleValue()); - } - }); - } - -} diff --git a/src/com/jsyn/swing/PortControllerFactory.java b/src/com/jsyn/swing/PortControllerFactory.java deleted file mode 100644 index a73d047..0000000 --- a/src/com/jsyn/swing/PortControllerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.swing; - -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.jsyn.ports.UnitInputPort; - -/** - * Factory class for making various controllers for JSyn ports. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class PortControllerFactory { - private static final int RESOLUTION = 100000; - - public static DoubleBoundedRangeSlider createPortSlider(final UnitInputPort port) { - DoubleBoundedRangeModel rangeModel = new DoubleBoundedRangeModel(port.getName(), - RESOLUTION, port.getMinimum(), port.getMaximum(), port.get()); - rangeModel.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - DoubleBoundedRangeModel model = (DoubleBoundedRangeModel) e.getSource(); - double value = model.getDoubleValue(); - port.set(value); - } - }); - return new DoubleBoundedRangeSlider(rangeModel, 4); - } - - public static DoubleBoundedRangeSlider createExponentialPortSlider(final UnitInputPort port) { - ExponentialRangeModel rangeModel = new ExponentialRangeModel(port.getName(), RESOLUTION, - port.getMinimum(), port.getMaximum(), port.get()); - rangeModel.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - ExponentialRangeModel model = (ExponentialRangeModel) e.getSource(); - double value = model.getDoubleValue(); - port.set(value); - } - }); - return new DoubleBoundedRangeSlider(rangeModel, 4); - } - -} diff --git a/src/com/jsyn/swing/PortModelFactory.java b/src/com/jsyn/swing/PortModelFactory.java deleted file mode 100644 index 8bec76a..0000000 --- a/src/com/jsyn/swing/PortModelFactory.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2009 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.swing; - -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.jsyn.ports.UnitInputPort; - -public class PortModelFactory { - private static final int RESOLUTION = 1000000; - - public static DoubleBoundedRangeModel createLinearModel(final UnitInputPort pPort) { - final DoubleBoundedRangeModel model = new DoubleBoundedRangeModel(pPort.getName(), - RESOLUTION, pPort.getMinimum(), pPort.getMaximum(), pPort.get()); - model.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - pPort.set(model.getDoubleValue()); - } - }); - return model; - } - - public static ExponentialRangeModel createExponentialModel(final UnitInputPort pPort) { - final ExponentialRangeModel model = new ExponentialRangeModel(pPort.getName(), RESOLUTION, - pPort.getMinimum(), pPort.getMaximum(), pPort.get()); - model.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - pPort.set(model.getDoubleValue()); - } - }); - return model; - } - - public static ExponentialRangeModel createExponentialModel(final int partNum, - final UnitInputPort pPort) { - final ExponentialRangeModel model = new ExponentialRangeModel(pPort.getName(), RESOLUTION, - pPort.getMinimum(), pPort.getMaximum(), pPort.get()); - model.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - pPort.set(partNum, model.getDoubleValue()); - } - }); - return model; - } - -} diff --git a/src/com/jsyn/swing/PresetSelectionListener.java b/src/com/jsyn/swing/PresetSelectionListener.java deleted file mode 100644 index daf0310..0000000 --- a/src/com/jsyn/swing/PresetSelectionListener.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2009 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.swing; - -import com.jsyn.util.VoiceDescription; - -public interface PresetSelectionListener { - public void presetSelected(VoiceDescription voiceDescription, int presetIndex); -} diff --git a/src/com/jsyn/swing/RotaryController.java b/src/com/jsyn/swing/RotaryController.java deleted file mode 100644 index c26c37f..0000000 --- a/src/com/jsyn/swing/RotaryController.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * 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.swing; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionAdapter; - -import javax.swing.BoundedRangeModel; -import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -/** - * Rotary controller looks like a knob on a synthesizer. You control this knob by clicking on it and - * dragging <b>up</b> or <b>down</b>. If you move the mouse to the <b>left</b> of the knob then you - * will have <b>coarse</b> control. If you move the mouse to the <b>right</b> of the knob then you - * will have <b>fine</b> control. - * <P> - * - * @author (C) 2010 Phil Burk, Mobileer Inc - * @version 16.1 - */ -public class RotaryController extends JPanel { - private static final long serialVersionUID = 6681532871556659546L; - private static final double SENSITIVITY = 0.01; - private final BoundedRangeModel model; - - private final double minAngle = 1.4 * Math.PI; - private final double maxAngle = -0.4 * Math.PI; - private final double unitIncrement = 0.01; - private int lastY; - private int startX; - private Color knobColor = Color.LIGHT_GRAY; - private Color lineColor = Color.RED; - private double baseValue; - - public enum Style { - LINE, LINEDOT, ARROW, ARC - }; - - private Style style = Style.ARC; - - public RotaryController(BoundedRangeModel model) { - this.model = model; - setMinimumSize(new Dimension(50, 50)); - setPreferredSize(new Dimension(50, 50)); - addMouseListener(new MouseHandler()); - addMouseMotionListener(new MouseMotionHandler()); - model.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - safeRepaint(); - } - - }); - } - - // This can be overridden in subclasses to workaround OpenJDK bugs. - public void safeRepaint() { - repaint(); - } - - public BoundedRangeModel getModel() { - return model; - } - - private class MouseHandler extends MouseAdapter { - - @Override - public void mousePressed(MouseEvent e) { - lastY = e.getY(); - startX = e.getX(); - } - - @Override - public void mouseReleased(MouseEvent e) { - if (isEnabled()) { - setKnobByXY(e.getX(), e.getY()); - } - } - } - - private class MouseMotionHandler extends MouseMotionAdapter { - @Override - public void mouseDragged(MouseEvent e) { - if (isEnabled()) { - setKnobByXY(e.getX(), e.getY()); - } - } - } - - private int getModelRange() { - return (((model.getMaximum() - model.getExtent()) - model.getMinimum())); - } - - /** - * A fractional value is useful for drawing. - * - * @return model value as a normalized fraction between 0.0 and 1.0 - */ - public double getFractionFromModel() { - double value = model.getValue(); - return convertValueToFraction(value); - } - - private double convertValueToFraction(double value) { - return (value - model.getMinimum()) / getModelRange(); - } - - private void setKnobByXY(int x, int y) { - // Scale increment by X position. - int xdiff = startX - x; // More to left causes bigger increments. - double power = xdiff * SENSITIVITY; - double perPixel = unitIncrement * Math.pow(2.0, power); - - int ydiff = lastY - y; - double fractionalDelta = ydiff * perPixel; - // Only update the model if we actually change values. - // This is needed in case the range is small. - int valueDelta = (int) Math.round(fractionalDelta * getModelRange()); - if (valueDelta != 0) { - model.setValue(model.getValue() + valueDelta); - lastY = y; - } - } - - private double fractionToAngle(double fraction) { - return (fraction * (maxAngle - minAngle)) + minAngle; - } - - private void drawLineIndicator(Graphics g, int x, int y, int radius, double angle, - boolean drawDot) { - double arrowSize = radius * 0.95; - int arrowX = (int) (arrowSize * Math.sin(angle)); - int arrowY = (int) (arrowSize * Math.cos(angle)); - g.setColor(lineColor); - g.drawLine(x, y, x + arrowX, y - arrowY); - if (drawDot) { - // draw little dot at end - double dotScale = 0.1; - int dotRadius = (int) (dotScale * arrowSize); - if (dotRadius > 1) { - int dotX = x + (int) ((0.99 - dotScale) * arrowX) - dotRadius; - int dotY = y - (int) ((0.99 - dotScale) * arrowY) - dotRadius; - g.fillOval(dotX, dotY, dotRadius * 2, dotRadius * 2); - } - } - } - - private void drawArrowIndicator(Graphics g, int x0, int y0, int radius, double angle) { - int arrowSize = (int) (radius * 0.95); - int arrowWidth = (int) (radius * 0.2); - int xp[] = { - 0, arrowWidth, 0, -arrowWidth - }; - int yp[] = { - arrowSize, -arrowSize / 2, 0, -arrowSize / 2 - }; - double sa = Math.sin(angle); - double ca = Math.cos(angle); - for (int i = 0; i < xp.length; i++) { - int x = xp[i]; - int y = yp[i]; - xp[i] = x0 - (int) ((x * ca) - (y * sa)); - yp[i] = y0 - (int) ((x * sa) + (y * ca)); - } - g.fillPolygon(xp, yp, xp.length); - } - - private void drawArcIndicator(Graphics g, int x, int y, int radius, double angle) { - final double DEGREES_PER_RADIAN = 180.0 / Math.PI; - final int minAngleDegrees = (int) (minAngle * DEGREES_PER_RADIAN); - final int maxAngleDegrees = (int) (maxAngle * DEGREES_PER_RADIAN); - - int zeroAngleDegrees = (int) (fractionToAngle(baseValue) * DEGREES_PER_RADIAN); - - double arrowSize = radius * 0.95; - int arcX = x - radius; - int arcY = y - radius; - int arcAngle = (int) (angle * DEGREES_PER_RADIAN); - int arrowX = (int) (arrowSize * Math.cos(angle)); - int arrowY = (int) (arrowSize * Math.sin(angle)); - - g.setColor(knobColor.darker().darker()); - g.fillArc(arcX, arcY, 2 * radius, 2 * radius, minAngleDegrees, maxAngleDegrees - - minAngleDegrees); - g.setColor(Color.ORANGE); - g.fillArc(arcX, arcY, 2 * radius, 2 * radius, zeroAngleDegrees, arcAngle - zeroAngleDegrees); - - // fill in middle - int arcWidth = radius / 4; - int diameter = ((radius - arcWidth) * 2); - g.setColor(knobColor); - g.fillOval(arcWidth + x - radius, arcWidth + y - radius, diameter, diameter); - - g.setColor(lineColor); - g.drawLine(x, y, x + arrowX, y - arrowY); - - } - - /** - * Override this method if you want to draw your own line or dot on the knob. - */ - public void drawIndicator(Graphics g, int x, int y, int radius, double angle) { - g.setColor(isEnabled() ? lineColor : lineColor.darker()); - switch (style) { - case LINE: - drawLineIndicator(g, x, y, radius, angle, false); - break; - case LINEDOT: - drawLineIndicator(g, x, y, radius, angle, true); - break; - case ARROW: - drawArrowIndicator(g, x, y, radius, angle); - break; - case ARC: - drawArcIndicator(g, x, y, radius, angle); - break; - } - } - - /** - * Override this method if you want to draw your own knob. - * - * @param g graphics context - * @param x position of center of knob - * @param y position of center of knob - * @param radius of knob in pixels - * @param angle in radians. Zero is straight up. - */ - public void drawKnob(Graphics g, int x, int y, int radius, double angle) { - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - - int diameter = radius * 2; - // Draw shaded side. - g.setColor(knobColor.darker()); - g.fillOval(x - radius + 2, y - radius + 2, diameter, diameter); - g.setColor(knobColor); - g.fillOval(x - radius, y - radius, diameter, diameter); - - // Draw line or other indicator of knob position. - drawIndicator(g, x, y, radius, angle); - } - - // Draw the round knob based on the current size and model value. - // This used to have a bug where the scope would draw in this components background. - // Then I changed it from overriding paint() to overriding paintComponent() and it worked. - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - - int width = getWidth(); - int height = getHeight(); - int x = width / 2; - int y = height / 2; - - // Calculate radius from size of component. - int diameter = (width < height) ? width : height; - diameter -= 4; - int radius = diameter / 2; - - double angle = fractionToAngle(getFractionFromModel()); - drawKnob(g, x, y, radius, angle); - } - - public Color getKnobColor() { - return knobColor; - } - - /** - * @param knobColor color of body of knob - */ - public void setKnobColor(Color knobColor) { - this.knobColor = knobColor; - } - - public Color getLineColor() { - return lineColor; - } - - /** - * @param lineColor color of indicator on knob like a line or arrow - */ - public void setLineColor(Color lineColor) { - this.lineColor = lineColor; - } - - public void setStyle(Style style) { - this.style = style; - } - - public Style getStyle() { - return style; - } - - public double getBaseValue() { - return baseValue; - } - - /* - * Specify where the orange arc originates. For example a pan knob with a centered arc would - * have a baseValue of 0.5. - * @param baseValue a fraction between 0.0 and 1.0. - */ - public void setBaseValue(double baseValue) { - if (baseValue < 0.0) { - baseValue = 0.0; - } else if (baseValue > 1.0) { - baseValue = 1.0; - } - this.baseValue = baseValue; - } - -} diff --git a/src/com/jsyn/swing/RotaryTextController.java b/src/com/jsyn/swing/RotaryTextController.java deleted file mode 100644 index 81d6614..0000000 --- a/src/com/jsyn/swing/RotaryTextController.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.swing; - -import java.awt.BorderLayout; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; - -/** - * Combine a RotaryController and a DoubleBoundedTextField into a convenient package. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class RotaryTextController extends JPanel { - private static final long serialVersionUID = -2931828326251895375L; - private RotaryController rotary; - private DoubleBoundedTextField textField; - - public RotaryTextController(DoubleBoundedRangeModel pModel, int numDigits) { - rotary = new RotaryController(pModel); - textField = new DoubleBoundedTextField(pModel, numDigits); - setLayout(new BorderLayout()); - add(rotary, BorderLayout.CENTER); - add(textField, BorderLayout.SOUTH); - } - - /** Display the title in a border. */ - public void setTitle(String label) { - setBorder(BorderFactory.createTitledBorder(label)); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - rotary.setEnabled(enabled); - textField.setEnabled(enabled); - } -} diff --git a/src/com/jsyn/swing/SoundTweaker.java b/src/com/jsyn/swing/SoundTweaker.java deleted file mode 100644 index 043677e..0000000 --- a/src/com/jsyn/swing/SoundTweaker.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2009 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.swing; - -import java.awt.Component; -import java.awt.GridLayout; -import java.util.ArrayList; -import java.util.logging.Logger; - -import javax.swing.JLabel; -import javax.swing.JPanel; - -import com.jsyn.Synthesizer; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitPort; -import com.jsyn.unitgen.UnitGenerator; -import com.jsyn.unitgen.UnitSource; -import com.jsyn.unitgen.UnitVoice; -import com.jsyn.util.Instrument; -import com.softsynth.math.AudioMath; - -@SuppressWarnings("serial") -public class SoundTweaker extends JPanel { - private UnitSource source; - private ASCIIMusicKeyboard keyboard; - private Synthesizer synth; - - static Logger logger = Logger.getLogger(SoundTweaker.class.getName()); - - public SoundTweaker(Synthesizer synth, String title, UnitSource source) { - this.synth = synth; - this.source = source; - - setLayout(new GridLayout(0, 2)); - - UnitGenerator ugen = source.getUnitGenerator(); - ArrayList<Component> sliders = new ArrayList<Component>(); - - add(new JLabel(title)); - - if (source instanceof Instrument) { - add(keyboard = createPolyphonicKeyboard()); - } else if (source instanceof UnitVoice) { - add(keyboard = createMonophonicKeyboard()); - } - - // Arrange the faders in a stack. - // Iterate through the ports. - for (UnitPort port : ugen.getPorts()) { - if (port instanceof UnitInputPort) { - UnitInputPort inputPort = (UnitInputPort) port; - Component slider; - // Use an exponential slider if it seems appropriate. - if ((inputPort.getMinimum() > 0.0) - && ((inputPort.getMaximum() / inputPort.getMinimum()) > 4.0)) { - slider = PortControllerFactory.createExponentialPortSlider(inputPort); - } else { - slider = PortControllerFactory.createPortSlider(inputPort); - - } - add(slider); - sliders.add(slider); - } - } - - if (keyboard != null) { - for (Component slider : sliders) { - slider.addKeyListener(keyboard.getKeyListener()); - } - } - validate(); - } - - @SuppressWarnings("serial") - private ASCIIMusicKeyboard createPolyphonicKeyboard() { - ASCIIMusicKeyboard keyboard = new ASCIIMusicKeyboard() { - @Override - public void keyOff(int pitch) { - ((Instrument) source).noteOff(pitch, synth.createTimeStamp()); - } - - @Override - public void keyOn(int pitch) { - double freq = AudioMath.pitchToFrequency(pitch); - ((Instrument) source).noteOn(pitch, freq, 0.5, synth.createTimeStamp()); - } - }; - return keyboard; - } - - @SuppressWarnings("serial") - private ASCIIMusicKeyboard createMonophonicKeyboard() { - ASCIIMusicKeyboard keyboard = new ASCIIMusicKeyboard() { - @Override - public void keyOff(int pitch) { - ((UnitVoice) source).noteOff(synth.createTimeStamp()); - } - - @Override - public void keyOn(int pitch) { - double freq = AudioMath.pitchToFrequency(pitch); - ((UnitVoice) source).noteOn(freq, 0.5, synth.createTimeStamp()); - } - }; - return keyboard; - } - -} diff --git a/src/com/jsyn/swing/XYController.java b/src/com/jsyn/swing/XYController.java deleted file mode 100644 index 0d97c62..0000000 --- a/src/com/jsyn/swing/XYController.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.swing; - -import javax.swing.JPanel; - -/** - * Root class for 2 dimensional X,Y controller for wave editors, Theremins, etc. Maps pixel - * coordinates into "world" coordinates. - * - * @author (C) 1997 Phil Burk, SoftSynth.com - */ - -public class XYController extends JPanel { - double minWorldX = 0.0; - double maxWorldX = 1.0; - double minWorldY = 0.0; - double maxWorldY = 1.0; - - public XYController() { - } - - public XYController(double minWX, double minWY, double maxWX, double maxWY) { - setMinWorldX(minWX); - setMaxWorldX(maxWX); - setMinWorldY(minWY); - setMaxWorldY(maxWY); - } - - /** - * Set minimum World coordinate value for the horizontal X dimension. The minimum value - * corresponds to the left of the component. - */ - public void setMinWorldX(double minWX) { - minWorldX = minWX; - } - - public double getMinWorldX() { - return minWorldX; - } - - /** - * Set maximum World coordinate value for the horizontal X dimension. The minimum value - * corresponds to the right of the component. - */ - public void setMaxWorldX(double maxWX) { - maxWorldX = maxWX; - } - - public double getMaxWorldX() { - return maxWorldX; - } - - /** - * Set minimum World coordinate value for the vertical Y dimension. The minimum value - * corresponds to the bottom of the component. - */ - public void setMinWorldY(double minWY) { - minWorldY = minWY; - } - - public double getMinWorldY() { - return minWorldY; - } - - /** - * Set maximum World coordinate value for the vertical Y dimension. The maximum value - * corresponds to the top of the component. - */ - public void setMaxWorldY(double maxWY) { - maxWorldY = maxWY; - } - - public double getMaxWorldY() { - return maxWorldY; - } - - /** Convert from graphics coordinates (pixels) to world coordinates. */ - public double convertGXtoWX(int gx) { - int width = getWidth(); - return minWorldX + ((maxWorldX - minWorldX) * gx) / width; - } - - public double convertGYtoWY(int gy) { - int height = getHeight(); - return minWorldY + ((maxWorldY - minWorldY) * (height - gy)) / height; - } - - /** Convert from world coordinates to graphics coordinates (pixels). */ - public int convertWXtoGX(double wx) { - int width = getWidth(); - return (int) (((wx - minWorldX) * width) / (maxWorldX - minWorldX)); - } - - public int convertWYtoGY(double wy) { - int height = getHeight(); - return height - (int) (((wy - minWorldY) * height) / (maxWorldY - minWorldY)); - } - - /** Clip wx to the min and max World X values. */ - public double clipWorldX(double wx) { - if (wx < minWorldX) - wx = minWorldX; - else if (wx > maxWorldX) - wx = maxWorldX; - return wx; - } - - /** Clip wy to the min and max World Y values. */ - public double clipWorldY(double wy) { - if (wy < minWorldY) - wy = minWorldY; - else if (wy > maxWorldY) - wy = maxWorldY; - return wy; - } - -} diff --git a/src/com/jsyn/unitgen/Add.java b/src/com/jsyn/unitgen/Add.java deleted file mode 100644 index 5a2a24c..0000000 --- a/src/com/jsyn/unitgen/Add.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * This unit performs a signed addition on its two inputs. <br> - * - * <pre> - * output = inputA + inputB - * </pre> - * - * <br> - * Note that signals connected to an InputPort are automatically added together so you may not need - * this unit. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see MultiplyAdd - * @see Subtract - */ -public class Add extends UnitBinaryOperator { - - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] outputs = output.getValues(); - - // System.out.println("adder = " + this); - // System.out.println("A = " + aValues[0]); - for (int i = start; i < limit; i++) { - outputs[i] = aValues[i] + bValues[i]; - } - // System.out.println("add out = " + outputs[0]); - } -} diff --git a/src/com/jsyn/unitgen/AsymptoticRamp.java b/src/com/jsyn/unitgen/AsymptoticRamp.java deleted file mode 100644 index 8b51294..0000000 --- a/src/com/jsyn/unitgen/AsymptoticRamp.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2009 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.UnitVariablePort; - -/** - * Output approaches Input exponentially. This unit provides a slowly changing value that approaches - * its Input value exponentially. The equation is: - * - * <PRE> - * Output = Output + Rate * (Input - Output); - * </PRE> - * - * Note that the output may never reach the value of the input. It approaches the input - * asymptotically. The Rate is calculated internally based on the value on the halfLife port. Rate - * is generally just slightly less than 1.0. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see LinearRamp - * @see ExponentialRamp - * @see ContinuousRamp - */ -public class AsymptoticRamp extends UnitFilter { - public UnitVariablePort current; - public UnitInputPort halfLife; - private double previousHalfLife = -1.0; - private double decayScalar = 0.99; - - /* Define Unit Ports used by connect() and set(). */ - public AsymptoticRamp() { - addPort(halfLife = new UnitInputPort(1, "HalfLife", 0.1)); - addPort(current = new UnitVariablePort("Current")); - } - - @Override - public void generate(int start, int limit) { - double[] outputs = output.getValues(); - double[] inputs = input.getValues(); - double currentHalfLife = halfLife.getValues()[0]; - double currentValue = current.getValue(); - double inputValue = currentValue; - - if (currentHalfLife != previousHalfLife) { - decayScalar = this.convertHalfLifeToMultiplier(currentHalfLife); - previousHalfLife = currentHalfLife; - } - - for (int i = start; i < limit; i++) { - inputValue = inputs[i]; - currentValue = currentValue + decayScalar * (inputValue - currentValue); - outputs[i] = currentValue; - } - - /* - * When current gets close to input, set current to input to prevent FP underflow, which can - * cause a severe performance degradation in 'C'. - */ - if (Math.abs(inputValue - currentValue) < VERY_SMALL_FLOAT) { - currentValue = inputValue; - } - - current.setValue(currentValue); - } -} diff --git a/src/com/jsyn/unitgen/BrownNoise.java b/src/com/jsyn/unitgen/BrownNoise.java deleted file mode 100644 index e70b7f4..0000000 --- a/src/com/jsyn/unitgen/BrownNoise.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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; -import com.jsyn.util.PseudoRandom; - -/** - * BrownNoise unit. This unit uses a pseudo-random number generator to produce a noise related to - * Brownian Motion. A DC blocker is used to prevent runaway drift. - * - * <pre> - * <code> - * output = (previous * (1.0 - damping)) + (random * amplitude) - * </code> - * </pre> - * - * The output drifts quite a bit and will generally exceed the range of +/1 amplitude. - * - * @author (C) 1997-2011 Phil Burk, Mobileer Inc - * @see WhiteNoise - * @see RedNoise - * @see PinkNoise - */ -public class BrownNoise extends UnitGenerator implements UnitSource { - private PseudoRandom randomNum; - /** Increasing the damping will effectively increase the cutoff - * frequency of a high pass filter that is used to block DC bias. - * Warning: setting this too close to zero can result in very large output values. - */ - public UnitInputPort damping; - public UnitInputPort amplitude; - public UnitOutputPort output; - private double previous; - - public BrownNoise() { - randomNum = new PseudoRandom(); - addPort(damping = new UnitInputPort("Damping")); - damping.setup(0.0001, 0.01, 0.1); - addPort(amplitude = new UnitInputPort("Amplitude", UnitOscillator.DEFAULT_AMPLITUDE)); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - double damper = 1.0 - damping.getValues()[0]; - - for (int i = start; i < limit; i++) { - double r = randomNum.nextRandomDouble() * amplitudes[i]; - outputs[i] = previous = (damper * previous) + r; - } - } - - @Override - public UnitOutputPort getOutput() { - return output; - } -} diff --git a/src/com/jsyn/unitgen/ChannelIn.java b/src/com/jsyn/unitgen/ChannelIn.java deleted file mode 100644 index c440b4f..0000000 --- a/src/com/jsyn/unitgen/ChannelIn.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2009 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.UnitOutputPort; - -/** - * Provides access to one specific channel of the audio input. For ChannelIn to work you must call - * the {@link com.jsyn.Synthesizer} start() method with numInputChannels > 0. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see ChannelOut - * @see LineIn - */ -public class ChannelIn extends UnitGenerator { - public UnitOutputPort output; - private int channelIndex; - - public ChannelIn() { - this(0); - } - - public ChannelIn(int channelIndex) { - addPort(output = new UnitOutputPort()); - setChannelIndex(channelIndex); - } - - public int getChannelIndex() { - return channelIndex; - } - - public void setChannelIndex(int channelIndex) { - this.channelIndex = channelIndex; - } - - @Override - public void generate(int start, int limit) { - double[] outputs = output.getValues(0); - double[] buffer = synthesisEngine.getInputBuffer(channelIndex); - for (int i = start; i < limit; i++) { - outputs[i] = buffer[i]; - } - } - -} diff --git a/src/com/jsyn/unitgen/ChannelOut.java b/src/com/jsyn/unitgen/ChannelOut.java deleted file mode 100644 index 8ef0677..0000000 --- a/src/com/jsyn/unitgen/ChannelOut.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Provides access to one channel of the audio output. - * For more than two channels you must call - * the {@link com.jsyn.Synthesizer} start() method with numOutputChannels > 2. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see ChannelIn - */ -public class ChannelOut extends UnitGenerator { - public UnitInputPort input; - private int channelIndex; - - public ChannelOut() { - addPort(input = new UnitInputPort("Input")); - } - - public int getChannelIndex() { - return channelIndex; - } - - public void setChannelIndex(int channelIndex) { - this.channelIndex = channelIndex; - } - - /** - * This unit won't do anything unless you start() it. - */ - @Override - public boolean isStartRequired() { - return true; - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(0); - double[] buffer = synthesisEngine.getOutputBuffer(channelIndex); - for (int i = start; i < limit; i++) { - buffer[i] += inputs[i]; - } - } - -} diff --git a/src/com/jsyn/unitgen/Circuit.java b/src/com/jsyn/unitgen/Circuit.java deleted file mode 100644 index 01cb860..0000000 --- a/src/com/jsyn/unitgen/Circuit.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2009 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 java.util.ArrayList; -import java.util.LinkedHashMap; - -import com.jsyn.engine.SynthesisEngine; -import com.jsyn.ports.UnitPort; - -/** - * Contains a list of units that are executed together. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class Circuit extends UnitGenerator { - private ArrayList<UnitGenerator> units = new ArrayList<UnitGenerator>(); - - private final LinkedHashMap<String, UnitPort> portAliases = new LinkedHashMap<String, UnitPort>(); - - @Override - public void generate(int start, int limit) { - for (UnitGenerator unit : units) { - unit.generate(start, limit); - } - } - - /** - * Call flattenOutputs on subunits. Flatten output ports so we don't output a changing signal - * when stopped. - */ - @Override - public void flattenOutputs() { - for (UnitGenerator unit : units) { - unit.flattenOutputs(); - } - } - - /** - * Call setEnabled on subunits. - */ - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - for (UnitGenerator unit : units) { - unit.setEnabled(enabled); - } - } - - /** - * @deprecated ignored, frameRate comes from the SynthesisEngine - * @param frameRate - */ - @Deprecated - @Override - public void setFrameRate(int frameRate) { - super.setFrameRate(frameRate); - for (UnitGenerator unit : units) { - unit.setFrameRate(frameRate); - } - } - - @Override - public void setSynthesisEngine(SynthesisEngine engine) { - super.setSynthesisEngine(engine); - for (UnitGenerator unit : units) { - unit.setSynthesisEngine(engine); - } - } - - /** Add a unit to the circuit. */ - public void add(UnitGenerator unit) { - units.add(unit); - unit.setCircuit(this); - // Propagate circuit properties down into subunits. - unit.setEnabled(isEnabled()); - } - - public void usePreset(int presetIndex) { - } - - - /** - * Add an alternate name for looking up a port. - * @param port - * @param alias - */ - public void addPortAlias(UnitPort port, String alias) { - // Store in a hash table by an alternate name. - portAliases.put(alias.toLowerCase(), port); - } - - - /** - * Case-insensitive search for a port by its name or alias. - * @param portName - * @return matching port or null - */ - @Override - public UnitPort getPortByName(String portName) { - UnitPort port = super.getPortByName(portName); - if (port == null) { - port = portAliases.get(portName.toLowerCase()); - } - return port; - } - -} diff --git a/src/com/jsyn/unitgen/Compare.java b/src/com/jsyn/unitgen/Compare.java deleted file mode 100644 index 7de2e53..0000000 --- a/src/com/jsyn/unitgen/Compare.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * - Output 1.0 if inputA > inputB. Otherwise output 0.0. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see Maximum - */ -public class Compare extends UnitBinaryOperator { - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = (aValues[i] > bValues[i]) ? 1.0 : 0.0; - } - } -} diff --git a/src/com/jsyn/unitgen/ContinuousRamp.java b/src/com/jsyn/unitgen/ContinuousRamp.java deleted file mode 100644 index dd90445..0000000 --- a/src/com/jsyn/unitgen/ContinuousRamp.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2009 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.UnitVariablePort; - -/** - * A ramp whose function over time is continuous in value and in slope. Also called an "S curve". - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see LinearRamp - * @see ExponentialRamp - * @see AsymptoticRamp - */ -public class ContinuousRamp extends UnitFilter { - public UnitVariablePort current; - /** - * Time it takes to get from current value to input value when input is changed. Default value - * is 1.0 seconds. - */ - public UnitInputPort time; - private double previousInput = Double.MIN_VALUE; - // Coefficients for cubic polynomial. - private double a; - private double b; - private double d; - private int framesLeft; - - /* Define Unit Ports used by connect() and set(). */ - public ContinuousRamp() { - addPort(time = new UnitInputPort(1, "Time", 1.0)); - addPort(current = new UnitVariablePort("Current")); - } - - @Override - public void generate(int start, int limit) { - double[] outputs = output.getValues(); - double[] inputs = input.getValues(); - double currentTime = time.getValues()[0]; - double currentValue = current.getValue(); - double inputValue = currentValue; - - for (int i = start; i < limit; i++) { - inputValue = inputs[i]; - double x; - if (inputValue != previousInput) { - x = framesLeft; - // Calculate coefficients. - double currentSlope = x * ((3 * a * x) + (2 * b)); - - framesLeft = (int) (getSynthesisEngine().getFrameRate() * currentTime); - if (framesLeft < 1) { - framesLeft = 1; - } - x = framesLeft; - // Calculate coefficients. - d = inputValue; - double xsq = x * x; - b = ((3 * currentValue) - (currentSlope * x) - (3 * d)) / xsq; - a = (currentSlope - (2 * b * x)) / (3 * xsq); - previousInput = inputValue; - } - - if (framesLeft > 0) { - x = --framesLeft; - // Cubic polynomial. c==0 - currentValue = (x * (x * ((x * a) + b))) + d; - } - - outputs[i] = currentValue; - } - - current.setValue(currentValue); - } -} diff --git a/src/com/jsyn/unitgen/CrossFade.java b/src/com/jsyn/unitgen/CrossFade.java deleted file mode 100644 index 4375fa6..0000000 --- a/src/com/jsyn/unitgen/CrossFade.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Linear CrossFade between parts of the input. - * <P> - * Mix input[0] and input[1] based on the value of "fade". When fade is -1, output is all input[0]. - * When fade is 0, output is half input[0] and half input[1]. When fade is +1, output is all - * input[1]. - * <P> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see Pan - */ -public class CrossFade extends UnitGenerator { - public UnitInputPort input; - public UnitInputPort fade; - public UnitOutputPort output; - - /* Define Unit Ports used by connect() and set(). */ - public CrossFade() { - addPort(input = new UnitInputPort(2, "Input")); - addPort(fade = new UnitInputPort("Fade")); - fade.setup(-1.0, 0.0, 1.0); - addPort(output = new UnitOutputPort()); - } - - @Override - public void generate(int start, int limit) { - double[] input0s = input.getValues(0); - double[] input1s = input.getValues(1); - double[] fades = fade.getValues(); - double[] outputs = output.getValues(); - for (int i = start; i < limit; i++) { - // Scale and offset to 0.0 to 1.0 range. - double gain = (fades[i] * 0.5) + 0.5; - outputs[i] = (input0s[i] * (1.0 - gain)) + (input1s[i] * gain); - } - } - -} diff --git a/src/com/jsyn/unitgen/Delay.java b/src/com/jsyn/unitgen/Delay.java deleted file mode 100644 index aa450a9..0000000 --- a/src/com/jsyn/unitgen/Delay.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Simple non-interpolating delay. The delay line must be allocated by calling allocate(n). - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see InterpolatingDelay - */ - -public class Delay extends UnitFilter { - private float[] buffer; - private int cursor; - private int numSamples; - - /** - * Allocate an internal array for the delay line. - * - * @param numSamples - */ - public void allocate(int numSamples) { - this.numSamples = numSamples; - buffer = new float[numSamples]; - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = buffer[cursor]; - buffer[cursor] = (float) inputs[i]; - cursor += 1; - if (cursor >= numSamples) { - cursor = 0; - } - } - } - -} diff --git a/src/com/jsyn/unitgen/Divide.java b/src/com/jsyn/unitgen/Divide.java deleted file mode 100644 index cddcd7c..0000000 --- a/src/com/jsyn/unitgen/Divide.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * This unit divides its two inputs. <br> - * - * <pre> - * output = inputA / inputB - * </pre> - * - * <br> - * Note that this unit is protected from dividing by zero. But you can still get some very big - * outputs. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see Multiply - * @see Subtract - */ -public class Divide extends UnitBinaryOperator { - - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] outputs = output.getValues(); - for (int i = start; i < limit; i++) { - /* Prevent divide by zero crash. */ - double b = bValues[i]; - if (b == 0.0) { - b = 0.0000001; - } - - outputs[i] = aValues[i] / b; - } - } - -} diff --git a/src/com/jsyn/unitgen/DualInTwoOut.java b/src/com/jsyn/unitgen/DualInTwoOut.java deleted file mode 100644 index ec7dff5..0000000 --- a/src/com/jsyn/unitgen/DualInTwoOut.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * This unit splits a dual (stereo) input to two discrete outputs. <br> - * - * <pre> - * outputA = input[0]; - * outputB = input[1]; - * </pre> - * - * <br> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - */ - -public class DualInTwoOut extends UnitGenerator { - public UnitInputPort input; - public UnitOutputPort outputA; - public UnitOutputPort outputB; - - public DualInTwoOut() { - addPort(input = new UnitInputPort(2, "Input")); - addPort(outputA = new UnitOutputPort("OutputA")); - addPort(outputB = new UnitOutputPort("OutputB")); - } - - @Override - public void generate(int start, int limit) { - double[] input0s = input.getValues(0); - double[] input1s = input.getValues(1); - double[] outputAs = outputA.getValues(); - double[] outputBs = outputB.getValues(); - - for (int i = start; i < limit; i++) { - outputAs[i] = input0s[i]; - outputBs[i] = input1s[i]; - } - } -} diff --git a/src/com/jsyn/unitgen/EdgeDetector.java b/src/com/jsyn/unitgen/EdgeDetector.java deleted file mode 100644 index e314f7d..0000000 --- a/src/com/jsyn/unitgen/EdgeDetector.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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; - -/** - * Output 1.0 if the input crosses from zero while rising. Otherwise output zero. The output is a - * single sample wide impulse. This can be used with a Latch to implement a "sample and hold" - * circuit. - * - * @author (C) 1997-2010 Phil Burk, Mobileer Inc - * @see Latch - */ -public class EdgeDetector extends UnitFilter { - private double previous = 0.0; - - public EdgeDetector() { - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - double in = inputs[i]; - outputs[i] = ((previous <= 0.0) && (in > 0.0)) ? 1.0 : 0.0; - previous = in; - } - } -} diff --git a/src/com/jsyn/unitgen/EnvelopeAttackDecay.java b/src/com/jsyn/unitgen/EnvelopeAttackDecay.java deleted file mode 100644 index db3ecaa..0000000 --- a/src/com/jsyn/unitgen/EnvelopeAttackDecay.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.engine.SynthesisEngine; -import com.jsyn.ports.UnitInputPort; - -/** - * Two stage Attack/Decay envelope that is triggered by an input level greater than THRESHOLD. This - * does not sustain. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class EnvelopeAttackDecay extends UnitGate { - public static final double THRESHOLD = 0.01; - private static final double MIN_DURATION = (1.0 / 100000.0); - - /** - * Time in seconds for the rising stage of the envelope to go from 0.0 to 1.0. The attack is a - * linear ramp. - */ - public UnitInputPort attack; - /** - * Time in seconds for the falling stage to go from 0 dB to -90 dB. - */ - public UnitInputPort decay; - - public UnitInputPort amplitude; - - private enum State { - IDLE, ATTACKING, DECAYING - } - - private State state = State.IDLE; - private double scaler = 1.0; - private double level; - private double increment; - - public EnvelopeAttackDecay() { - super(); - addPort(attack = new UnitInputPort("Attack")); - attack.setup(0.001, 0.05, 8.0); - addPort(decay = new UnitInputPort("Decay")); - decay.setup(0.001, 0.2, 8.0); - addPort(amplitude = new UnitInputPort("Amplitude", 1.0)); - startIdle(); - } - - public void export(Circuit circuit, String prefix) { - circuit.addPort(attack, prefix + attack.getName()); - circuit.addPort(decay, prefix + decay.getName()); - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit;) { - boolean triggered = input.checkGate(i); - switch (state) { - case IDLE: - for (; i < limit; i++) { - outputs[i] = level; - if (triggered) { - startAttack(i); - break; - } - } - break; - case ATTACKING: - for (; i < limit; i++) { - // Increment first so we can render fast attacks. - level += increment; - if (level >= 1.0) { - level = 1.0; - outputs[i] = level * amplitudes[i]; - startDecay(i); - break; - } - outputs[i] = level * amplitudes[i]; - } - break; - case DECAYING: - for (; i < limit; i++) { - outputs[i] = level * amplitudes[i]; - level *= scaler; - if (triggered) { - startAttack(i); - break; - } else if (level < SynthesisEngine.DB90) { - input.checkAutoDisable(); - startIdle(); - break; - } - } - break; - } - } - } - - private void startIdle() { - state = State.IDLE; - level = 0.0; - } - - private void startAttack(int i) { - double[] attacks = attack.getValues(); - double duration = attacks[i]; - if (duration < MIN_DURATION) { - level = 1.0; - startDecay(i); - } else { - // assume going from 0.0 to 1.0 even if retriggering - increment = getFramePeriod() / duration; - state = State.ATTACKING; - } - } - - private void startDecay(int i) { - double[] decays = decay.getValues(); - double duration = decays[i]; - if (duration < MIN_DURATION) { - startIdle(); - } else { - scaler = getSynthesisEngine().convertTimeToExponentialScaler(duration); - state = State.DECAYING; - } - } - -} diff --git a/src/com/jsyn/unitgen/EnvelopeDAHDSR.java b/src/com/jsyn/unitgen/EnvelopeDAHDSR.java deleted file mode 100644 index c5ebe83..0000000 --- a/src/com/jsyn/unitgen/EnvelopeDAHDSR.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.data.SegmentedEnvelope; -import com.jsyn.engine.SynthesisEngine; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; - -/** - * Six stage envelope similar to an ADSR. DAHDSR is like an ADSR but with an additional Delay stage - * before the attack, and a Hold stage after the Attack. If Delay and Hold are both set to zero then - * it will act like an ADSR. The envelope is triggered when the input goes above THRESHOLD. The - * envelope is released when the input goes below THRESHOLD. The THRESHOLD is currently 0.01 but may - * change so it would be best to use an input signal that went from 0 to 1. Mathematically an - * exponential Release will never reach 0.0. But when it reaches -96 dB the DAHDSR just sets its - * output to 0.0 and stops. There is an example program in the ZIP archive called HearDAHDSR. It - * drives a DAHDSR with a square wave. - * - * @author Phil Burk (C) 2010 Mobileer Inc - * @see SegmentedEnvelope - */ -public class EnvelopeDAHDSR extends UnitGate implements UnitSource { - private static final double MIN_DURATION = (1.0 / 100000.0); - - /** - * Time in seconds for first stage of the envelope, before the attack. Typically zero. - */ - public UnitInputPort delay; - /** - * Time in seconds for the rising stage of the envelope to go from 0.0 to 1.0. The attack is a - * linear ramp. - */ - public UnitInputPort attack; - /** Time in seconds for the plateau between the attack and decay stages. */ - public UnitInputPort hold; - /** - * Time in seconds for the falling stage to go from 0 dB to -90 dB. The decay stage will stop at - * the sustain level. But we calculate the time to fall to -90 dB so that the decay - * <em>rate</em> will be unaffected by the sustain level. - */ - public UnitInputPort decay; - /** - * Level for the sustain stage. The envelope will hold here until the input goes to zero or - * less. This should be set between 0.0 and 1.0. - */ - public UnitInputPort sustain; - /** - * Time in seconds to go from 0 dB to -90 dB. This stage is triggered when the input goes to - * zero or less. The release stage will start from the sustain level. But we calculate the time - * to fall from full amplitude so that the release <em>rate</em> will be unaffected by the - * sustain level. - */ - public UnitInputPort release; - public UnitInputPort amplitude; - - enum State { - IDLE, DELAYING, ATTACKING, HOLDING, DECAYING, SUSTAINING, RELEASING - } - - private State state = State.IDLE; - private double countdown; - private double scaler = 1.0; - private double level; - private double increment; - - public EnvelopeDAHDSR() { - super(); - addPort(delay = new UnitInputPort("Delay", 0.0)); - delay.setup(0.0, 0.0, 2.0); - addPort(attack = new UnitInputPort("Attack", 0.1)); - attack.setup(0.01, 0.1, 8.0); - addPort(hold = new UnitInputPort("Hold", 0.0)); - hold.setup(0.0, 0.0, 2.0); - addPort(decay = new UnitInputPort("Decay", 0.2)); - decay.setup(0.01, 0.2, 8.0); - addPort(sustain = new UnitInputPort("Sustain", 0.5)); - sustain.setup(0.0, 0.5, 1.0); - addPort(release = new UnitInputPort("Release", 0.3)); - release.setup(0.01, 0.3, 8.0); - addPort(amplitude = new UnitInputPort("Amplitude", 1.0)); - } - - @Override - public void generate(int start, int limit) { - double[] sustains = sustain.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit;) { - boolean triggered = input.checkGate(i); - switch (state) { - case IDLE: - for (; i < limit; i++) { - outputs[i] = level * amplitudes[i]; - if (triggered) { - startDelay(i); - break; - } - } - break; - - case DELAYING: - for (; i < limit; i++) { - outputs[i] = level * amplitudes[i]; - if (input.isOff()) { - startRelease(i); - break; - } else { - countdown -= 1; - if (countdown <= 0) { - startAttack(i); - break; - } - } - } - break; - - case ATTACKING: - for (; i < limit; i++) { - // Increment first so we can render fast attacks. - level += increment; - if (level >= 1.0) { - level = 1.0; - outputs[i] = level * amplitudes[i]; - startHold(i); - break; - } else { - outputs[i] = level * amplitudes[i]; - if (input.isOff()) { - startRelease(i); - break; - } - } - } - break; - - case HOLDING: - for (; i < limit; i++) { - outputs[i] = amplitudes[i]; // level is 1.0 - countdown -= 1; - if (countdown <= 0) { - startDecay(i); - break; - } else if (input.isOff()) { - startRelease(i); - break; - } - } - break; - - case DECAYING: - for (; i < limit; i++) { - outputs[i] = level * amplitudes[i]; - level *= scaler; // exponential decay - if (triggered) { - startDelay(i); - break; - } else if (level < sustains[i]) { - level = sustains[i]; - startSustain(i); - break; - } else if (level < SynthesisEngine.DB96) { - input.checkAutoDisable(); - startIdle(); - break; - } else if (input.isOff()) { - startRelease(i); - break; - } - } - break; - - case SUSTAINING: - for (; i < limit; i++) { - level = sustains[i]; - outputs[i] = level * amplitudes[i]; - if (triggered) { - startDelay(i); - break; - } else if (input.isOff()) { - startRelease(i); - break; - } - } - break; - - case RELEASING: - for (; i < limit; i++) { - outputs[i] = level * amplitudes[i]; - level *= scaler; // exponential decay - if (triggered) { - startDelay(i); - break; - } else if (level < SynthesisEngine.DB96) { - input.checkAutoDisable(); - startIdle(); - break; - } - } - break; - } - } - } - - private void startIdle() { - state = State.IDLE; - level = 0.0; - } - - private void startDelay(int i) { - double[] delays = delay.getValues(); - if (delays[i] <= 0.0) { - startAttack(i); - } else { - countdown = (int) (delays[i] * getFrameRate()); - state = State.DELAYING; - } - } - - private void startAttack(int i) { - double[] attacks = attack.getValues(); - double duration = attacks[i]; - if (duration < MIN_DURATION) { - level = 1.0; - startHold(i); - } else { - increment = getFramePeriod() / duration; - state = State.ATTACKING; - } - } - - private void startHold(int i) { - double[] holds = hold.getValues(); - if (holds[i] <= 0.0) { - startDecay(i); - } else { - countdown = (int) (holds[i] * getFrameRate()); - state = State.HOLDING; - } - } - - private void startDecay(int i) { - double[] decays = decay.getValues(); - double duration = decays[i]; - if (duration < MIN_DURATION) { - startSustain(i); - } else { - scaler = getSynthesisEngine().convertTimeToExponentialScaler(duration); - state = State.DECAYING; - } - } - - private void startSustain(int i) { - state = State.SUSTAINING; - } - - private void startRelease(int i) { - double[] releases = release.getValues(); - double duration = releases[i]; - if (duration < MIN_DURATION) { - duration = MIN_DURATION; - } - scaler = getSynthesisEngine().convertTimeToExponentialScaler(duration); - state = State.RELEASING; - } - - public void export(Circuit circuit, String prefix) { - circuit.addPort(attack, prefix + attack.getName()); - circuit.addPort(decay, prefix + decay.getName()); - circuit.addPort(sustain, prefix + sustain.getName()); - circuit.addPort(release, prefix + release.getName()); - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - -} diff --git a/src/com/jsyn/unitgen/ExponentialRamp.java b/src/com/jsyn/unitgen/ExponentialRamp.java deleted file mode 100644 index 36159b4..0000000 --- a/src/com/jsyn/unitgen/ExponentialRamp.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitVariablePort; - -/** - * Output approaches Input exponentially and will reach it in the specified time. - * - * @author Phil Burk (C) 2010 Mobileer Inc - * @version 016 - * @see LinearRamp - * @see AsymptoticRamp - * @see ContinuousRamp - */ -public class ExponentialRamp extends UnitFilter { - public UnitInputPort time; - public UnitVariablePort current; - - private double target; - private double timeHeld = 0.0; - private double scaler = 1.0; - - public ExponentialRamp() { - addPort(time = new UnitInputPort("Time")); - input.setup(0.0001, 1.0, 1.0); - addPort(current = new UnitVariablePort("Current", 1.0)); - } - - @Override - public void generate(int start, int limit) { - double[] outputs = output.getValues(); - double currentInput = input.getValues()[0]; - double currentTime = time.getValues()[0]; - double currentValue = current.getValue(); - - if (currentTime != timeHeld) { - scaler = convertTimeToExponentialScaler(currentTime, currentValue, currentInput); - timeHeld = currentTime; - } - - // If input has changed, start new segment. - // Equality check is OK because we set them exactly equal below. - if (currentInput != target) { - scaler = convertTimeToExponentialScaler(currentTime, currentValue, currentInput); - target = currentInput; - } - - if (currentValue < target) { - // Going up. - for (int i = start; i < limit; i++) { - currentValue = currentValue * scaler; - if (currentValue > target) { - currentValue = target; - scaler = 1.0; - } - outputs[i] = currentValue; - } - } else if (currentValue > target) { - // Going down. - for (int i = start; i < limit; i++) { - currentValue = currentValue * scaler; - if (currentValue < target) { - currentValue = target; - scaler = 1.0; - } - outputs[i] = currentValue; - } - - } else if (currentValue == target) { - for (int i = start; i < limit; i++) { - outputs[i] = target; - } - } - - current.setValue(currentValue); - } - - private double convertTimeToExponentialScaler(double duration, double source, double target) { - double product = source * target; - if (product <= 0.0000001) { - throw new IllegalArgumentException( - "Exponential ramp crosses zero or gets too close to zero."); - } - // Calculate scaler so that scaler^frames = target/source - double numFrames = duration * getFrameRate(); - return Math.pow((target / source), (1.0 / numFrames)); - } -} diff --git a/src/com/jsyn/unitgen/FFT.java b/src/com/jsyn/unitgen/FFT.java deleted file mode 100644 index 63fce50..0000000 --- a/src/com/jsyn/unitgen/FFT.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013 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; - -/** - * Periodically transform the complex input signal using an FFT to a complex spectral stream. This - * is probably not as useful as the SpectralFFT, which outputs complete spectra. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @see IFFT - * @see SpectralFFT - */ -public class FFT extends FFTBase { - public FFT() { - super(); - } - - @Override - protected int getSign() { - return 1; // 1 for FFT - } -} diff --git a/src/com/jsyn/unitgen/FFTBase.java b/src/com/jsyn/unitgen/FFTBase.java deleted file mode 100644 index 055c04b..0000000 --- a/src/com/jsyn/unitgen/FFTBase.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2013 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.data.Spectrum; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; -import com.softsynth.math.FourierMath; - -/** - * Periodically transform the complex input signal using an FFT to a complex spectral stream. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @version 016 - * @see IFFT - */ -public abstract class FFTBase extends UnitGenerator { - public UnitInputPort inputReal; - public UnitInputPort inputImaginary; - public UnitOutputPort outputReal; - public UnitOutputPort outputImaginary; - protected double[] realInput; - protected double[] realOutput; - protected double[] imaginaryInput; - protected double[] imaginaryOutput; - protected int cursor; - - protected FFTBase() { - addPort(inputReal = new UnitInputPort("InputReal")); - addPort(inputImaginary = new UnitInputPort("InputImaginary")); - addPort(outputReal = new UnitOutputPort("OutputReal")); - addPort(outputImaginary = new UnitOutputPort("OutputImaginary")); - setSize(Spectrum.DEFAULT_SIZE); - } - - public void setSize(int size) { - realInput = new double[size]; - realOutput = new double[size]; - imaginaryInput = new double[size]; - imaginaryOutput = new double[size]; - cursor = 0; - } - - public int getSize() { - return realInput.length; - } - - @Override - public void generate(int start, int limit) { - double[] inputRs = inputReal.getValues(); - double[] inputIs = inputImaginary.getValues(); - double[] outputRs = outputReal.getValues(); - double[] outputIs = outputImaginary.getValues(); - for (int i = start; i < limit; i++) { - realInput[cursor] = inputRs[i]; - imaginaryInput[cursor] = inputIs[i]; - outputRs[i] = realOutput[cursor]; - outputIs[i] = imaginaryOutput[cursor]; - cursor += 1; - // When it is full, do the FFT. - if (cursor == realInput.length) { - // Copy to output buffer so we can do the FFT in place. - System.arraycopy(realInput, 0, realOutput, 0, realInput.length); - System.arraycopy(imaginaryInput, 0, imaginaryOutput, 0, imaginaryInput.length); - FourierMath.transform(getSign(), realOutput.length, realOutput, imaginaryOutput); - cursor = 0; - } - } - } - - protected abstract int getSign(); -} diff --git a/src/com/jsyn/unitgen/FilterAllPass.java b/src/com/jsyn/unitgen/FilterAllPass.java deleted file mode 100644 index 749b2d6..0000000 --- a/src/com/jsyn/unitgen/FilterAllPass.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * AllPass filter using the following formula: - * - * <pre> - * y(n) = -gain * x(n) + x(n - 1) + gain * y(n - 1) - * </pre> - * - * where y(n) is Output, x(n) is Input, x(n-1) is a delayed copy of the input, and y(n-1) is a - * delayed copy of the output. An all-pass filter will pass all frequencies with equal amplitude. - * But it changes the phase relationships of the partials by delaying them by an amount proportional - * to their wavelength,. - * - * @author (C) 2014 Phil Burk, SoftSynth.com - * @see FilterLowPass - */ - -public class FilterAllPass extends UnitFilter { - /** Feedback gain. Should be less than 1.0. Default is 0.8. */ - public UnitInputPort gain; - - private double x1; - private double y1; - - public FilterAllPass() { - addPort(gain = new UnitInputPort("Gain", 0.8)); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double g = gain.getValue(); - - for (int i = start; i < limit; i++) { - double x0 = inputs[i]; - y1 = (g * (y1 - x0)) + x1; - x1 = x0; - outputs[i] = y1; - } - - } -} diff --git a/src/com/jsyn/unitgen/FilterBandPass.java b/src/com/jsyn/unitgen/FilterBandPass.java deleted file mode 100644 index b103400..0000000 --- a/src/com/jsyn/unitgen/FilterBandPass.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2009 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. - */ -/** - * Aug 21, 2009 - * com.jsyn.engine.units.Filter_HighPass.java - */ - -package com.jsyn.unitgen; - -/** - * Filter that allows frequencies around the center frequency to pass and blocks others. This filter - * is based on the BiQuad filter. Coefficients are updated whenever the frequency or Q changes. - * - * @author Phil Burk (C) 2009 Mobileer Inc Translated from 'C' to Java by Lisa - * Tolentino. - */ -public class FilterBandPass extends FilterBiquadCommon { - /** - * This method is by Filter_Biquad to update coefficients for the Filter_BandPass filter. - */ - @Override - public void updateCoefficients() { - double scalar = 1.0 / (1.0 + alpha); - - a0 = alpha * scalar; - a1 = 0.0; - a2 = -a0; - b1 = -2.0 * cos_omega * scalar; - b2 = (1.0 - alpha) * scalar; - } -} diff --git a/src/com/jsyn/unitgen/FilterBandStop.java b/src/com/jsyn/unitgen/FilterBandStop.java deleted file mode 100644 index d4f5249..0000000 --- a/src/com/jsyn/unitgen/FilterBandStop.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Filter that blocks frequencies around the center frequency. This filter is based on the BiQuad - * filter. Coefficients are updated whenever the frequency or Q changes. - * - * @author Phil Burk (C) 2009 Mobileer Inc Translated from 'C' to Java by Lisa - * Tolentino. - */ -public class FilterBandStop extends FilterBiquadCommon { - - @Override - public void updateCoefficients() { - - // scalar = 1.0f / (1.0f + BQCM.alpha); - // A1_B1_Value = -2.0f * BQCM.cos_omega * scalar; - // - // csFilter->csFBQ_A0 = scalar; - // csFilter->csFBQ_A1 = A1_B1_Value; - // csFilter->csFBQ_A2 = scalar; - // csFilter->csFBQ_B1 = A1_B1_Value; - // csFilter->csFBQ_B2 = (1.0f - BQCM.alpha) * scalar; - - double scalar = 1.0 / (1.0 + alpha); - double a1_b1_value = -2.0 * cos_omega * scalar; - - this.a0 = scalar; - this.a1 = a1_b1_value; - this.a2 = scalar; - this.b1 = a1_b1_value; - this.b2 = (1.0 - alpha) * scalar; - } -} diff --git a/src/com/jsyn/unitgen/FilterBiquad.java b/src/com/jsyn/unitgen/FilterBiquad.java deleted file mode 100644 index f9b792f..0000000 --- a/src/com/jsyn/unitgen/FilterBiquad.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitInputPort; - -/** - * Base class for a set of IIR filters. - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see FilterBandStop - * @see FilterBandPass - * @see FilterLowPass - * @see FilterHighPass - * @see FilterTwoPolesTwoZeros - */ -public abstract class FilterBiquad extends TunableFilter { - public UnitInputPort amplitude; - - protected static final double MINIMUM_FREQUENCY = 0.00001; - protected static final double MINIMUM_GAIN = 0.00001; - protected static final double RATIO_MINIMUM = 0.499; - protected double a0; - protected double a1; - protected double a2; - protected double b1; - protected double b2; - private double x1; - private double x2; - private double y1; - private double y2; - protected double previousFrequency; - protected double omega; - protected double sin_omega; - protected double cos_omega; - - public FilterBiquad() { - addPort(amplitude = new UnitInputPort("Amplitude", 1.0)); - } - - /** - * Generic generate(int start, int limit) method calls this filter's recalculate() and - * performBiquadFilter(int, int) methods. - */ - @Override - public void generate(int start, int limit) { - recalculate(); - performBiquadFilter(start, limit); - } - - protected abstract void recalculate(); - - /** - * Each filter calls performBiquadFilter() through the generate(int, int) method. This method - * has converted Robert Bristow-Johnson's coefficients for the Direct I form in this way: Here - * is the equation that JSyn uses for this filter: - * - * <pre> - * y(n) = A0*x(n) + A1*x(n-1) + A2*x(n-2) -vB1*y(n-1) - B2*y(n-2) - * </pre> - * - * Here is the equation that Robert Bristow-Johnson uses: - * - * <pre> - * y[n] = (b0/a0)*x[n] + (b1/a0)*x[n-1] + (b2/a0)*x[n-2] - (a1/a0)*y[n-1] - (a2/a0)*y[n-2] - * </pre> - * - * So to translate between JSyn coefficients and RBJ coefficients: - * - * <pre> - * JSyn => RBJ - * A0 => b0/a0 - * A1 => b1/a0 - * A2 => b2/a0 - * B1 => a1/a0 - * B2 => a2/a0 - * </pre> - * - * @param start - * @param limit - */ - public void performBiquadFilter(int start, int limit) { - double[] inputs = input.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - double a0_jsyn, a1_jsyn, a2_jsyn, b1_jsyn, b2_jsyn; - double x0_jsyn, x1_jsyn, x2_jsyn, y1_jsyn, y2_jsyn; - - x1_jsyn = this.x1; - x2_jsyn = this.x2; - - y1_jsyn = this.y1; - y2_jsyn = this.y2; - - a0_jsyn = this.a0; - a1_jsyn = this.a1; - a2_jsyn = this.a2; - - b1_jsyn = this.b1; - b2_jsyn = this.b2; - - // Permute filter operations to reduce data movement. - for (int i = start; i < limit; i += 2) - - { - x0_jsyn = inputs[i]; - y2_jsyn = (a0_jsyn * x0_jsyn) + (a1_jsyn * x1_jsyn) + (a2_jsyn * x2_jsyn) - - (b1_jsyn * y1_jsyn) - (b2_jsyn * y2_jsyn); - - outputs[i] = amplitudes[i] * y2_jsyn; - - x2_jsyn = inputs[i + 1]; - y1_jsyn = (a0_jsyn * x2_jsyn) + (a1_jsyn * x0_jsyn) + (a2_jsyn * x1_jsyn) - - (b1_jsyn * y2_jsyn) - (b2_jsyn * y1_jsyn); - - outputs[i + 1] = amplitudes[i + 1] * y1_jsyn; - - x1_jsyn = x2_jsyn; - x2_jsyn = x0_jsyn; - } - - this.x1 = x1_jsyn; // save filter state for next time - this.x2 = x2_jsyn; - - // apply small bipolar impulse to prevent arithmetic underflow - this.y1 = y1_jsyn + VERY_SMALL_FLOAT; - this.y2 = y2_jsyn - VERY_SMALL_FLOAT; - } - - protected void calculateOmega(double ratio) { - if (ratio >= FilterBiquad.RATIO_MINIMUM) // keep a minimum - // distance from Nyquist - { - ratio = FilterBiquad.RATIO_MINIMUM; - } - - omega = 2.0 * Math.PI * ratio; - cos_omega = Math.cos(omega); // compute cosine - sin_omega = Math.sin(omega); // compute sine - } - -} diff --git a/src/com/jsyn/unitgen/FilterBiquadCommon.java b/src/com/jsyn/unitgen/FilterBiquadCommon.java deleted file mode 100644 index f21c8e7..0000000 --- a/src/com/jsyn/unitgen/FilterBiquadCommon.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Extend this class to create a filter that implements a Biquad filter with a Q port. - * - * @author Phil Burk (C) 2009 Mobileer Inc Translated from 'C' to Java by Lisa - * Tolentino. - */ -public abstract class FilterBiquadCommon extends FilterBiquad { - public UnitInputPort Q; - - protected final static double MINIMUM_Q = 0.00001; - private double previousQ; - protected double alpha; - - /** - * No-argument constructor instantiates the Biquad common and adds a Q port to this filter. - */ - public FilterBiquadCommon() { - addPort(Q = new UnitInputPort("Q")); - Q.setup(0.1, 1.0, 10.0); - } - - /** - * Calculate coefficients based on the filter type, eg. LowPass. - */ - public abstract void updateCoefficients(); - - public void computeBiquadCommon(double ratio, double Q) { - if (ratio >= FilterBiquad.RATIO_MINIMUM) // keep a minimum distance - // from Nyquist - { - ratio = FilterBiquad.RATIO_MINIMUM; - } - - omega = 2.0 * Math.PI * ratio; - cos_omega = Math.cos(omega); // compute cosine - sin_omega = Math.sin(omega); // compute sine - alpha = sin_omega / (2.0 * Q); // set alpha - // System.out.println("Q = " + Q + ", omega = " + omega + - // ", cos(omega) = " + cos_omega + ", alpha = " + alpha ); - } - - /** - * The recalculate() method checks and ensures that the frequency and Q values are at a minimum. - * It also only updates the Biquad coefficients if either frequency or Q have changed. - */ - @Override - public void recalculate() { - double frequencyValue = frequency.getValues()[0]; // grab frequency - // element (we'll - // only use - // element[0]) - double qValue = Q.getValues()[0]; // grab Q element (we'll only use - // element[0]) - - if (frequencyValue < MINIMUM_FREQUENCY) // ensure a minimum frequency - { - frequencyValue = MINIMUM_FREQUENCY; - } - - if (qValue < MINIMUM_Q) // ensure a minimum Q - { - qValue = MINIMUM_Q; - } - // only update changed values - if (isRecalculationNeeded(frequencyValue, qValue)) { - previousFrequency = frequencyValue; // hold previous frequency - previousQ = qValue; // hold previous Q - - double ratio = frequencyValue * getFramePeriod(); - computeBiquadCommon(ratio, qValue); - updateCoefficients(); - } - } - - protected boolean isRecalculationNeeded(double frequencyValue, double qValue) { - return (frequencyValue != previousFrequency) || (qValue != previousQ); - } - -} diff --git a/src/com/jsyn/unitgen/FilterBiquadShelf.java b/src/com/jsyn/unitgen/FilterBiquadShelf.java deleted file mode 100644 index 737d18d..0000000 --- a/src/com/jsyn/unitgen/FilterBiquadShelf.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * This filter is based on the BiQuad filter and is used as a base class for FilterLowShelf and - * FilterHighShelf. Coefficients are updated whenever the frequency, gain or slope changes. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public abstract class FilterBiquadShelf extends FilterBiquad { - protected final static double MINIMUM_SLOPE = 0.00001; - - /** - * Gain of peak. Use 1.0 for flat response. - */ - public UnitInputPort gain; - - /** - * Shelf Slope parameter. When S = 1, the shelf slope is as steep as you can get it and remain - * monotonically increasing or decreasing gain with frequency. - */ - public UnitInputPort slope; - - private double prevGain; - private double prevSlope; - - private double beta; - protected double alpha; - protected double factorA; - protected double AP1; - protected double AM1; - protected double beta_sn; - protected double AP1cs; - protected double AM1cs; - - public FilterBiquadShelf() { - addPort(gain = new UnitInputPort("Gain", 1.0)); - addPort(slope = new UnitInputPort("Slope", 1.0)); - } - - /** - * Abstract method. Each filter must implement its update of coefficients. - */ - public abstract void updateCoefficients(); - - /** - * Compute coefficients for shelf filter if frequency, gain or slope have changed. - */ - @Override - public void recalculate() { - // Just look at first value to save time. - double frequencyValue = frequency.getValues()[0]; - if (frequencyValue < MINIMUM_FREQUENCY) { - frequencyValue = MINIMUM_FREQUENCY; - } - - double gainValue = gain.getValues()[0]; - if (gainValue < MINIMUM_GAIN) { - gainValue = MINIMUM_GAIN; - } - - double slopeValue = slope.getValues()[0]; - if (slopeValue < MINIMUM_SLOPE) { - slopeValue = MINIMUM_SLOPE; - } - - // Only do complex calculations if input changed. - if ((frequencyValue != previousFrequency) || (gainValue != prevGain) - || (slopeValue != prevSlope)) { - previousFrequency = frequencyValue; // hold previous frequency - prevGain = gainValue; - prevSlope = slopeValue; - - double ratio = frequencyValue * getFramePeriod(); - calculateOmega(ratio); - - factorA = Math.sqrt(gainValue); - - AP1 = factorA + 1.0; - AM1 = factorA - 1.0; - - /* Avoid sqrt(r<0) which hangs filter. */ - double beta2 = ((gainValue + 1.0) / slopeValue) - (AM1 * AM1); - beta = (beta2 < 0.0) ? 0.0 : Math.sqrt(beta2); - - beta_sn = beta * sin_omega; - AP1cs = AP1 * cos_omega; - AM1cs = AM1 * cos_omega; - - updateCoefficients(); - } - } - -} diff --git a/src/com/jsyn/unitgen/FilterFourPoles.java b/src/com/jsyn/unitgen/FilterFourPoles.java deleted file mode 100644 index 39a47c7..0000000 --- a/src/com/jsyn/unitgen/FilterFourPoles.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * Resonant filter in the style of the Moog ladder filter. This implementation is loosely based on: - * http://www.musicdsp.org/archive.php?classid=3#26 - * More interesting reading: - * http://dafx04.na.infn.it/WebProc/Proc/P_061.pdf - * http://www.acoustics.ed.ac.uk/wp-content/uploads/AMT_MSc_FinalProjects - * /2012__Daly__AMT_MSc_FinalProject_MoogVCF.pdf - * http://www.music.mcgill.ca/~ich/research/misc/papers/cr1071.pdf - * - * @author Phil Burk (C) 2014 Mobileer Inc - * @see FilterLowPass - */ -public class FilterFourPoles extends TunableFilter { - public UnitInputPort Q; - public UnitInputPort gain; - - private static final double MINIMUM_FREQUENCY = 1.0; // blows up if near 0.01 - private static final double MINIMUM_Q = 0.00001; - - //private static final double SATURATION_COEFFICIENT = 0.1666667; - private static final double SATURATION_COEFFICIENT = 0.2; - // Inflection point where slope is zero. - private static final double SATURATION_UPPER_INPUT = 1.0 / Math.sqrt(3.0 * SATURATION_COEFFICIENT); - private static final double SATURATION_LOWER_INPUT = 0.0 - SATURATION_UPPER_INPUT; - private static final double SATURATION_UPPER_OUTPUT = cubicPolynomial(SATURATION_UPPER_INPUT); - private static final double SATURATION_LOWER_OUTPUT = cubicPolynomial(SATURATION_LOWER_INPUT); - - private double x1; - private double x2; - private double x3; - private double x4; - private double y1; - private double y2; - private double y3; - private double y4; - - private double previousFrequency; - private double previousQ; - // filter coefficients - private double f; - private double fTo4th; - private double feedback; - - private boolean oversampled = true; - - public FilterFourPoles() { - addPort(Q = new UnitInputPort("Q")); - frequency.setup(40.0, DEFAULT_FREQUENCY, 4000.0); - Q.setup(0.1, 2.0, 10.0); - } - - /** - * The recalculate() method checks and ensures that the frequency and Q values are at a minimum. - * It also only updates the coefficients if either frequency or Q have changed. - */ - public void recalculate() { - double frequencyValue = frequency.getValues()[0]; - double qValue = Q.getValues()[0]; - - if (frequencyValue < MINIMUM_FREQUENCY) // ensure a minimum frequency - { - frequencyValue = MINIMUM_FREQUENCY; - } - if (qValue < MINIMUM_Q) // ensure a minimum Q - { - qValue = MINIMUM_Q; - } - - // Only recompute coefficients if changed. - if ((frequencyValue != previousFrequency) || (qValue != previousQ)) { - previousFrequency = frequencyValue; - previousQ = qValue; - computeCoefficients(); - } - } - - private void computeCoefficients() { - double normalizedFrequency = previousFrequency * getFramePeriod(); - double fudge = 4.9 - 0.27 * previousQ; - if (fudge < 3.0) - fudge = 3.0; - f = normalizedFrequency * (oversampled ? 1.0 : 2.0) * fudge; - - double fSquared = f * f; - fTo4th = fSquared * fSquared; - feedback = 0.5 * previousQ * (1.0 - 0.15 * fSquared); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - - recalculate(); - - for (int i = start; i < limit; i++) { - double x0 = inputs[i]; - - if (oversampled) { - oneSample(0.0); - } - oneSample(x0); - outputs[i] = y4; - } - - // apply small bipolar impulse to prevent arithmetic underflow - y1 += VERY_SMALL_FLOAT; - y2 -= VERY_SMALL_FLOAT; - } - - private void oneSample(double x0) { - final double coeff = 0.3; - x0 -= y4 * feedback; // feedback - x0 *= 0.35013 * fTo4th; - y1 = x0 + coeff * x1 + (1 - f) * y1; // pole 1 - x1 = x0; - y2 = y1 + coeff * x2 + (1 - f) * y2; // pole 2 - x2 = y1; - y3 = y2 + coeff * x3 + (1 - f) * y3; // pole 3 - x3 = y2; - y4 = y3 + coeff * x4 + (1 - f) * y4; // pole 4 - y4 = clip(y4); - x4 = y3; - } - - public boolean isOversampled() { - return oversampled; - } - - public void setOversampled(boolean oversampled) { - this.oversampled = oversampled; - } - - // Soft saturation. This used to blow up the filter! - private static double cubicPolynomial(double x) { - return x - (x * x * x * SATURATION_COEFFICIENT); - } - - private static double clip(double x) { - if (x > SATURATION_UPPER_INPUT) { - return SATURATION_UPPER_OUTPUT; - } else if (x < SATURATION_LOWER_INPUT) { - return SATURATION_LOWER_OUTPUT; - } else { - return cubicPolynomial(x); - } - } - - public void reset() { - x1 = 0.0; - x2 = 0.0; - x3 = 0.0; - x4 = 0.0; - y1 = 0.0; - y2 = 0.0; - y3 = 0.0; - y4 = 0.0; - - previousFrequency = 0.0; - previousQ = 0.0; - f = 0.0; - fTo4th = 0.0; - feedback = 0.0; - } -} diff --git a/src/com/jsyn/unitgen/FilterHighPass.java b/src/com/jsyn/unitgen/FilterHighPass.java deleted file mode 100644 index 76ad6b9..0000000 --- a/src/com/jsyn/unitgen/FilterHighPass.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2009 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. - */ -/** - * Aug 21, 2009 - * com.jsyn.engine.units.Filter_HighPass.java - */ - -package com.jsyn.unitgen; - -/** - * Filter that allows frequencies above the center frequency to pass. This filter is based on the - * BiQuad filter. Coefficients are updated whenever the frequency or Q changes. - * - * @author Phil Burk (C) 2009 Mobileer Inc Translated from 'C' to Java by Lisa - * Tolentino. - */ -public class FilterHighPass extends FilterBiquadCommon { - /** - * This method is used by Filter_Biquad to update coefficients for the Filter_HighPass filter. - */ - @Override - public void updateCoefficients() { - double scalar = 1.0 / (1.0 + alpha); - double onePlusCosine = 1.0 + cos_omega; - double a0_a2_value = onePlusCosine * 0.5 * scalar; - - this.a0 = a0_a2_value; - this.a1 = -onePlusCosine * scalar; - this.a2 = a0_a2_value; - this.b1 = -2.0 * cos_omega * scalar; - this.b2 = (1.0 - alpha) * scalar; - } -} diff --git a/src/com/jsyn/unitgen/FilterHighShelf.java b/src/com/jsyn/unitgen/FilterHighShelf.java deleted file mode 100644 index 449090a..0000000 --- a/src/com/jsyn/unitgen/FilterHighShelf.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * HighShelf Filter. This creates a flat response above the cutoff frequency. This filter is - * sometimes used at the end of a bank of EQ filters. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FilterHighShelf extends FilterBiquadShelf { - /** - * This method is called by by Filter_BiquadShelf to update coefficients. - */ - @Override - public void updateCoefficients() { - double scalar = 1.0 / (AP1 - AM1cs + beta_sn); - a0 = factorA * (AP1 + AM1cs + beta_sn) * scalar; - a1 = -2.0 * factorA * (AM1 + AP1cs) * scalar; - a2 = factorA * (AP1 + AM1cs - beta_sn) * scalar; - b1 = 2.0 * (AM1 - AP1cs) * scalar; - b2 = (AP1 - AM1cs - beta_sn) * scalar; - } -} diff --git a/src/com/jsyn/unitgen/FilterLowPass.java b/src/com/jsyn/unitgen/FilterLowPass.java deleted file mode 100644 index 1557367..0000000 --- a/src/com/jsyn/unitgen/FilterLowPass.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2009 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. - */ -/** - * Aug 21, 2009 - * com.jsyn.engine.units.Filter_HighPass.java - */ - -package com.jsyn.unitgen; - -/** - * Filter that allows frequencies below the center frequency to pass. This filter is based on the - * BiQuad filter. Coefficients are updated whenever the frequency or Q changes. - * - * @author Phil Burk (C) 2009 Mobileer Inc Translated from 'C' to Java by Lisa - * Tolentino. - * - * @see FilterFourPoles - */ -public class FilterLowPass extends FilterBiquadCommon { - - /** - * This method is by FilterBiquad to update coefficients for the lowpass filter. - */ - @Override - public void updateCoefficients() { - - // scalar = 1.0f / (1.0f + BQCM.alpha); - // omc = (1.0f - BQCM.cos_omega); - // A0_A2_Value = omc * 0.5f * scalar; - // // translating from RBJ coefficients - // // A0 = (b0/(2*a0) - // // = ((1 - cos_omega)/2) / (1 + alpha) - // // = (omc*0.5) / (1 + alpha) - // // = (omc*0.5) * (1.0/(1 + alpha)) - // // = omc * 0.5 * scalar - // csFilter->csFBQ_A0 = A0_A2_Value; - // csFilter->csFBQ_A1 = omc * scalar; - // csFilter->csFBQ_A2 = A0_A2_Value; - // csFilter->csFBQ_B1 = -2.0f * BQCM.cos_omega * scalar; - // csFilter->csFBQ_B2 = (1.0f - BQCM.alpha) * scalar; - - double scalar = 1.0 / (1.0 + alpha); - double oneMinusCosine = 1.0 - cos_omega; - double a0_a2_value = oneMinusCosine * 0.5 * scalar; - - this.a0 = a0_a2_value; - this.a1 = oneMinusCosine * scalar; - this.a2 = a0_a2_value; - this.b1 = -2.0 * cos_omega * scalar; - this.b2 = (1.0 - alpha) * scalar; - } -} diff --git a/src/com/jsyn/unitgen/FilterLowShelf.java b/src/com/jsyn/unitgen/FilterLowShelf.java deleted file mode 100644 index cf41f45..0000000 --- a/src/com/jsyn/unitgen/FilterLowShelf.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * LowShelf Filter. This creates a flat response below the cutoff frequency. This filter is - * sometimes used at the end of a bank of EQ filters. This filter is based on the BiQuad filter. - * Coefficients are updated whenever the frequency or Q changes. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FilterLowShelf extends FilterBiquadShelf { - - /** - * This method is called by Filter_BiquadShelf to update coefficients. - */ - @Override - public void updateCoefficients() { - double scalar = 1.0 / (AP1 + AM1cs + beta_sn); - a0 = factorA * (AP1 - AM1cs + beta_sn) * scalar; - a1 = 2.0 * factorA * (AM1 - AP1cs) * scalar; - a2 = factorA * (AP1 - AM1cs - beta_sn) * scalar; - b1 = -2.0 * (AM1 + AP1cs) * scalar; - b2 = (AP1 + AM1cs - beta_sn) * scalar; - } -} diff --git a/src/com/jsyn/unitgen/FilterOnePole.java b/src/com/jsyn/unitgen/FilterOnePole.java deleted file mode 100644 index 090e42b..0000000 --- a/src/com/jsyn/unitgen/FilterOnePole.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2009 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.UnitVariablePort; - -/** - * First Order, One Pole filter using the following formula: - * - * <pre> - * y(n) = A0 * x(n) - B1 * y(n - 1) - * </pre> - * - * where y(n) is Output, x(n) is Input and y(n-1) is a delayed copy of the output. This filter is a - * recursive IIR or Infinite Impulse Response filter. It can be unstable depending on the values of - * the coefficients. This can be useful as a low-pass filter, or a "leaky integrator". A thorough - * description of the digital filter theory needed to fully describe this filter is beyond the scope - * of this document. Calculating coefficients is non-intuitive; the interested user is referred to - * one of the standard texts on filter theory (e.g., Moore, "Elements of Computer Music", section - * 2.4). - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see FilterLowPass - */ -public class FilterOnePole extends UnitFilter { - public UnitVariablePort a0; - public UnitVariablePort b1; - private double y1; - - public FilterOnePole() { - addPort(a0 = new UnitVariablePort("A0", 0.6)); - addPort(b1 = new UnitVariablePort("B1", -0.3)); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double a0v = a0.getValue(); - double b1v = b1.getValue(); - - for (int i = start; i < limit; i++) { - double x0 = inputs[i]; - outputs[i] = y1 = (a0v * x0) - (b1v * y1); - } - - } -} diff --git a/src/com/jsyn/unitgen/FilterOnePoleOneZero.java b/src/com/jsyn/unitgen/FilterOnePoleOneZero.java deleted file mode 100644 index ed1868c..0000000 --- a/src/com/jsyn/unitgen/FilterOnePoleOneZero.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.UnitVariablePort; - -/** - * First Order, One Pole, One Zero filter using the following formula: - * - * <pre> - * y(n) = A0 * x(n) + A1 * x(n - 1) - B1 * y(n - 1) - * </pre> - * - * where y(n) is Output, x(n) is Input, x(n-1) is a delayed copy of the input, and y(n-1) is a - * delayed copy of the output. This filter is a recursive IIR or Infinite Impulse Response filter. - * it can be unstable depending on the values of the coefficients. A thorough description of the - * digital filter theory needed to fully describe this filter is beyond the scope of this document. - * Calculating coefficients is non-intuitive; the interested user is referred to one of the standard - * texts on filter theory (e.g., Moore, "Elements of Computer Music", section 2.4). - * - * @author (C) 1997-2009 Phil Burk, SoftSynth.com - * @see FilterLowPass - */ - -public class FilterOnePoleOneZero extends UnitFilter { - public UnitVariablePort a0; - public UnitVariablePort a1; - public UnitVariablePort b1; - - private double x1; - private double y1; - - public FilterOnePoleOneZero() { - addPort(a0 = new UnitVariablePort("A0")); - addPort(a1 = new UnitVariablePort("A1")); - addPort(b1 = new UnitVariablePort("B1")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double a0v = a0.getValue(); - double a1v = a1.getValue(); - double b1v = b1.getValue(); - - for (int i = start; i < limit; i++) { - double x0 = inputs[i]; - outputs[i] = y1 = (a0v * x0) + (a1v * x1) + (b1v * y1); - x1 = x0; - } - - } -} diff --git a/src/com/jsyn/unitgen/FilterOneZero.java b/src/com/jsyn/unitgen/FilterOneZero.java deleted file mode 100644 index 2a07a16..0000000 --- a/src/com/jsyn/unitgen/FilterOneZero.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitVariablePort; - -/** - * First Order, One Zero filter using the following formula: - * - * <pre> - * y(n) = A0 * x(n) + A1 * x(n - 1) - * </pre> - * - * where y(n) is Output, x(n) is Input and x(n-1) is Input at the prior sample tick. Setting A1 - * positive gives a low-pass response; setting A1 negative gives a high-pass response. The bandwidth - * of this filter is fairly high, so it often serves a building block by being cascaded with other - * filters. If A0 and A1 are both 0.5, then this filter is a simple averaging lowpass filter, with a - * zero at SR/2 = 22050 Hz. If A0 is 0.5 and A1 is -0.5, then this filter is a high pass filter, - * with a zero at 0.0 Hz. A thorough description of the digital filter theory needed to fully - * describe this filter is beyond the scope of this document. Calculating coefficients is - * non-intuitive; the interested user is referred to one of the standard texts on filter theory - * (e.g., Moore, "Elements of Computer Music", section 2.4). - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see FilterLowPass - */ -public class FilterOneZero extends UnitFilter { - public UnitVariablePort a0; - public UnitVariablePort a1; - private double x1; - - public FilterOneZero() { - addPort(a0 = new UnitVariablePort("A0", 0.5)); - addPort(a1 = new UnitVariablePort("A1", 0.5)); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double a0v = a0.getValue(); - double a1v = a1.getValue(); - - for (int i = start; i < limit; i++) { - double x0 = inputs[i]; - outputs[i] = (a0v * x0) + (a1v * x1); - x1 = x0; - } - - } -} diff --git a/src/com/jsyn/unitgen/FilterPeakingEQ.java b/src/com/jsyn/unitgen/FilterPeakingEQ.java deleted file mode 100644 index bec7096..0000000 --- a/src/com/jsyn/unitgen/FilterPeakingEQ.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * PeakingEQ Filter. This can be used to raise or lower the gain around the cutoff frequency. This - * filter is sometimes used in the middle of a bank of EQ filters. This filter is based on the - * BiQuad filter. Coefficients are updated whenever the frequency or Q changes. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FilterPeakingEQ extends FilterBiquadCommon { - public UnitInputPort gain; - - private double previousGain; - - public FilterPeakingEQ() { - addPort(gain = new UnitInputPort("Gain", 1.0)); - } - - @Override - protected boolean isRecalculationNeeded(double frequencyValue, double qValue) { - double currentGain = gain.getValues()[0]; - if (currentGain < MINIMUM_GAIN) { - currentGain = MINIMUM_GAIN; - } - - boolean needed = super.isRecalculationNeeded(frequencyValue, qValue); - needed |= (previousGain != currentGain); - - previousGain = currentGain; - return needed; - } - - @Override - public void updateCoefficients() { - double factorA = Math.sqrt(previousGain); - double alphaTimesA = alpha * factorA; - double alphaOverA = alpha / factorA; - // Note this is not the normal scalar! - double scalar = 1.0 / (1.0 + alphaOverA); - double a1_b1_value = -2.0 * cos_omega * scalar; - - this.a0 = (1.0 + alphaTimesA) * scalar; - - this.a1 = a1_b1_value; - this.a2 = (1.0 - alphaTimesA) * scalar; - - this.b1 = a1_b1_value; - this.b2 = (1.0 - alphaOverA) * scalar; - } -} diff --git a/src/com/jsyn/unitgen/FilterStateVariable.java b/src/com/jsyn/unitgen/FilterStateVariable.java deleted file mode 100644 index 74dde5e..0000000 --- a/src/com/jsyn/unitgen/FilterStateVariable.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * A versatile filter described in Hal Chamberlain's "Musical Applications of MicroProcessors". It - * is convenient because its frequency and resonance can each be controlled by a single value. The - * "output" port of this filter is the "lowPass" output multiplied by the "amplitude" - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see FilterLowPass - * @see FilterHighPass - * @see FilterFourPoles - */ -public class FilterStateVariable extends TunableFilter { - /** - * Amplitude of Output in the range of 0.0 to 1.0. SIGNAL_TYPE_RAW_SIGNED Defaults to 1.0 - * <P> - * Note that the amplitude only affects the "output" port and not the lowPass, bandPass or - * highPass signals. Use a Multiply unit if you need to scale those signals. - */ - public UnitInputPort amplitude; - - /** - * Controls feedback that causes self oscillation. Actually 1/Q - SIGNAL_TYPE_RAW_SIGNED in the - * range of 0.0 to 1.0. Defaults to 0.125. - */ - public UnitInputPort resonance; - /** - * Low pass filtered signal. - * <P> - * Note that this signal is not affected by the amplitude port. - */ - public UnitOutputPort lowPass; - /** - * Band pass filtered signal. - * <P> - * Note that this signal is not affected by the amplitude port. - */ - public UnitOutputPort bandPass; - /** - * High pass filtered signal. - * <P> - * Note that this signal is not affected by the amplitude port. - */ - public UnitOutputPort highPass; - - private double freqInternal; - private double previousFrequency = Double.MAX_VALUE; // So we trigger an immediate update. - private double lowPassValue; - private double bandPassValue; - - /** - * No-argument constructor instantiates the Biquad common and adds an amplitude port to this - * filter. - */ - public FilterStateVariable() { - frequency.set(440.0); - addPort(resonance = new UnitInputPort("Resonance", 0.2)); - addPort(amplitude = new UnitInputPort("Amplitude", 1.0)); - addPort(lowPass = new UnitOutputPort("LowPass")); - addPort(bandPass = new UnitOutputPort("BandPass")); - addPort(highPass = new UnitOutputPort("HighPass")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] reses = resonance.getValues(); - double[] lows = lowPass.getValues(); - double[] highs = highPass.getValues(); - double[] bands = bandPass.getValues(); - - double newFreq = frequencies[0]; - if (newFreq != previousFrequency) { - previousFrequency = newFreq; - freqInternal = 2.0 * Math.sin(Math.PI * newFreq * getFramePeriod()); - } - - for (int i = start; i < limit; i++) { - lowPassValue = (freqInternal * bandPassValue) + lowPassValue; - // Clip between -1 and +1 to prevent blowup. - lowPassValue = (lowPassValue < -1.0) ? -1.0 : ((lowPassValue > 1.0) ? 1.0 - : lowPassValue); - lows[i] = lowPassValue; - - outputs[i] = lowPassValue * (amplitudes[i]); - double highPassValue = inputs[i] - (reses[i] * bandPassValue) - lowPassValue; - // System.out.println("low = " + lowPassValue + ", band = " + bandPassValue + - // ", high = " + highPassValue ); - highs[i] = highPassValue; - - bandPassValue = (freqInternal * highPassValue) + bandPassValue; - bands[i] = bandPassValue; - // System.out.println("low = " + lowPassValue + ", band = " + bandPassValue + - // ", high = " + highPassValue ); - } - } - -} diff --git a/src/com/jsyn/unitgen/FilterTwoPoles.java b/src/com/jsyn/unitgen/FilterTwoPoles.java deleted file mode 100644 index 0c68a64..0000000 --- a/src/com/jsyn/unitgen/FilterTwoPoles.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.UnitVariablePort; - -/** - * Second Order, Two Pole filter using the following formula: - * - * <pre> - * y(n) = A0 * x(n) - B1 * y(n - 1) - B2 * y(n - 2) - * </pre> - * - * where y(n) is Output, x(n) is Input, and y(n-1) is a delayed copy of the output. This filter is a - * recursive IIR or Infinite Impulse Response filter. it can be unstable depending on the values of - * the coefficients. A thorough description of the digital filter theory needed to fully describe - * this filter is beyond the scope of this document. Calculating coefficients is non-intuitive; the - * interested user is referred to one of the standard texts on filter theory (e.g., Moore, - * "Elements of Computer Music", section 2.4). - * - * @author (C) 1997-2009 Phil Burk, Mobileer Inc - */ - -public class FilterTwoPoles extends UnitFilter { - public UnitVariablePort a0; - public UnitVariablePort b1; - public UnitVariablePort b2; - private double y1; - private double y2; - - public FilterTwoPoles() { - addPort(a0 = new UnitVariablePort("A0")); - addPort(b1 = new UnitVariablePort("B1")); - addPort(b2 = new UnitVariablePort("B2")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double a0v = a0.getValue(); - double b1v = b1.getValue(); - double b2v = b2.getValue(); - - for (int i = start; i < limit; i++) { - double x0 = inputs[i]; - outputs[i] = y1 = 2.0 * ((a0v * x0) + (b1v * y1) + (b2v * y2)); - y2 = y1; - } - - } -} diff --git a/src/com/jsyn/unitgen/FilterTwoPolesTwoZeros.java b/src/com/jsyn/unitgen/FilterTwoPolesTwoZeros.java deleted file mode 100644 index cde279f..0000000 --- a/src/com/jsyn/unitgen/FilterTwoPolesTwoZeros.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.UnitVariablePort; - -/** - * Second Order, Two Pole, Two Zero filter using the following formula: - * - * <pre> - * y(n) = 2.0 * (A0 * x(n) + A1 * x(n - 1) + A2 * x(n - 2) - B1 * y(n - 1) - B2 * y(n - 2)) - * </pre> - * - * where y(n) is Output, x(n) is Input, x(n-1) is a delayed copy of the input, and y(n-1) is a - * delayed copy of the output. This filter is a recursive IIR or Infinite Impulse Response filter. - * It can be unstable depending on the values of the coefficients. This filter is basically the same - * as the FilterBiquad with different ports. A thorough description of the digital filter theory - * needed to fully describe this filter is beyond the scope of this document. Calculating - * coefficients is non-intuitive; the interested user is referred to one of the standard texts on - * filter theory (e.g., Moore, "Elements of Computer Music", section 2.4). Special thanks to Robert - * Bristow-Johnson for contributing his filter equations to the music-dsp list. They were used for - * calculating the coefficients for the lowPass, highPass, and other parametric filter calculations. - * - * @author (C) 1997-2009 Phil Burk, SoftSynth.com - */ - -public class FilterTwoPolesTwoZeros extends UnitFilter { - public UnitVariablePort a0; - public UnitVariablePort a1; - public UnitVariablePort a2; - public UnitVariablePort b1; - public UnitVariablePort b2; - private double x1; - private double y1; - private double x2; - private double y2; - - public FilterTwoPolesTwoZeros() { - addPort(a0 = new UnitVariablePort("A0")); - addPort(a1 = new UnitVariablePort("A1")); - addPort(a2 = new UnitVariablePort("A2")); - addPort(b1 = new UnitVariablePort("B1")); - addPort(b2 = new UnitVariablePort("B2")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double a0v = a0.getValue(); - double a1v = a1.getValue(); - double a2v = a2.getValue(); - double b1v = b1.getValue(); - double b2v = b2.getValue(); - - for (int i = start; i < limit; i++) { - double x0 = inputs[i]; - outputs[i] = y1 = 2.0 * ((a0v * x0) + (a1v * x1) + (a2v * x2) + (b1v * y1) + (b2v * y2)); - x2 = x1; - x1 = x0; - y2 = y1; - } - - } -} diff --git a/src/com/jsyn/unitgen/FixedRateMonoReader.java b/src/com/jsyn/unitgen/FixedRateMonoReader.java deleted file mode 100644 index c6edc23..0000000 --- a/src/com/jsyn/unitgen/FixedRateMonoReader.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2009 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.UnitOutputPort; - -/** - * Simple sample player. Play one sample per audio frame with no interpolation. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FixedRateMonoReader extends SequentialDataReader { - - public FixedRateMonoReader() { - addPort(output = new UnitOutputPort()); - } - - @Override - public void generate(int start, int limit) { - - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - if (dataQueue.hasMore()) { - double fdata = dataQueue.readNextMonoDouble(getFramePeriod()); - outputs[i] = fdata * amplitudes[i]; - } else { - outputs[i] = 0.0; - if (dataQueue.testAndClearAutoStop()) { - autoStop(); - } - } - dataQueue.firePendingCallbacks(); - } - } - -} diff --git a/src/com/jsyn/unitgen/FixedRateMonoWriter.java b/src/com/jsyn/unitgen/FixedRateMonoWriter.java deleted file mode 100644 index c215c55..0000000 --- a/src/com/jsyn/unitgen/FixedRateMonoWriter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Simple sample writer. Write one sample per audio frame with no interpolation. This can be used to - * record audio or to build delay lines. - * - * Note that you must call start() on this unit because it does not have an output for pulling data. - * - * @see FixedRateStereoWriter - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FixedRateMonoWriter extends SequentialDataWriter { - - public FixedRateMonoWriter() { - addPort(input = new UnitInputPort("Input")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - - for (int i = start; i < limit; i++) { - if (dataQueue.hasMore()) { - double value = inputs[i]; - dataQueue.writeNextDouble(value); - } else { - if (dataQueue.testAndClearAutoStop()) { - autoStop(); - } - } - dataQueue.firePendingCallbacks(); - } - - } - -} diff --git a/src/com/jsyn/unitgen/FixedRateStereoReader.java b/src/com/jsyn/unitgen/FixedRateStereoReader.java deleted file mode 100644 index c5c00ce..0000000 --- a/src/com/jsyn/unitgen/FixedRateStereoReader.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2009 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.UnitOutputPort; - -/** - * Simple stereo sample player. Play one sample per audio frame with no interpolation. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FixedRateStereoReader extends SequentialDataReader { - public FixedRateStereoReader() { - addPort(output = new UnitOutputPort(2, "Output")); - dataQueue.setNumChannels(2); - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] output0s = output.getValues(0); - double[] output1s = output.getValues(1); - - for (int i = start; i < limit; i++) { - if (dataQueue.hasMore()) { - dataQueue.beginFrame(getFramePeriod()); - double fdata = dataQueue.readCurrentChannelDouble(0); - // System.out.println("SampleReader_16F2: left = " + fdata ); - double amp = amplitudes[i]; - output0s[i] = fdata * amp; - fdata = dataQueue.readCurrentChannelDouble(1); - // System.out.println("SampleReader_16F2: right = " + fdata ); - output1s[i] = fdata * amp; - dataQueue.endFrame(); - } else { - output0s[i] = 0.0; - output1s[i] = 0.0; - if (dataQueue.testAndClearAutoStop()) { - autoStop(); - } - } - dataQueue.firePendingCallbacks(); - } - } -} diff --git a/src/com/jsyn/unitgen/FixedRateStereoWriter.java b/src/com/jsyn/unitgen/FixedRateStereoWriter.java deleted file mode 100644 index e4502f9..0000000 --- a/src/com/jsyn/unitgen/FixedRateStereoWriter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Simple stereo sample writer. Write two samples per audio frame with no interpolation. This can be - * used to record audio or to build delay lines. - * - * Note that you must call start() on this unit because it does not have an output for pulling data. - * - * @see FixedRateMonoWriter - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FixedRateStereoWriter extends SequentialDataWriter { - - public FixedRateStereoWriter() { - addPort(input = new UnitInputPort(2, "Input")); - dataQueue.setNumChannels(2); - } - - @Override - public void generate(int start, int limit) { - double[] input0s = input.getValues(0); - double[] input1s = input.getValues(1); - - for (int i = start; i < limit; i++) { - if (dataQueue.hasMore()) { - dataQueue.beginFrame(getFramePeriod()); - double value = input0s[i]; - dataQueue.writeCurrentChannelDouble(0, value); - value = input1s[i]; - dataQueue.writeCurrentChannelDouble(1, value); - dataQueue.endFrame(); - } else { - if (dataQueue.testAndClearAutoStop()) { - autoStop(); - } - } - dataQueue.firePendingCallbacks(); - } - - } - -} diff --git a/src/com/jsyn/unitgen/FourWayFade.java b/src/com/jsyn/unitgen/FourWayFade.java deleted file mode 100644 index c7fd22a..0000000 --- a/src/com/jsyn/unitgen/FourWayFade.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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; - -/** - * FourWayFade unit. - * <P> - * Mix inputs 0-3 based on the value of two fade ports. You can think of the four inputs arranged - * clockwise as follows. - * <P> - * - * <PRE> - * input[0] ---- input[1] - * | | - * | | - * | | - * input[3] ---- input[2] - * </PRE> - * - * The "fade" port has two parts. Fade[0] fades between the pair of inputs (0,3) and the pair of - * inputs (1,2). Fade[1] fades between the pair of inputs (0,1) and the pair of inputs (3,2). - * - * <PRE> - * Fade[0] Fade[1] Output - * -1 -1 Input[3] - * -1 +1 Input[0] - * +1 -1 Input[2] - * +1 +1 Input[1] - * - * - * -----Fade[0]-----> - * - * A - * | - * | - * Fade[1] - * | - * | - * </PRE> - * <P> - * - * @author (C) 1997-2009 Phil Burk, Mobileer Inc - */ -public class FourWayFade extends UnitGenerator { - public UnitInputPort input; - public UnitInputPort fade; - public UnitOutputPort output; - - /* Define Unit Ports used by connect() and set(). */ - public FourWayFade() { - addPort(input = new UnitInputPort(4, "Input")); - addPort(fade = new UnitInputPort(2, "Fade")); - addPort(output = new UnitOutputPort()); - } - - @Override - public void generate(int start, int limit) { - double[] inputAs = input.getValues(0); - double[] inputBs = input.getValues(1); - double[] inputCs = input.getValues(2); - double[] inputDs = input.getValues(3); - double[] fadeLRs = fade.getValues(0); - double[] fadeFBs = fade.getValues(1); - double[] outputs = output.getValues(0); - - for (int i = start; i < limit; i++) { - // Scale and offset to 0.0 to 1.0 range. - double gainLR = (fadeLRs[i] * 0.5) + 0.5; - double temp = 1.0 - gainLR; - double mixFront = (inputAs[i] * temp) + (inputBs[i] * gainLR); - double mixBack = (inputDs[i] * temp) + (inputCs[i] * gainLR); - - double gainFB = (fadeFBs[i] * 0.5) + 0.5; - outputs[i] = (mixBack * (1.0 - gainFB)) + (mixFront * gainFB); - } - } -} diff --git a/src/com/jsyn/unitgen/FunctionEvaluator.java b/src/com/jsyn/unitgen/FunctionEvaluator.java deleted file mode 100644 index 0cc0c83..0000000 --- a/src/com/jsyn/unitgen/FunctionEvaluator.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2009 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. - */ -/** - * Aug 26, 2009 - * com.jsyn.engine.units.TunableFilter.java - */ - -package com.jsyn.unitgen; - -import com.jsyn.data.Function; -import com.jsyn.ports.UnitFunctionPort; -import com.jsyn.ports.UnitInputPort; - -/** - * Convert an input value to an output value. The Function is typically implemented by looking up a - * value in a DoubleTable. But other implementations of Function can be used. Input typically ranges - * from -1.0 to +1.0. - * - * <pre> - * <code> - * // A unit that will lookup the function. - * FunctionEvaluator shaper = new FunctionEvaluator(); - * synth.add( shaper ); - * shaper.start(); - * // Define a custom function. - * Function cuber = new Function() - * { - * public double evaluate( double x ) - * { - * return x * x * x; - * } - * }; - * shaper.function.set(cuber); - * - * shaper.input.set( 0.5 ); - * </code> - * </pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see Function - */ -public class FunctionEvaluator extends UnitFilter { - public UnitInputPort amplitude; - public UnitFunctionPort function; - - public FunctionEvaluator() { - addPort(amplitude = new UnitInputPort("Amplitude", 1.0)); - addPort(function = new UnitFunctionPort("Function")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - Function functionObject = function.get(); - - for (int i = start; i < limit; i++) { - outputs[i] = functionObject.evaluate(inputs[i]) * amplitudes[i]; - } - - } -} diff --git a/src/com/jsyn/unitgen/FunctionOscillator.java b/src/com/jsyn/unitgen/FunctionOscillator.java deleted file mode 100644 index 30d32d5..0000000 --- a/src/com/jsyn/unitgen/FunctionOscillator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2009 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.data.Function; -import com.jsyn.ports.UnitFunctionPort; - -/** - * Oscillator that uses a Function object to define the waveform. Note that a DoubleTable can be - * used as the Function. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class FunctionOscillator extends UnitOscillator { - public UnitFunctionPort function; - - public FunctionOscillator() { - addPort(function = new UnitFunctionPort("Function")); - } - - @Override - public void generate(int start, int limit) { - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - Function functionObject = function.get(); - - // Variables have a single value. - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - // Generate sawtooth phasor to provide phase for function lookup. - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - double value = functionObject.evaluate(currentPhase); - outputs[i] = value * amplitudes[i]; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/Grain.java b/src/com/jsyn/unitgen/Grain.java deleted file mode 100644 index 812061c..0000000 --- a/src/com/jsyn/unitgen/Grain.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.unitgen; - -/** - * A single Grain that is normally created and controlled by a GrainFarm. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class Grain implements GrainEnvelope { - private double frameRate; - private double amplitude = 1.0; - - private GrainSource source; - private GrainEnvelope envelope; - - public Grain(GrainSource source, GrainEnvelope envelope) { - this.source = source; - this.envelope = envelope; - } - - @Override - public double next() { - if (envelope.hasMoreValues()) { - double env = envelope.next(); - return source.next() * env * amplitude; - } else { - return 0.0; - } - } - - @Override - public boolean hasMoreValues() { - return envelope.hasMoreValues(); - } - - @Override - public void reset() { - source.reset(); - envelope.reset(); - } - - public void setRate(double rate) { - source.setRate(rate); - } - - @Override - public void setDuration(double duration) { - envelope.setDuration(duration); - } - - @Override - public double getFrameRate() { - return frameRate; - } - - @Override - public void setFrameRate(double frameRate) { - this.frameRate = frameRate; - source.setFrameRate(frameRate); - envelope.setFrameRate(frameRate); - } - - public double getAmplitude() { - return amplitude; - } - - public void setAmplitude(double amplitude) { - this.amplitude = amplitude; - } - - public GrainSource getSource() { - return source; - } -} diff --git a/src/com/jsyn/unitgen/GrainCommon.java b/src/com/jsyn/unitgen/GrainCommon.java deleted file mode 100644 index a7a04fc..0000000 --- a/src/com/jsyn/unitgen/GrainCommon.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2009 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; - -public class GrainCommon { - protected double frameRate; - - public double getFrameRate() { - return frameRate; - } - - public void setFrameRate(double frameRate) { - this.frameRate = frameRate; - } - - public void reset() { - } -} diff --git a/src/com/jsyn/unitgen/GrainEnvelope.java b/src/com/jsyn/unitgen/GrainEnvelope.java deleted file mode 100644 index e6ff24c..0000000 --- a/src/com/jsyn/unitgen/GrainEnvelope.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.unitgen; - -/** - * This envelope should start at 0.0, go up to 1.0 and then return to 0.0 in duration time. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public interface GrainEnvelope { - - double getFrameRate(); - - void setFrameRate(double frameRate); - - /** - * @return next amplitude value of envelope - */ - double next(); - - /** - * Are there any more values to be generated in the envelope? - * - * @return true if more - */ - boolean hasMoreValues(); - - /** - * Prepare to start a new envelope. - */ - void reset(); - - /** - * @param duration in seconds. - */ - void setDuration(double duration); - -} diff --git a/src/com/jsyn/unitgen/GrainFarm.java b/src/com/jsyn/unitgen/GrainFarm.java deleted file mode 100644 index 78179bc..0000000 --- a/src/com/jsyn/unitgen/GrainFarm.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.util.PseudoRandom; - -/** - * A unit generator that generates a cloud of sound using multiple Grains. Special thanks to my - * friend Ross Bencina for his excellent article on Granular Synthesis. Several of his ideas are - * reflected in this architecture. "Implementing Real-Time Granular Synthesis" by Ross Bencina, - * Audio Anecdotes III, 2001. - * - * <pre><code> - synth.add( sampleGrainFarm = new GrainFarm() ); - grainFarm.allocate( NUM_GRAINS ); -</code></pre> - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see Grain - * @see GrainSourceSine - * @see RaisedCosineEnvelope - */ -public class GrainFarm extends UnitGenerator implements UnitSource { - /** A scaler for playback rate. Nominally 1.0. */ - public UnitInputPort rate; - public UnitInputPort rateRange; - public UnitInputPort amplitude; - public UnitInputPort amplitudeRange; - public UnitInputPort density; - public UnitInputPort duration; - public UnitInputPort durationRange; - public UnitOutputPort output; - - PseudoRandom randomizer; - private GrainState[] states; - private double countScaler = 1.0; - private final GrainScheduler scheduler = new StochasticGrainScheduler(); - - public GrainFarm() { - randomizer = new PseudoRandom(); - addPort(rate = new UnitInputPort("Rate", 1.0)); - addPort(amplitude = new UnitInputPort("Amplitude", 1.0)); - addPort(duration = new UnitInputPort("Duration", 0.01)); - addPort(rateRange = new UnitInputPort("RateRange", 0.0)); - addPort(amplitudeRange = new UnitInputPort("AmplitudeRange", 0.0)); - addPort(durationRange = new UnitInputPort("DurationRange", 0.0)); - addPort(density = new UnitInputPort("Density", 0.1)); - addPort(output = new UnitOutputPort()); - } - - private class GrainState { - Grain grain; - int countdown; - double lastDuration; - final static int STATE_IDLE = 0; - final static int STATE_GAP = 1; - final static int STATE_RUNNING = 2; - int state = STATE_IDLE; - private double gapError; - - public double next(int i) { - double output = 0.0; - if (state == STATE_RUNNING) { - if (grain.hasMoreValues()) { - output = grain.next(); - } else { - startGap(i); - } - } else if (state == STATE_GAP) { - if (countdown > 0) { - countdown -= 1; - } else if (countdown == 0) { - state = STATE_RUNNING; - grain.reset(); - - setupGrain(grain, i); - - double dur = nextDuration(i); - grain.setDuration(dur); - } - } else if (state == STATE_IDLE) { - nextDuration(i); // initialize lastDuration - startGap(i); - } - return output; - } - - private double nextDuration(int i) { - double dur = duration.getValues()[i]; - dur = scheduler.nextDuration(dur); - lastDuration = dur; - return dur; - } - - private void startGap(int i) { - state = STATE_GAP; - double dens = density.getValues()[i]; - double gap = scheduler.nextGap(lastDuration, dens) * getFrameRate(); - gap += gapError; - countdown = (int) gap; - gapError = gap - countdown; - } - } - - public void setGrainArray(Grain[] grains) { - countScaler = 1.0 / grains.length; - states = new GrainState[grains.length]; - for (int i = 0; i < states.length; i++) { - states[i] = new GrainState(); - states[i].grain = grains[i]; - grains[i].setFrameRate(getSynthesisEngine().getFrameRate()); - } - } - - public void setupGrain(Grain grain, int i) { - double temp = rate.getValues()[i] * calculateOctaveScaler(rateRange.getValues()[i]); - grain.setRate(temp); - - // Scale the amplitude range so that we never go above - // original amplitude. - double base = amplitude.getValues()[i]; - double offset = base * Math.random() * amplitudeRange.getValues()[i]; - grain.setAmplitude(base - offset); - } - - public void allocate(int numGrains) { - Grain[] grainArray = new Grain[numGrains]; - for (int i = 0; i < numGrains; i++) { - Grain grain = new Grain(new GrainSourceSine(), new RaisedCosineEnvelope()); - grainArray[i] = grain; - } - setGrainArray(grainArray); - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - - private double calculateOctaveScaler(double rangeValue) { - double octaveRange = 0.5 * randomizer.nextRandomDouble() * rangeValue; - return Math.pow(2.0, octaveRange); - } - - @Override - public void generate(int start, int limit) { - double[] outputs = output.getValues(); - double[] amplitudes = amplitude.getValues(); - // double frp = getSynthesisEngine().getFramePeriod(); - for (int i = start; i < limit; i++) { - double result = 0.0; - - // Mix the grains together. - for (GrainState grainState : states) { - result += grainState.next(i); - } - - outputs[i] = result * amplitudes[i] * countScaler; - } - - } -} diff --git a/src/com/jsyn/unitgen/GrainScheduler.java b/src/com/jsyn/unitgen/GrainScheduler.java deleted file mode 100644 index df9c25e..0000000 --- a/src/com/jsyn/unitgen/GrainScheduler.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.unitgen; - -/** - * Defines a class that can schedule the execution of Grains in a GrainFarm. This is mostly for - * internal use. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public interface GrainScheduler { - - /** - * Calculate time in seconds for the next gap between grains. - * - * @param duration - * @param density - * @return seconds before next grain - */ - double nextGap(double duration, double density); - - /** - * Calculate duration in seconds for the next grains. - * - * @param suggestedDuration - * @return duration of grain seconds - */ - double nextDuration(double suggestedDuration); - -} diff --git a/src/com/jsyn/unitgen/GrainSource.java b/src/com/jsyn/unitgen/GrainSource.java deleted file mode 100644 index 1d5c522..0000000 --- a/src/com/jsyn/unitgen/GrainSource.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.unitgen; - -/** - * Defines classes that can provide the signal inside a Grain. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public interface GrainSource { - double getFrameRate(); - - void setFrameRate(double frameRate); - - /** Generate one more value or the source signal. */ - double next(); - - /** Reset the internal phase of the grain. */ - void reset(); - - void setRate(double rate); -} diff --git a/src/com/jsyn/unitgen/GrainSourceSine.java b/src/com/jsyn/unitgen/GrainSourceSine.java deleted file mode 100644 index 0af9cbd..0000000 --- a/src/com/jsyn/unitgen/GrainSourceSine.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.unitgen; - -/** - * A simple sine wave generator for a Grain. This uses the same fast Taylor expansion that the - * SineOscillator uses. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class GrainSourceSine extends GrainCommon implements GrainSource { - protected double phase; - protected double phaseIncrement; - - public GrainSourceSine() { - setRate(1.0); - } - - public void setPhaseIncrement(double phaseIncrement) { - this.phaseIncrement = phaseIncrement; - } - - @Override - public double next() { - phase += phaseIncrement; - if (phase > 1.0) { - phase -= 2.0; - } - return SineOscillator.fastSin(phase); - } - - @Override - public void setRate(double rate) { - setPhaseIncrement(rate * 0.1 / Math.PI); - } - -} diff --git a/src/com/jsyn/unitgen/IFFT.java b/src/com/jsyn/unitgen/IFFT.java deleted file mode 100644 index 307acd2..0000000 --- a/src/com/jsyn/unitgen/IFFT.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013 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; - -/** - * Periodically transform the complex input spectrum using an IFFT to a complex signal stream. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @version 016 - * @see FFT - */ -public class IFFT extends FFTBase { - - public IFFT() { - super(); - } - - @Override - protected int getSign() { - return -1; // -1 for IFFT - } -} diff --git a/src/com/jsyn/unitgen/ImpulseOscillator.java b/src/com/jsyn/unitgen/ImpulseOscillator.java deleted file mode 100644 index 8c676f3..0000000 --- a/src/com/jsyn/unitgen/ImpulseOscillator.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Narrow impulse oscillator. An impulse is only one sample wide. It is useful for pinging filters - * or generating an "impulse response". - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class ImpulseOscillator extends UnitOscillator { - - @Override - public void generate(int start, int limit) { - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - // Variables have a single value. - double currentPhase = phase.getValue(); - - double inverseNyquist = synthesisEngine.getInverseNyquist(); - - for (int i = start; i < limit; i++) { - /* Generate sawtooth phasor to provide phase for impulse generation. */ - double phaseIncrement = frequencies[i] * inverseNyquist; - currentPhase += phaseIncrement; - - double ampl = amplitudes[i]; - double result = 0.0; - if (currentPhase >= 1.0) { - currentPhase -= 2.0; - result = ampl; - } else if (currentPhase < -1.0) { - currentPhase += 2.0; - result = ampl; - } - outputs[i] = result; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/ImpulseOscillatorBL.java b/src/com/jsyn/unitgen/ImpulseOscillatorBL.java deleted file mode 100644 index 23686b8..0000000 --- a/src/com/jsyn/unitgen/ImpulseOscillatorBL.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2009 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.engine.MultiTable; - -/** - * Impulse oscillator created by differentiating a sawtoothBL. A band limited impulse is very narrow - * but is slightly wider than one sample. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class ImpulseOscillatorBL extends SawtoothOscillatorBL { - private double previous = 0.0; - - @Override - protected double generateBL(MultiTable multiTable, double currentPhase, - double positivePhaseIncrement, double flevel, int i) { - double saw = multiTable.calculateSawtooth(currentPhase, positivePhaseIncrement, flevel); - double result = previous - saw; - previous = saw; - return result; - } - -} diff --git a/src/com/jsyn/unitgen/Integrate.java b/src/com/jsyn/unitgen/Integrate.java deleted file mode 100644 index b5beea9..0000000 --- a/src/com/jsyn/unitgen/Integrate.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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; - -/** - * IntegrateUnit unit. - * <P> - * Output accumulated sum of the input signal. This can be used to transform one signal into - * another, or to generate ramps between the limits by setting the input signal positive or - * negative. For a "leaky integrator" use a FilterOnePoleOneZero. - * <P> - * - * <pre> - * output = output + input; - * if (output < lowerLimit) - * output = lowerLimit; - * else if (output > upperLimit) - * output = upperLimit; - * </pre> - * - * @author (C) 1997-2011 Phil Burk, Mobileer Inc - * @see FilterOnePoleOneZero - */ -public class Integrate extends UnitGenerator { - public UnitInputPort input; - /** - * Output will be stopped internally from going below this value. Default is -1.0. - */ - public UnitInputPort lowerLimit; - /** - * Output will be stopped internally from going above this value. Default is +1.0. - */ - public UnitInputPort upperLimit; - public UnitOutputPort output; - - private double accum; - - /* Define Unit Ports used by connect() and set(). */ - public Integrate() { - addPort(input = new UnitInputPort("Input")); - addPort(lowerLimit = new UnitInputPort("LowerLimit", -1.0)); - addPort(upperLimit = new UnitInputPort("UpperLimit", 1.0)); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] lowerLimits = lowerLimit.getValues(); - double[] upperLimits = upperLimit.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - accum += inputs[i]; // INTEGRATE - - // clip to limits - if (accum > upperLimits[i]) - accum = upperLimits[i]; - else if (accum < lowerLimits[i]) - accum = lowerLimits[i]; - - outputs[i] = accum; - } - } -} diff --git a/src/com/jsyn/unitgen/InterpolatingDelay.java b/src/com/jsyn/unitgen/InterpolatingDelay.java deleted file mode 100644 index 24de4f9..0000000 --- a/src/com/jsyn/unitgen/InterpolatingDelay.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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; - -/** - * InterpolatingDelay - * <P> - * InterpolatingDelay provides a variable time delay with an input and output. The internal data - * format is 32-bit floating point. The amount of delay can be varied from 0.0 to a time in seconds - * corresponding to the numFrames allocated. The fractional delay values are calculated by linearly - * interpolating between adjacent values in the delay line. - * <P> - * This unit can be used to implement time varying delay effects such as a flanger or a chorus. It - * can also be used to implement physical models of acoustic instruments, or other tunable delay - * based resonant systems. - * <P> - * - * @author (C) 1997-2011 Phil Burk, Mobileer Inc - * @see Delay - */ - -public class InterpolatingDelay extends UnitFilter { - /** - * Delay time in seconds. This value will converted to frames and clipped between zero and the - * numFrames value passed to allocate(). The minimum and default delay time is 0.0. - */ - public UnitInputPort delay; - - private float[] buffer; - private int cursor; - private int numFrames; - - public InterpolatingDelay() { - addPort(delay = new UnitInputPort("Delay")); - } - - /** - * Allocate memory for the delay buffer. For a 2 second delay at 44100 Hz sample rate you will - * need at least 88200 samples. - * - * @param numFrames size of the float array to hold the delayed samples - */ - public void allocate(int numFrames) { - this.numFrames = numFrames; - // Allocate extra frame for guard point to speed up interpolation. - buffer = new float[numFrames + 1]; - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double[] delays = delay.getValues(); - - for (int i = start; i < limit; i++) { - // This should be at the beginning of the loop - // because the guard point should == buffer[0]. - if (cursor == numFrames) { - // Write guard point! Must allocate one extra sample. - buffer[numFrames] = (float) inputs[i]; - cursor = 0; - } - - buffer[cursor] = (float) inputs[i]; - - /* Convert delay time to a clipped frame offset. */ - double delayFrames = delays[i] * getFrameRate(); - - // Clip to zero delay. - if (delayFrames <= 0.0) { - outputs[i] = buffer[cursor]; - } else { - // Clip to maximum delay. - if (delayFrames >= numFrames) { - delayFrames = numFrames - 1; - } - - // Calculate fractional index into delay buffer. - double readIndex = cursor - delayFrames; - if (readIndex < 0.0) { - readIndex += numFrames; - } - // setup for interpolation. - // We know readIndex is > 0 so we do not need to call floor(). - int iReadIndex = (int) readIndex; - double frac = readIndex - iReadIndex; - - // Get adjacent values relying on guard point to prevent overflow. - double val0 = buffer[iReadIndex]; - double val1 = buffer[iReadIndex + 1]; - - // Interpolate new value. - outputs[i] = val0 + (frac * (val1 - val0)); - } - - cursor += 1; - } - - } - -} diff --git a/src/com/jsyn/unitgen/Latch.java b/src/com/jsyn/unitgen/Latch.java deleted file mode 100644 index 0518f69..0000000 --- a/src/com/jsyn/unitgen/Latch.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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; - -/** - * Latch or hold an input value. - * <p> - * Pass a value unchanged if gate true, otherwise output held value. - * <p> - * output = ( gate > 0.0 ) ? input : previous_output; - * - * @author (C) 1997-2010 Phil Burk, Mobileer Inc - * @see EdgeDetector - */ -public class Latch extends UnitFilter { - public UnitInputPort gate; - private double held; - - /* Define Unit Ports used by connect() and set(). */ - public Latch() { - addPort(gate = new UnitInputPort("Gate")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] gates = gate.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - if (gates[i] > 0.0) { - held = inputs[i]; - } - outputs[i] = held; - } - } -} diff --git a/src/com/jsyn/unitgen/LatchZeroCrossing.java b/src/com/jsyn/unitgen/LatchZeroCrossing.java deleted file mode 100644 index 9e6c011..0000000 --- a/src/com/jsyn/unitgen/LatchZeroCrossing.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; - -/** - * Latches when input crosses zero. - * <P> - * Pass a value unchanged if gate true, otherwise pass input unchanged until input crosses zero then - * output zero. This can be used to turn off a sound at a zero crossing so there is no pop. - * <P> - * - * @author (C) 2010 Phil Burk, Mobileer Inc - * @see Latch - * @see Minimum - */ -public class LatchZeroCrossing extends UnitGenerator { - public UnitInputPort input; - public UnitInputPort gate; - public UnitOutputPort output; - private double held; - private boolean crossed; - - /* Define Unit Ports used by connect() and set(). */ - public LatchZeroCrossing() { - addPort(input = new UnitInputPort("Input")); - addPort(gate = new UnitInputPort("Gate", 1.0)); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] gates = gate.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - double current = inputs[i]; - if (gates[i] > 0.0) { - held = current; - crossed = false; - } else { - // If we haven't already seen a zero crossing then look for one. - if (!crossed) { - if ((held * current) <= 0.0) { - held = 0.0; - crossed = true; - } else { - held = current; - } - } - } - outputs[i] = held; - } - } -} diff --git a/src/com/jsyn/unitgen/LineIn.java b/src/com/jsyn/unitgen/LineIn.java deleted file mode 100644 index aeef965..0000000 --- a/src/com/jsyn/unitgen/LineIn.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2009 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.Synthesizer; -import com.jsyn.ports.UnitOutputPort; - -/** - * External audio input is sent to the output of this unit. The LineIn provides a stereo signal - * containing channels 0 and 1. For LineIn to work you must call the Synthesizer start() method with - * numInputChannels > 0. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see Synthesizer - * @see ChannelIn - * @see LineOut - */ -public class LineIn extends UnitGenerator { - public UnitOutputPort output; - - public LineIn() { - addPort(output = new UnitOutputPort(2, "Output")); - } - - @Override - public void generate(int start, int limit) { - double[] outputs0 = output.getValues(0); - double[] outputs1 = output.getValues(1); - double[] buffer0 = synthesisEngine.getInputBuffer(0); - double[] buffer1 = synthesisEngine.getInputBuffer(1); - for (int i = start; i < limit; i++) { - outputs0[i] = buffer0[i]; - outputs1[i] = buffer1[i]; - } - } - -} diff --git a/src/com/jsyn/unitgen/LineOut.java b/src/com/jsyn/unitgen/LineOut.java deleted file mode 100644 index 29c8ce7..0000000 --- a/src/com/jsyn/unitgen/LineOut.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Input audio is sent to the external audio output device. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class LineOut extends UnitGenerator implements UnitSink { - public UnitInputPort input; - - public LineOut() { - addPort(input = new UnitInputPort(2, "Input")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs0 = input.getValues(0); - double[] inputs1 = input.getValues(1); - double[] buffer0 = synthesisEngine.getOutputBuffer(0); - double[] buffer1 = synthesisEngine.getOutputBuffer(1); - for (int i = start; i < limit; i++) { - buffer0[i] += inputs0[i]; - buffer1[i] += inputs1[i]; - } - } - - /** - * This unit won't do anything unless you start() it. - */ - @Override - public boolean isStartRequired() { - return true; - } - - @Override - public UnitInputPort getInput() { - return input; - } -} diff --git a/src/com/jsyn/unitgen/LinearRamp.java b/src/com/jsyn/unitgen/LinearRamp.java deleted file mode 100644 index cad53d5..0000000 --- a/src/com/jsyn/unitgen/LinearRamp.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.UnitVariablePort; - -/** - * Output approaches Input linearly. - * <P> - * When you change the value of the input port, the ramp will start changing from its current output - * value toward the value of input. An internal phase value will go from 0.0 to 1.0 at a rate - * controlled by time. When the internal phase reaches 1.0, the output will equal input. - * <P> - * - * @author (C) 1997 Phil Burk, SoftSynth.com - * @see ExponentialRamp - * @see AsymptoticRamp - * @see ContinuousRamp - */ -public class LinearRamp extends UnitFilter { - /** Time in seconds to get to the input value. */ - public UnitInputPort time; - public UnitVariablePort current; - - private double source; - private double phase; - private double target; - private double timeHeld = 0.0; - private double rate = 1.0; - - public LinearRamp() { - addPort(time = new UnitInputPort("Time")); - addPort(current = new UnitVariablePort("Current")); - } - - @Override - public void generate(int start, int limit) { - double[] outputs = output.getValues(); - double currentInput = input.getValues()[0]; - double currentValue = current.getValue(); - - // If input has changed, start new segment. - // Equality check is OK because we set them exactly equal below. - if (currentInput != target) - { - source = currentValue; - phase = 0.0; - target = currentInput; - } - - if (currentValue == target) { - // at end of ramp - for (int i = start; i < limit; i++) { - outputs[i] = currentValue; - } - } else { - // in middle of ramp - double currentTime = time.getValues()[0]; - // Has time changed? - if (currentTime != timeHeld) { - rate = convertTimeToRate(currentTime); - timeHeld = currentTime; - } - - for (int i = start; i < limit; i++) { - if (phase < 1.0) { - /* Interpolate current. */ - currentValue = source + (phase * (target - source)); - phase += rate; - } else { - currentValue = target; - } - outputs[i] = currentValue; - } - } - - current.setValue(currentValue); - } -} diff --git a/src/com/jsyn/unitgen/Maximum.java b/src/com/jsyn/unitgen/Maximum.java deleted file mode 100644 index 296e5da..0000000 --- a/src/com/jsyn/unitgen/Maximum.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * - Output largest of inputA or inputB. - * - * <pre> - * output = (inputA > InputB) ? inputA : InputB; - * </pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see Minimum - */ -public class Maximum extends UnitBinaryOperator { - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = (aValues[i] > bValues[i]) ? aValues[i] : bValues[i]; - } - } -} diff --git a/src/com/jsyn/unitgen/Minimum.java b/src/com/jsyn/unitgen/Minimum.java deleted file mode 100644 index 046387e..0000000 --- a/src/com/jsyn/unitgen/Minimum.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * - Output smallest of inputA or inputB. - * - * <pre> - * output = (inputA < InputB) ? inputA : InputB; - * </pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see Maximum - */ -public class Minimum extends UnitBinaryOperator { - - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = (aValues[i] < bValues[i]) ? aValues[i] : bValues[i]; - } - } -} diff --git a/src/com/jsyn/unitgen/MixerMono.java b/src/com/jsyn/unitgen/MixerMono.java deleted file mode 100644 index f4c7d7d..0000000 --- a/src/com/jsyn/unitgen/MixerMono.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * Multi-channel mixer with mono output and master amplitude. - * - * @author Phil Burk (C) 2014 Mobileer Inc - * @see MixerMonoRamped - * @see MixerStereo - */ -public class MixerMono extends UnitGenerator implements UnitSink, UnitSource { - public UnitInputPort input; - /** - * Linear gain for the corresponding input. - */ - public UnitInputPort gain; - /** - * Master gain control. - */ - public UnitInputPort amplitude; - public UnitOutputPort output; - - public MixerMono(int numInputs) { - addPort(input = new UnitInputPort(numInputs, "Input")); - addPort(gain = new UnitInputPort(numInputs, "Gain", 1.0)); - addPort(amplitude = new UnitInputPort("Amplitude", 1.0)); - addPort(output = new UnitOutputPort(getNumOutputs(), "Output")); - } - - public int getNumOutputs() { - return 1; - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(0); - double[] outputs = output.getValues(0); - for (int i = start; i < limit; i++) { - double sum = 0; - for (int n = 0; n < input.getNumParts(); n++) { - double[] inputs = input.getValues(n); - double[] gains = gain.getValues(n); - sum += inputs[i] * gains[i]; - } - outputs[i] = sum * amplitudes[i]; - } - } - - @Override - public UnitInputPort getInput() { - return input; - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - -} diff --git a/src/com/jsyn/unitgen/MixerMonoRamped.java b/src/com/jsyn/unitgen/MixerMonoRamped.java deleted file mode 100644 index 30f5342..0000000 --- a/src/com/jsyn/unitgen/MixerMonoRamped.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * Similar to MixerMono but the gain and amplitude ports are smoothed using short linear ramps. So - * you can control them with knobs and not hear any zipper noise. - * - * @author Phil Burk (C) 2014 Mobileer Inc - */ -public class MixerMonoRamped extends MixerMono { - private Unzipper[] unzippers; - private Unzipper amplitudeUnzipper; - - public MixerMonoRamped(int numInputs) { - super(numInputs); - unzippers = new Unzipper[numInputs]; - for (int i = 0; i < numInputs; i++) { - unzippers[i] = new Unzipper(); - } - amplitudeUnzipper = new Unzipper(); - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(0); - double[] outputs = output.getValues(0); - for (int i = start; i < limit; i++) { - double sum = 0; - for (int n = 0; n < input.getNumParts(); n++) { - double[] inputs = input.getValues(n); - double[] gains = gain.getValues(n); - double smoothGain = unzippers[n].smooth(gains[i]); - sum += inputs[i] * smoothGain; - } - outputs[i] = sum * amplitudeUnzipper.smooth(amplitudes[i]); - } - } - -} diff --git a/src/com/jsyn/unitgen/MixerStereo.java b/src/com/jsyn/unitgen/MixerStereo.java deleted file mode 100644 index 218546e..0000000 --- a/src/com/jsyn/unitgen/MixerStereo.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * Mixer with monophonic inputs and two channels of output. Each signal can be panned left or right - * using an equal power curve. The "left" signal will be on output part zero. The "right" signal - * will be on output part one. - * - * @author Phil Burk (C) 2014 Mobileer Inc - * @see MixerMono - * @see MixerStereoRamped - */ -public class MixerStereo extends MixerMono { - /** - * Set to -1.0 for all left channel, 0.0 for center, or +1.0 for all right. Or anywhere in - * between. - */ - public UnitInputPort pan; - protected PanTracker[] panTrackers; - - static class PanTracker { - double previousPan = Double.MAX_VALUE; // so we update immediately - double leftGain; - double rightGain; - - public void update(double pan) { - if (pan != previousPan) { - // fastSine range is -1.0 to +1.0 for full cycle. - // We want a quarter cycle. So map -1.0 to +1.0 into 0.0 to 0.5 - double phase = pan * 0.25 + 0.25; - leftGain = SineOscillator.fastSin(0.5 - phase); - rightGain = SineOscillator.fastSin(phase); - previousPan = pan; - } - } - } - - public MixerStereo(int numInputs) { - super(numInputs); - addPort(pan = new UnitInputPort(numInputs, "Pan")); - pan.setup(-1.0, 0.0, 1.0); - panTrackers = new PanTracker[numInputs]; - for (int i = 0; i < numInputs; i++) { - panTrackers[i] = new PanTracker(); - } - } - - @Override - public int getNumOutputs() { - return 2; - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(0); - double[] outputs0 = output.getValues(0); - double[] outputs1 = output.getValues(1); - for (int i = start; i < limit; i++) { - double sum0 = 0.0; - double sum1 = 0.0; - for (int n = 0; n < input.getNumParts(); n++) { - double[] inputs = input.getValues(n); - double[] gains = gain.getValues(n); - double[] pans = pan.getValues(n); - PanTracker panTracker = panTrackers[n]; - panTracker.update(pans[i]); - double scaledInput = inputs[i] * gains[i]; - sum0 += scaledInput * panTracker.leftGain; - sum1 += scaledInput * panTracker.rightGain; - } - double amp = amplitudes[i]; - outputs0[i] = sum0 * amp; - outputs1[i] = sum1 * amp; - } - } - -} diff --git a/src/com/jsyn/unitgen/MixerStereoRamped.java b/src/com/jsyn/unitgen/MixerStereoRamped.java deleted file mode 100644 index 6f3bfcc..0000000 --- a/src/com/jsyn/unitgen/MixerStereoRamped.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * Similar to MixerStereo but the gain, pan and amplitude ports are smoothed using short linear - * ramps. So you can control them with knobs and not hear any zipper noise. - * - * @author Phil Burk (C) 2014 Mobileer Inc - */ -public class MixerStereoRamped extends MixerStereo { - private Unzipper[] gainUnzippers; - private Unzipper[] panUnzippers; - private Unzipper amplitudeUnzipper; - - public MixerStereoRamped(int numInputs) { - super(numInputs); - gainUnzippers = new Unzipper[numInputs]; - for (int i = 0; i < numInputs; i++) { - gainUnzippers[i] = new Unzipper(); - } - panUnzippers = new Unzipper[numInputs]; - for (int i = 0; i < numInputs; i++) { - panUnzippers[i] = new Unzipper(); - } - amplitudeUnzipper = new Unzipper(); - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(0); - double[] outputs0 = output.getValues(0); - double[] outputs1 = output.getValues(1); - for (int i = start; i < limit; i++) { - double sum0 = 0; - double sum1 = 0; - for (int n = 0; n < input.getNumParts(); n++) { - double[] inputs = input.getValues(n); - double[] gains = gain.getValues(n); - double[] pans = pan.getValues(n); - - PanTracker panTracker = panTrackers[n]; - double smoothPan = panUnzippers[n].smooth(pans[i]); - panTracker.update(smoothPan); - - double smoothGain = gainUnzippers[n].smooth(gains[i]); - double scaledInput = inputs[i] * smoothGain; - sum0 += scaledInput * panTracker.leftGain; - sum1 += scaledInput * panTracker.rightGain; - } - double amp = amplitudeUnzipper.smooth(amplitudes[i]); - outputs0[i] = sum0 * amp; - outputs1[i] = sum1 * amp; - } - } - -} diff --git a/src/com/jsyn/unitgen/MonoStreamWriter.java b/src/com/jsyn/unitgen/MonoStreamWriter.java deleted file mode 100644 index 283af81..0000000 --- a/src/com/jsyn/unitgen/MonoStreamWriter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2009 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 java.io.IOException; - -import com.jsyn.io.AudioOutputStream; -import com.jsyn.ports.UnitInputPort; - -/** - * Write one sample per audio frame to an AudioOutputStream with no interpolation. - * - * Note that you must call start() on this unit because it does not have an output for pulling data. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class MonoStreamWriter extends UnitStreamWriter { - public MonoStreamWriter() { - addPort(input = new UnitInputPort("Input")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - AudioOutputStream output = outputStream; - if (output != null) { - int count = limit - start; - try { - output.write(inputs, start, count); - } catch (IOException e) { - } - } - } - -} diff --git a/src/com/jsyn/unitgen/MorphingOscillatorBL.java b/src/com/jsyn/unitgen/MorphingOscillatorBL.java deleted file mode 100644 index 7ca440d..0000000 --- a/src/com/jsyn/unitgen/MorphingOscillatorBL.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2009 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.engine.MultiTable; -import com.jsyn.ports.UnitInputPort; - -/** - * Oscillator that can change its shape from sine to sawtooth to pulse. - * - * @author Phil Burk (C) 2016 Mobileer Inc - */ -public class MorphingOscillatorBL extends PulseOscillatorBL { - /** - * Controls the shape of the waveform. - * The shape varies continuously from a sine wave at -1.0, - * to a sawtooth at 0.0 to a pulse wave at 1.0. - */ - public UnitInputPort shape; - - public MorphingOscillatorBL() { - addPort(shape = new UnitInputPort("Shape")); - shape.setMinimum(-1.0); - shape.setMaximum(1.0); - } - - @Override - protected double generateBL(MultiTable multiTable, double currentPhase, - double positivePhaseIncrement, double flevel, int i) { - double[] shapes = shape.getValues(); - double shape = shapes[i]; - - if (shape < 0.0) { - // Squeeze flevel towards the pure sine table. - flevel += flevel * shape; - return multiTable.calculateSawtooth(currentPhase, positivePhaseIncrement, flevel); - } else { - double[] widths = width.getValues(); - double width = widths[i]; - width = (width > 0.999) ? 0.999 : ((width < -0.999) ? -0.999 : width); - - double val1 = multiTable.calculateSawtooth(currentPhase, positivePhaseIncrement, flevel); - // Generate second sawtooth so we can add them together. - double phase2 = currentPhase + 1.0 - width; // 180 degrees out of phase - if (phase2 >= 1.0) { - phase2 -= 2.0; - } - double val2 = multiTable.calculateSawtooth(phase2, positivePhaseIncrement, flevel); - - /* - * Need to adjust amplitude based on positive phaseInc. little less than half at - * Nyquist/2.0! - */ - double scale = 1.0 - positivePhaseIncrement; - return scale * (val1 - ((val2 + width) * shape)); // apply shape morphing - } - } -} diff --git a/src/com/jsyn/unitgen/MultiPassThrough.java b/src/com/jsyn/unitgen/MultiPassThrough.java deleted file mode 100644 index 9125fc3..0000000 --- a/src/com/jsyn/unitgen/MultiPassThrough.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; - -/** - * Pass the input through to the output unchanged. This is often used for distributing a signal to - * multiple ports inside a circuit. It can also be used as a summing node, in other words, a mixer. - * - * This is just like PassThrough except the input and output ports have multiple parts. - * The default is two parts, ie. stereo. - * - * @author Phil Burk (C) 2016 Mobileer Inc - * @see Circuit - * @see PassThrough - */ -public class MultiPassThrough extends UnitGenerator implements UnitSink, UnitSource { - public UnitInputPort input; - public UnitOutputPort output; - private final int mNumParts; - - /* Define Unit Ports used by connect() and set(). */ - public MultiPassThrough(int numParts) { - mNumParts = numParts; - addPort(input = new UnitInputPort(numParts, "Input")); - addPort(output = new UnitOutputPort(numParts, "Output")); - } - - public MultiPassThrough() { - this(2); // stereo - } - - @Override - public UnitInputPort getInput() { - return input; - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - - @Override - public void generate(int start, int limit) { - for (int partIndex = 0; partIndex < mNumParts; partIndex++) { - double[] inputs = input.getValues(partIndex); - double[] outputs = output.getValues(partIndex); - - for (int i = start; i < limit; i++) { - outputs[i] = inputs[i]; - } - } - } -} diff --git a/src/com/jsyn/unitgen/Multiply.java b/src/com/jsyn/unitgen/Multiply.java deleted file mode 100644 index ded7646..0000000 --- a/src/com/jsyn/unitgen/Multiply.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * This unit multiplies its two inputs. <br> - * - * <pre> - * output = inputA * inputB - * </pre> - * - * <br> - * Note that some units have an amplitude port, which controls an internal multiply. So you may not - * need this unit. - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see MultiplyAdd - * @see Subtract - */ -public class Multiply extends UnitBinaryOperator { - public Multiply() { - } - - /** Connect a to inputA and b to inputB. */ - public Multiply(UnitOutputPort a, UnitOutputPort b) { - a.connect(inputA); - b.connect(inputB); - } - - /** Connect a to inputA and b to inputB and connect output to c. */ - public Multiply(UnitOutputPort a, UnitOutputPort b, UnitInputPort c) { - this(a, b); - output.connect(c); - } - - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] outputs = output.getValues(); - for (int i = start; i < limit; i++) { - outputs[i] = aValues[i] * bValues[i]; - } - } - -} diff --git a/src/com/jsyn/unitgen/MultiplyAdd.java b/src/com/jsyn/unitgen/MultiplyAdd.java deleted file mode 100644 index adbee6c..0000000 --- a/src/com/jsyn/unitgen/MultiplyAdd.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * <pre> - * output = (inputA * inputB) + inputC - * </pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see Multiply - * @see Add - */ -public class MultiplyAdd extends UnitGenerator { - public UnitInputPort inputA; - public UnitInputPort inputB; - public UnitInputPort inputC; - public UnitOutputPort output; - - /* Define Unit Ports used by connect() and set(). */ - public MultiplyAdd() { - addPort(inputA = new UnitInputPort("InputA")); - addPort(inputB = new UnitInputPort("InputB")); - addPort(inputC = new UnitInputPort("InputC")); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] cValues = inputC.getValues(); - double[] outputs = output.getValues(); - for (int i = start; i < limit; i++) { - outputs[i] = (aValues[i] * bValues[i]) + cValues[i]; - } - } - -} diff --git a/src/com/jsyn/unitgen/Pan.java b/src/com/jsyn/unitgen/Pan.java deleted file mode 100644 index bc90984..0000000 --- a/src/com/jsyn/unitgen/Pan.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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; - -/** - * Pan unit. The profile is constant amplitude and not constant energy. - * <P> - * Takes an input and pans it between two outputs based on value of pan. When pan is -1, output[0] - * is input, and output[1] is zero. When pan is 0, output[0] and output[1] are both input/2. When - * pan is +1, output[0] is zero, and output[1] is input. - * <P> - * - * @author (C) 1997 Phil Burk, SoftSynth.com - * @see Select - */ -public class Pan extends UnitGenerator { - public UnitInputPort input; - /** - * Pan control varies from -1.0 for full left to +1.0 for full right. Set to 0.0 for center. - */ - public UnitInputPort pan; - public UnitOutputPort output; - - public Pan() { - addPort(input = new UnitInputPort("Input")); - addPort(pan = new UnitInputPort("Pan")); - addPort(output = new UnitOutputPort(2, "Output")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] panPtr = pan.getValues(); - double[] outputs_0 = output.getValues(0); - double[] outputs_1 = output.getValues(1); - - for (int i = start; i < limit; i++) { - double gainB = (panPtr[i] * 0.5) + 0.5; /* - * Scale and offset to 0.0 to 1.0 - */ - double gainA = 1.0 - gainB; - double inVal = inputs[i]; - outputs_0[i] = inVal * gainA; - outputs_1[i] = inVal * gainB; - } - } -} diff --git a/src/com/jsyn/unitgen/PanControl.java b/src/com/jsyn/unitgen/PanControl.java deleted file mode 100644 index 63bddd8..0000000 --- a/src/com/jsyn/unitgen/PanControl.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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; - -/** - * PanControl unit. - * <P> - * Generates control signals that can be used to control a mixer or the amplitude ports of two - * units. - * - * <PRE> - * temp = (pan * 0.5) + 0.5; - * output[0] = temp; - * output[1] = 1.0 - temp; - * </PRE> - * <P> - * - * @author (C) 1997-2009 Phil Burk, SoftSynth.com - */ -public class PanControl extends UnitGenerator { - public UnitInputPort pan; - public UnitOutputPort output; - - /* Define Unit Ports used by connect() and set(). */ - public PanControl() { - addPort(pan = new UnitInputPort("Pan")); - addPort(output = new UnitOutputPort(2, "Output", 0.0)); - } - - @Override - public void generate(int start, int limit) { - double[] panPtr = pan.getValues(); - double[] output0s = output.getValues(0); - double[] output1s = output.getValues(1); - - for (int i = start; i < limit; i++) { - double gainB = (panPtr[i] * 0.5) + 0.5; /* - * Scale and offset to 0.0 to 1.0 - */ - output0s[i] = 1.0 - gainB; - output1s[i] = gainB; - } - } -} diff --git a/src/com/jsyn/unitgen/ParabolicEnvelope.java b/src/com/jsyn/unitgen/ParabolicEnvelope.java deleted file mode 100644 index 6de97d9..0000000 --- a/src/com/jsyn/unitgen/ParabolicEnvelope.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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; - } - } -} diff --git a/src/com/jsyn/unitgen/PassThrough.java b/src/com/jsyn/unitgen/PassThrough.java deleted file mode 100644 index 8ac0b93..0000000 --- a/src/com/jsyn/unitgen/PassThrough.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.unitgen; - -/** - * Pass the input through to the output unchanged. This is often used for distributing a signal to - * multiple ports inside a circuit. It can also be used as a summing node, in other words, a mixer. - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see Circuit - * @see MultiPassThrough - */ -public class PassThrough extends UnitFilter { - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = inputs[i]; - } - - } -} diff --git a/src/com/jsyn/unitgen/PeakFollower.java b/src/com/jsyn/unitgen/PeakFollower.java deleted file mode 100644 index 7bf0508..0000000 --- a/src/com/jsyn/unitgen/PeakFollower.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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; -import com.jsyn.ports.UnitVariablePort; - -/** - * Tracks the peaks of an input signal. This can be used to monitor the overall amplitude of a - * signal. The output can be used to drive color organs, vocoders, VUmeters, etc. Output drops - * exponentially when the input drops below the current output level. The output approaches zero - * based on the value on the halfLife port. - * - * @author (C) 1997-2009 Phil Burk, SoftSynth.com - */ -public class PeakFollower extends UnitGenerator { - public UnitInputPort input; - public UnitVariablePort current; - public UnitInputPort halfLife; - public UnitOutputPort output; - - private double previousHalfLife = -1.0; - private double decayScalar = 0.99; - - /* Define Unit Ports used by connect() and set(). */ - public PeakFollower() { - addPort(input = new UnitInputPort("Input")); - addPort(halfLife = new UnitInputPort(1, "HalfLife", 0.1)); - addPort(current = new UnitVariablePort("Current")); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double currentHalfLife = halfLife.getValues()[0]; - double currentValue = current.getValue(); - - if (currentHalfLife != previousHalfLife) { - decayScalar = this.convertHalfLifeToMultiplier(currentHalfLife); - previousHalfLife = currentHalfLife; - } - - double scalar = 1.0 - decayScalar; - - for (int i = start; i < limit; i++) { - double inputValue = inputs[i]; - if (inputValue < 0.0) { - inputValue = -inputValue; // absolute value - } - - if (inputValue >= currentValue) { - currentValue = inputValue; - } else { - currentValue = currentValue * scalar; - } - - outputs[i] = currentValue; - } - - /* - * When current gets close to zero, set current to zero to prevent FP underflow, which can - * cause a severe performance degradation in 'C'. - */ - if (currentValue < VERY_SMALL_FLOAT) { - currentValue = 0.0; - } - - current.setValue(currentValue); - } -} diff --git a/src/com/jsyn/unitgen/PhaseShifter.java b/src/com/jsyn/unitgen/PhaseShifter.java deleted file mode 100644 index 4b17245..0000000 --- a/src/com/jsyn/unitgen/PhaseShifter.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * PhaseShifter effects processor. This unit emulates a common guitar pedal effect but without the - * LFO modulation. You can use your own modulation source connected to the "offset" port. Different - * frequencies are phase shifted varying amounts using a series of AllPass filters. By feeding the - * output back to the input we can get varying phase cancellation. This implementation was based on - * code posted to the music-dsp archive by Ross Bencina. http://www.musicdsp.org/files/phaser.cpp - * - * @author (C) 2014 Phil Burk, Mobileer Inc - * @see FilterLowPass - * @see FilterAllPass - * @see RangeConverter - */ - -public class PhaseShifter extends UnitFilter { - /** - * Connect an oscillator to this port to sweep the phase. A range of 0.05 to 0.4 is a good - * start. - */ - public UnitInputPort offset; - public UnitInputPort feedback; - public UnitInputPort depth; - - private double zm1; - private double[] xs; - private double[] ys; - - public PhaseShifter() { - this(6); - } - - public PhaseShifter(int numStages) { - addPort(offset = new UnitInputPort("Offset", 0.1)); - addPort(feedback = new UnitInputPort("Feedback", 0.7)); - addPort(depth = new UnitInputPort("Depth", 1.0)); - - xs = new double[numStages]; - ys = new double[numStages]; - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - double[] feedbacks = feedback.getValues(); - double[] depths = depth.getValues(); - double[] offsets = offset.getValues(); - double gain; - - for (int i = start; i < limit; i++) { - // Support audio rate modulation. - double currentOffset = offsets[i]; - - // Prevent gain from exceeding 1.0. - gain = 1.0 - (currentOffset * currentOffset); - if (gain < -1.0) { - gain = -1.0; - } - - double x = inputs[i] + (zm1 * feedbacks[i]); - // Cascaded all-pass filters. - for (int stage = 0; stage < xs.length; stage++) { - double temp = ys[stage] = (gain * (ys[stage] - x)) + xs[stage]; - xs[stage] = x; - x = temp; - } - zm1 = x; - outputs[i] = inputs[i] + (x * depths[i]); - } - } -} diff --git a/src/com/jsyn/unitgen/PinkNoise.java b/src/com/jsyn/unitgen/PinkNoise.java deleted file mode 100644 index 84aa2f2..0000000 --- a/src/com/jsyn/unitgen/PinkNoise.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2009 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; -import com.jsyn.util.PseudoRandom; - -/** - * Random output with 3dB per octave rolloff providing a soft natural noise sound. Generated using - * Gardner method. Optimization suggested by James McCartney uses a tree to select which random - * value to replace. - * - * <pre> - * x x x x x x x x x x x x x x x x - * x x x x x x x x - * x x x x - * x x - * x - * </pre> - * - * Tree is generated by counting trailing zeros in an increasing index. When the index is zero, no - * random number is selected. Author: Phil Burk (C) 1996 SoftSynth.com. - */ - -public class PinkNoise extends UnitGenerator implements UnitSource { - - public UnitInputPort amplitude; - public UnitOutputPort output; - - private final int NUM_ROWS = 16; - private final int RANDOM_BITS = 24; - private final int RANDOM_SHIFT = 32 - RANDOM_BITS; - - private PseudoRandom randomNum; - protected double prevNoise, currNoise; - - private long[] rows = new long[NUM_ROWS]; // NEXT RANDOM UNSIGNED 32 - private double scalar; // used to scale within range of -1.0 to +1.0 - private int runningSum; // used to optimize summing of generators - private int index; // incremented with each sample - private int indexMask; // index wrapped and ANDing with this mask - - /* Define Unit Ports used by connect() and set(). */ - public PinkNoise() { - addPort(amplitude = new UnitInputPort("Amplitude", UnitOscillator.DEFAULT_AMPLITUDE)); - addPort(output = new UnitOutputPort("Output")); - - randomNum = new PseudoRandom(); - - // set up for N rows of generators - index = 0; - indexMask = (1 << NUM_ROWS) - 1; - - // Calculate maximum possible signed random value. Extra 1 for white - // noise always added. - int pmax = (NUM_ROWS + 1) * (1 << (RANDOM_BITS - 1)); - scalar = 1.0 / pmax; - - // initialize rows - for (int i = 0; i < NUM_ROWS; i++) { - rows[i] = 0; - } - - runningSum = 0; - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = generatePinkNoise() * amplitudes[i]; - } - } - - public double generatePinkNoise() { - index = (index + 1) & indexMask; - - // If index is zero, don't update any random values. - if (index != 0) { - // Determine how many trailing zeros in PinkIndex. - // This algorithm will hang of n==0 so test first - int numZeros = 0; - int n = index; - - while ((n & 1) == 0) { - n = n >> 1; - numZeros++; - } - - // Replace the indexed ROWS random value. - // Subtract and add back to RunningSum instead of adding all the - // random values together. Only one changes each time. - runningSum -= rows[numZeros]; - int newRandom = randomNum.nextRandomInteger() >> RANDOM_SHIFT; - runningSum += newRandom; - rows[numZeros] = newRandom; - } - - // Add extra white noise value. - int newRandom = randomNum.nextRandomInteger() >> RANDOM_SHIFT; - int sum = runningSum + newRandom; - - // Scale to range of -1.0 to 0.9999. - return scalar * sum; - } - - @Override - public UnitOutputPort getOutput() { - return output; - } -} diff --git a/src/com/jsyn/unitgen/PitchDetector.java b/src/com/jsyn/unitgen/PitchDetector.java deleted file mode 100644 index da6a0e3..0000000 --- a/src/com/jsyn/unitgen/PitchDetector.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2012 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; -import com.jsyn.util.AutoCorrelator; -import com.jsyn.util.SignalCorrelator; - -/** - * Estimate the fundamental frequency of a monophonic signal. Analyzes an input signal and outputs - * an estimated period in frames and a frequency in Hertz. The frequency is frameRate/period. The - * confidence tells you how accurate the estimate is. When the confidence is low, you should ignore - * the period. You can use a CompareUnit and a LatchUnit to hold values that you are confident of. - * <P> - * Note that a stable monophonic signal is required for accurate pitch tracking. - * - * @author (C) 2012 Phil Burk, Mobileer Inc - */ -public class PitchDetector extends UnitGenerator { - public UnitInputPort input; - - public UnitOutputPort period; - public UnitOutputPort confidence; - public UnitOutputPort frequency; - public UnitOutputPort updated; - - protected SignalCorrelator signalCorrelator; - - private double lastFrequency = 440.0; - private double lastPeriod = 44100.0 / lastFrequency; // result of analysis TODO update for 48000 - private double lastConfidence = 0.0; // Measure of confidence in the result. - - private static final int LOWEST_FREQUENCY = 40; - private static final int HIGHEST_RATE = 48000; - private static final int CYCLES_NEEDED = 2; - - public PitchDetector() { - super(); - addPort(input = new UnitInputPort("Input")); - - addPort(period = new UnitOutputPort("Period")); - addPort(confidence = new UnitOutputPort("Confidence")); - addPort(frequency = new UnitOutputPort("Frequency")); - addPort(updated = new UnitOutputPort("Updated")); - signalCorrelator = createSignalCorrelator(); - } - - public SignalCorrelator createSignalCorrelator() { - int framesNeeded = HIGHEST_RATE * CYCLES_NEEDED / LOWEST_FREQUENCY; - return new AutoCorrelator(framesNeeded); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] periods = period.getValues(); - double[] confidences = confidence.getValues(); - double[] frequencies = frequency.getValues(); - double[] updateds = updated.getValues(); - - for (int i = start; i < limit; i++) { - double current = inputs[i]; - if (signalCorrelator.addSample(current)) { - lastPeriod = signalCorrelator.getPeriod(); - if (lastPeriod < 0.1) { - System.out.println("ILLEGAL PERIOD"); - } - double currentFrequency = getFrameRate() / (lastPeriod + 0); - double confidence = signalCorrelator.getConfidence(); - if (confidence > 0.1) { - if (true) { - double coefficient = confidence * 0.2; - // Take weighted average with previous frequency. - lastFrequency = ((lastFrequency * (1.0 - coefficient)) + (currentFrequency * coefficient)); - } else { - lastFrequency = ((lastFrequency * lastConfidence) + (currentFrequency * confidence)) - / (lastConfidence + confidence); - } - } - lastConfidence = confidence; - updateds[i] = 1.0; - } else { - updateds[i] = 0.0; - } - periods[i] = lastPeriod; - confidences[i] = lastConfidence; - frequencies[i] = lastFrequency; - } - } - - /** - * For debugging only. - * - * @return internal array of correlation results. - */ - public float[] getDiffs() { - return signalCorrelator.getDiffs(); - } - -} diff --git a/src/com/jsyn/unitgen/PitchToFrequency.java b/src/com/jsyn/unitgen/PitchToFrequency.java deleted file mode 100644 index 9086749..0000000 --- a/src/com/jsyn/unitgen/PitchToFrequency.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jsyn.unitgen; - -import com.softsynth.math.AudioMath; - -public class PitchToFrequency extends PowerOfTwo { - - public PitchToFrequency() { - input.setup(0.0, 60.0, 127.0); - } - - /** - * Convert from MIDI pitch to an octave offset from Concert A. - */ - @Override - public double adjustInput(double in) { - return (in - AudioMath.CONCERT_A_PITCH) * (1.0/12.0); - } - - /** - * Convert scaler to a frequency relative to Concert A. - */ - @Override - public double adjustOutput(double out) { - return out * AudioMath.getConcertAFrequency(); - } -} diff --git a/src/com/jsyn/unitgen/PowerOfTwo.java b/src/com/jsyn/unitgen/PowerOfTwo.java deleted file mode 100644 index 5916860..0000000 --- a/src/com/jsyn/unitgen/PowerOfTwo.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; - -/** - * output = (2.0^input) This is useful for converting a pitch modulation value into a frequency - * scaler. An input value of +1.0 will output 2.0 for an octave increase. An input value of -1.0 - * will output 0.5 for an octave decrease. - * - * This implementation uses a table lookup to optimize for - * speed. It is accurate enough for tuning. It also checks to see if the current input value is the - * same as the previous input value. If so then it reuses the previous computed value. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class PowerOfTwo extends UnitGenerator { - /** - * Offset in octaves. - */ - public UnitInputPort input; - public UnitOutputPort output; - - private static double[] table; - private static final int NUM_VALUES = 2048; - // Cached computation. - private double lastInput = 0.0; - private double lastOutput = 1.0; - - static { - // Add guard point for faster interpolation. - // Add another point to handle inputs like -1.5308084989341915E-17, - // which generate indices above range. - table = new double[NUM_VALUES + 2]; - // Fill one octave of the table. - for (int i = 0; i < table.length; i++) { - double value = Math.pow(2.0, ((double) i) / NUM_VALUES); - table[i] = value; - } - } - - public PowerOfTwo() { - addPort(input = new UnitInputPort("Input")); - input.setup(-8.0, 0.0, 8.0); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - double in = inputs[i]; - // Can we reuse a previously computed value? - if (in == lastInput) { - outputs[i] = lastOutput; - } else { - lastInput = in; - double adjustedInput = adjustInput(in); - int octave = (int) Math.floor(adjustedInput); - double normal = adjustedInput - octave; - // Do table lookup. - double findex = normal * NUM_VALUES; - int index = (int) findex; - double fraction = findex - index; - double value = table[index] + (fraction * (table[index + 1] - table[index])); - - // Adjust for octave. - while (octave > 0) { - octave -= 1; - value *= 2.0; - } - while (octave < 0) { - octave += 1; - value *= 0.5; - } - double adjustedOutput = adjustOutput(value); - outputs[i] = adjustedOutput; - lastOutput = adjustedOutput; - } - } - } - - public double adjustInput(double in) { - return in; - } - - public double adjustOutput(double out) { - return out; - } -} diff --git a/src/com/jsyn/unitgen/PulseOscillator.java b/src/com/jsyn/unitgen/PulseOscillator.java deleted file mode 100644 index 5ac7352..0000000 --- a/src/com/jsyn/unitgen/PulseOscillator.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Simple pulse wave oscillator. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class PulseOscillator extends UnitOscillator { - /** - * Pulse width varies from -1.0 to +1.0. At 0.0 the pulse is actually a square wave. - */ - public UnitInputPort width; - - public PulseOscillator() { - addPort(width = new UnitInputPort("Width")); - } - - @Override - public void generate(int start, int limit) { - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] widths = width.getValues(); - double[] outputs = output.getValues(); - - // Variables have a single value. - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - // Generate sawtooth phaser to provide phase for pulse generation. - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - double ampl = amplitudes[i]; - // Either full negative or positive amplitude. - outputs[i] = (currentPhase < widths[i]) ? -ampl : ampl; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/PulseOscillatorBL.java b/src/com/jsyn/unitgen/PulseOscillatorBL.java deleted file mode 100644 index c0e234c..0000000 --- a/src/com/jsyn/unitgen/PulseOscillatorBL.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2009 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.engine.MultiTable; -import com.jsyn.ports.UnitInputPort; - -/** - * Pulse oscillator that uses two band limited sawtooth waveforms. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class PulseOscillatorBL extends SawtoothOscillatorBL { - /** Controls the duty cycle of the pulse waveform. - * The width varies from -1.0 to +1.0. - * When width is zero the output is a square wave. - */ - public UnitInputPort width; - - public PulseOscillatorBL() { - addPort(width = new UnitInputPort("Width")); - } - - @Override - protected double generateBL(MultiTable multiTable, double currentPhase, - double positivePhaseIncrement, double flevel, int i) { - double[] widths = width.getValues(); - double width = widths[i]; - width = (width > 0.999) ? 0.999 : ((width < -0.999) ? -0.999 : width); - - double val1 = multiTable.calculateSawtooth(currentPhase, positivePhaseIncrement, flevel); - - // Generate second sawtooth so we can add them together. - double phase2 = currentPhase + 1.0 - width; // 180 degrees out of phase - if (phase2 >= 1.0) { - phase2 -= 2.0; - } - double val2 = multiTable.calculateSawtooth(phase2, positivePhaseIncrement, flevel); - - /* - * Need to adjust amplitude based on positive phaseInc and width. little less than half at - * Nyquist/2.0! - */ - double scale = 1.0 - positivePhaseIncrement; - return scale * (val1 - val2 - width); - } -} diff --git a/src/com/jsyn/unitgen/RaisedCosineEnvelope.java b/src/com/jsyn/unitgen/RaisedCosineEnvelope.java deleted file mode 100644 index c32417c..0000000 --- a/src/com/jsyn/unitgen/RaisedCosineEnvelope.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.unitgen; - -/** - * An envelope that can be used in a GrainFarm to shape the amplitude of a Grain. The envelope - * starts at 0.0, rises to 1.0, then returns to 0.0 following a cosine curve. - * - * <pre> - * output = 0.5 - (0.5 * cos(phase)) - * </pre> - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see GrainFarm - */ -public class RaisedCosineEnvelope extends GrainCommon implements GrainEnvelope { - protected double phase; - protected double phaseIncrement; - - public RaisedCosineEnvelope() { - setFrameRate(44100); - setDuration(0.1); - } - - /** - * @return next value of the envelope. - */ - @Override - public double next() { - phase += phaseIncrement; - if (phase > (2.0 * Math.PI)) { - return 0.0; - } else { - return 0.5 - (0.5 * Math.cos(phase)); // TODO optimize using Taylor expansion - } - } - - /** - * @return true if there are more envelope values left. - */ - @Override - public boolean hasMoreValues() { - return (phase < (2.0 * Math.PI)); - } - - /** - * Reset the envelope back to the beginning. - */ - @Override - public void reset() { - phase = 0.0; - } - - @Override - public void setDuration(double duration) { - phaseIncrement = 2.0 * Math.PI / (getFrameRate() * duration); - } - -} diff --git a/src/com/jsyn/unitgen/RangeConverter.java b/src/com/jsyn/unitgen/RangeConverter.java deleted file mode 100644 index ae94b0f..0000000 --- a/src/com/jsyn/unitgen/RangeConverter.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * Convert an input signal between -1.0 and +1.0 to the range min to max. This is handy when using - * an oscillator as a modulator. - * - * @author (C) 2014 Phil Burk, Mobileer Inc - * @see EdgeDetector - */ -public class RangeConverter extends UnitFilter { - public UnitInputPort min; - public UnitInputPort max; - - /* Define Unit Ports used by connect() and set(). */ - public RangeConverter() { - addPort(min = new UnitInputPort("Min", 40.0)); - addPort(max = new UnitInputPort("Max", 2000.0)); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] mins = min.getValues(); - double[] maxs = max.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - double low = mins[i]; - outputs[i] = low + ((maxs[i] - low) * (inputs[i] + 1) * 0.5); - } - } -} diff --git a/src/com/jsyn/unitgen/RectangularWindow.java b/src/com/jsyn/unitgen/RectangularWindow.java deleted file mode 100644 index d61f763..0000000 --- a/src/com/jsyn/unitgen/RectangularWindow.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013 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.data.SpectralWindow; - -/** - * Window that is just 1.0. Flat like a rectangle. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @see SpectralFFT - */ -public class RectangularWindow implements SpectralWindow { - static RectangularWindow instance = new RectangularWindow(); - - @Override - /** This always returns 1.0. Do not pass indices outside the window range. */ - public double get(int index) { - return 1.0; // impressive, eh? - } - - public static RectangularWindow getInstance() { - return instance; - } -} diff --git a/src/com/jsyn/unitgen/RedNoise.java b/src/com/jsyn/unitgen/RedNoise.java deleted file mode 100644 index d3e4321..0000000 --- a/src/com/jsyn/unitgen/RedNoise.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.util.PseudoRandom; - -/** - * RedNoise unit. This unit interpolates straight line segments between pseudo-random numbers to - * produce "red" noise. It is a grittier alternative to the white generator WhiteNoise. It is also - * useful as a slowly changing random control generator for natural sounds. Frequency port controls - * the number of times per second that a new random number is chosen. - * - * @author (C) 1997 Phil Burk, SoftSynth.com - * @see WhiteNoise - */ -public class RedNoise extends UnitOscillator { - private PseudoRandom randomNum; - protected double prevNoise, currNoise; - - /* Define Unit Ports used by connect() and set(). */ - public RedNoise() { - super(); - randomNum = new PseudoRandom(); - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] frequencies = frequency.getValues(); - double[] outputs = output.getValues(); - double currPhase = phase.getValue(); - double phaseIncrement, currOutput; - - double framePeriod = getFramePeriod(); - - for (int i = start; i < limit; i++) { - // compute phase - phaseIncrement = frequencies[i] * framePeriod; - - // verify that phase is within minimums and is not negative - if (phaseIncrement < 0.0) { - phaseIncrement = 0.0 - phaseIncrement; - } - if (phaseIncrement > 1.0) { - phaseIncrement = 1.0; - } - - currPhase += phaseIncrement; - - // calculate new random whenever phase passes 1.0 - if (currPhase > 1.0) { - prevNoise = currNoise; - currNoise = randomNum.nextRandomDouble(); - // reset phase for interpolation - currPhase -= 1.0; - } - - // interpolate current - currOutput = prevNoise + (currPhase * (currNoise - prevNoise)); - outputs[i] = currOutput * amplitudes[i]; - } - - // store new phase - phase.setValue(currPhase); - } -} diff --git a/src/com/jsyn/unitgen/SampleGrainFarm.java b/src/com/jsyn/unitgen/SampleGrainFarm.java deleted file mode 100644 index 3f908d6..0000000 --- a/src/com/jsyn/unitgen/SampleGrainFarm.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.data.FloatSample; -import com.jsyn.ports.UnitInputPort; - -/** - * A GrainFarm that uses a FloatSample as source material. In this example we load a FloatSample for - * use as a source material. - * - * <pre><code> - synth.add(sampleGrainFarm = new SampleGrainFarm()); - // Load a sample that we want to "granulate" from a file. - sample = SampleLoader.loadFloatSample(sampleFile); - sampleGrainFarm.setSample(sample); - // Use a ramp to move smoothly within the file. - synth.add(ramp = new ContinuousRamp()); - ramp.output.connect(sampleGrainFarm.position); -</code></pre> - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class SampleGrainFarm extends GrainFarm { - private FloatSample sample; - public UnitInputPort position; - public UnitInputPort positionRange; - - public SampleGrainFarm() { - super(); - addPort(position = new UnitInputPort("Position", 0.0)); - addPort(positionRange = new UnitInputPort("PositionRange", 0.0)); - } - - @Override - public void allocate(int numGrains) { - Grain[] grainArray = new Grain[numGrains]; - for (int i = 0; i < numGrains; i++) { - Grain grain = new Grain(new SampleGrainSource(), new RaisedCosineEnvelope()); - grainArray[i] = grain; - } - setGrainArray(grainArray); - } - - @Override - public void setupGrain(Grain grain, int i) { - SampleGrainSource sampleGrainSource = (SampleGrainSource) grain.getSource(); - sampleGrainSource.setSample(sample); - sampleGrainSource.setPosition(position.getValues()[i]); - sampleGrainSource.setPositionRange(positionRange.getValues()[i]); - super.setupGrain(grain, i); - } - - public void setSample(FloatSample sample) { - this.sample = sample; - } -} diff --git a/src/com/jsyn/unitgen/SampleGrainSource.java b/src/com/jsyn/unitgen/SampleGrainSource.java deleted file mode 100644 index f33817f..0000000 --- a/src/com/jsyn/unitgen/SampleGrainSource.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2009 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.data.FloatSample; - -public class SampleGrainSource extends GrainCommon implements GrainSource { - private FloatSample sample; - private double position; // ranges from -1.0 to 1.0 - private double positionRange; - private double phase; // ranges from 0.0 to 1.0 - private double phaseIncrement; - private int numFramesGuarded; - private static final double MAX_PHASE = 0.9999999999; - - @Override - public double next() { - phase += phaseIncrement; - if (phase > MAX_PHASE) { - phase = MAX_PHASE; - } - double fractionalIndex = phase * numFramesGuarded; - return sample.interpolate(fractionalIndex); - } - - @Override - public void setRate(double rate) { - phaseIncrement = rate * sample.getFrameRate() / (getFrameRate() * numFramesGuarded); - } - - public void setSample(FloatSample sample) { - this.sample = sample; - numFramesGuarded = sample.getNumFrames() - 1; - } - - public void setPosition(double position) { - this.position = position; - } - - @Override - public void reset() { - double randomPosition = position + (positionRange * (Math.random() - 0.5)); - phase = (randomPosition * 0.5) + 0.5; - if (phase < 0.0) { - phase = 0.0; - } else if (phase > MAX_PHASE) { - phase = MAX_PHASE; - } - } - - public void setPositionRange(double positionRange) { - this.positionRange = positionRange; - } - -} diff --git a/src/com/jsyn/unitgen/SawtoothOscillator.java b/src/com/jsyn/unitgen/SawtoothOscillator.java deleted file mode 100644 index 1b3dead..0000000 --- a/src/com/jsyn/unitgen/SawtoothOscillator.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Simple sawtooth oscillator. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class SawtoothOscillator extends UnitOscillator { - - @Override - public void generate(int start, int limit) { - - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - // Variables have a single value. - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - /* Generate sawtooth phasor to provide phase for sine generation. */ - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - outputs[i] = currentPhase * amplitudes[i]; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/SawtoothOscillatorBL.java b/src/com/jsyn/unitgen/SawtoothOscillatorBL.java deleted file mode 100644 index 8b58f6c..0000000 --- a/src/com/jsyn/unitgen/SawtoothOscillatorBL.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2009 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.engine.MultiTable; - -/** - * Sawtooth oscillator that uses multiple wave tables for band limiting. This requires more CPU than - * a plain SawtoothOscillator but has less aliasing at high frequencies. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class SawtoothOscillatorBL extends UnitOscillator { - @Override - public void generate(int start, int limit) { - MultiTable multiTable = MultiTable.getInstance(); - - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - // Variables have a single value. - double currentPhase = phase.getValue(); - - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[0]); - double positivePhaseIncrement = Math.abs(phaseIncrement); - // This is very expensive so we moved it outside the loop. - // Try to optimize it with a table lookup. - double flevel = multiTable.convertPhaseIncrementToLevel(positivePhaseIncrement); - - for (int i = start; i < limit; i++) { - /* Generate sawtooth phasor to provide phase for sine generation. */ - phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - positivePhaseIncrement = Math.abs(phaseIncrement); - - double val = generateBL(multiTable, currentPhase, positivePhaseIncrement, flevel, i); - - outputs[i] = val * amplitudes[i]; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - - protected double generateBL(MultiTable multiTable, double currentPhase, - double positivePhaseIncrement, double flevel, int i) { - /* Calculate table level then use it for lookup. */ - return multiTable.calculateSawtooth(currentPhase, positivePhaseIncrement, flevel); - } - -} diff --git a/src/com/jsyn/unitgen/SawtoothOscillatorDPW.java b/src/com/jsyn/unitgen/SawtoothOscillatorDPW.java deleted file mode 100644 index 27d0c5a..0000000 --- a/src/com/jsyn/unitgen/SawtoothOscillatorDPW.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Sawtooth DPW oscillator (a sawtooth with reduced aliasing). - * Based on a paper by Antti Huovilainen and Vesa Valimaki: - * http://www.scribd.com/doc/33863143/New-Approaches-to-Digital-Subtractive-Synthesis - * - * @author Phil Burk and Lisa Tolentino (C) 2009 Mobileer Inc - */ -public class SawtoothOscillatorDPW extends UnitOscillator { - // At a very low frequency, switch from DPW to raw sawtooth. - private static final double VERY_LOW_FREQUENCY = 2.0 * 0.1 / 44100.0; - private double z1; - private double z2; - - @Override - public void generate(int start, int limit) { - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - // Variables have a single value. - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - /* Generate raw sawtooth phaser. */ - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - - /* Square the raw sawtooth. */ - double squared = currentPhase * currentPhase; - // Differentiate using a delayed value. - double diffed = squared - z2; - z2 = z1; - z1 = squared; - - /* Calculate scaling based on phaseIncrement */ - double pinc = phaseIncrement; - // Absolute value. - if (pinc < 0.0) { - pinc = 0.0 - pinc; - } - - double dpw; - // If the frequency is very low then just use the raw sawtooth. - // This avoids divide by zero problems and scaling problems. - if (pinc < VERY_LOW_FREQUENCY) { - dpw = currentPhase; - } else { - dpw = diffed * 0.25 / pinc; - } - - outputs[i] = amplitudes[i] * dpw; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/SchmidtTrigger.java b/src/com/jsyn/unitgen/SchmidtTrigger.java deleted file mode 100644 index 64129ff..0000000 --- a/src/com/jsyn/unitgen/SchmidtTrigger.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * SchmidtTrigger unit. - * <P> - * Output logic level value with hysteresis. Transition high when input exceeds setLevel. Only go - * low when input is below resetLevel. This can be used to reject low level noise on the input - * signal. The default values for setLevel and resetLevel are both 0.0. Setting setLevel to 0.1 and - * resetLevel to -0.1 will give some hysteresis. The outputPulse is a single sample wide pulse set - * when the output transitions from low to high. - * - * <PRE> - * if (output == 0.0) - * output = (input > setLevel) ? 1.0 : 0.0; - * else if (output > 0.0) - * output = (input <= resetLevel) ? 0.0 : 1.0; - * else - * output = previous_output; - * </PRE> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see Compare - */ -public class SchmidtTrigger extends UnitFilter { - public UnitInputPort setLevel; - public UnitInputPort resetLevel; - public UnitOutputPort outputPulse; - - /* Define Unit Ports used by connect() and set(). */ - public SchmidtTrigger() { - addPort(setLevel = new UnitInputPort("SetLevel")); - addPort(resetLevel = new UnitInputPort("ResetLevel")); - addPort(input = new UnitInputPort("Input")); - addPort(outputPulse = new UnitOutputPort("OutputPulse")); - } - - @Override - public void generate(int start, int limit) { - double[] inPtr = input.getValues(); - double[] pulsePtr = outputPulse.getValues(); - double[] outPtr = output.getValues(); - double[] setPtr = setLevel.getValues(); - double[] resetPtr = resetLevel.getValues(); - - double outputValue = outPtr[0]; - boolean state = (outputValue > UnitGenerator.FALSE); - for (int i = start; i < limit; i++) { - pulsePtr[i] = UnitGenerator.FALSE; - if (state) { - if (inPtr[i] <= resetPtr[i]) { - state = false; - outputValue = UnitGenerator.FALSE; - } - } else { - if (inPtr[i] > setPtr[i]) { - state = true; - outputValue = UnitGenerator.TRUE; - pulsePtr[i] = UnitGenerator.TRUE; /* Single impulse. */ - } - } - outPtr[i] = outputValue; - } - } -} diff --git a/src/com/jsyn/unitgen/Select.java b/src/com/jsyn/unitgen/Select.java deleted file mode 100644 index 6d8792e..0000000 --- a/src/com/jsyn/unitgen/Select.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2004 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; - -/** - * SelectUnit unit. Select InputA or InputB based on value on Select port. - * - *<pre> <code> - output = ( select > 0.0 ) ? inputB : inputA; -</code> </pre> - * - * @author (C) 2004-2009 Phil Burk, SoftSynth.com - */ - -public class Select extends UnitGenerator { - public UnitInputPort inputA; - public UnitInputPort inputB; - public UnitInputPort select; - public UnitOutputPort output; - - public Select() { - addPort(inputA = new UnitInputPort("InputA")); - addPort(inputB = new UnitInputPort("InputB")); - addPort(select = new UnitInputPort("Select")); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] inputAs = inputA.getValues(); - double[] inputBs = inputB.getValues(); - double[] selects = select.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = (selects[i] > UnitGenerator.FALSE) ? inputBs[i] : inputAs[i]; - } - } -} diff --git a/src/com/jsyn/unitgen/SequentialDataReader.java b/src/com/jsyn/unitgen/SequentialDataReader.java deleted file mode 100644 index 901767b..0000000 --- a/src/com/jsyn/unitgen/SequentialDataReader.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2009 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.UnitDataQueuePort; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; - -/** - * Base class for reading a sample or envelope. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public abstract class SequentialDataReader extends UnitGenerator { - public UnitDataQueuePort dataQueue; - public UnitInputPort amplitude; - public UnitOutputPort output; - - /* Define Unit Ports used by connect() and set(). */ - public SequentialDataReader() { - addPort(dataQueue = new UnitDataQueuePort("Data")); - addPort(amplitude = new UnitInputPort("Amplitude", UnitOscillator.DEFAULT_AMPLITUDE)); - } -} diff --git a/src/com/jsyn/unitgen/SequentialDataWriter.java b/src/com/jsyn/unitgen/SequentialDataWriter.java deleted file mode 100644 index cb3bb11..0000000 --- a/src/com/jsyn/unitgen/SequentialDataWriter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2009 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.UnitDataQueuePort; -import com.jsyn.ports.UnitInputPort; - -/** - * Base class for writing to a sample. - * - * Note that you must call start() on subclasses of this unit because it does not have an output for pulling data. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public abstract class SequentialDataWriter extends UnitGenerator { - public UnitDataQueuePort dataQueue; - public UnitInputPort input; - - public SequentialDataWriter() { - addPort(dataQueue = new UnitDataQueuePort("Data")); - } - - /** - * This unit won't do anything unless you start() it. - */ - @Override - public boolean isStartRequired() { - return true; - } -} diff --git a/src/com/jsyn/unitgen/SineOscillator.java b/src/com/jsyn/unitgen/SineOscillator.java deleted file mode 100644 index 8c49ead..0000000 --- a/src/com/jsyn/unitgen/SineOscillator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Sine oscillator generates a frequency controlled sine wave. It is implemented using a fast Taylor - * expansion. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class SineOscillator extends UnitOscillator { - public SineOscillator() { - } - - public SineOscillator(double freq) { - frequency.set(freq); - } - - public SineOscillator(double freq, double amp) { - frequency.set(freq); - amplitude.set(amp); - } - - @Override - public void generate(int start, int limit) { - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - /* Generate sawtooth phasor to provide phase for sine generation. */ - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - if (true) { - double value = fastSin(currentPhase); - outputs[i] = value * amplitudes[i]; - } else { - // Slower but more accurate implementation. - outputs[i] = Math.sin(currentPhase * Math.PI) * amplitudes[i]; - } - } - - phase.setValue(currentPhase); - } - - /** - * Calculate sine using Taylor expansion. Do not use values outside the range. - * - * @param currentPhase in the range of -1.0 to +1.0 for one cycle - */ - public static double fastSin(double currentPhase) { - // Factorial constants so code is easier to read. - final double IF3 = 1.0 / (2 * 3); - final double IF5 = IF3 / (4 * 5); - final double IF7 = IF5 / (6 * 7); - final double IF9 = IF7 / (8 * 9); - final double IF11 = IF9 / (10 * 11); - - /* Wrap phase back into region where results are more accurate. */ - double yp = (currentPhase > 0.5) ? 1.0 - currentPhase : ((currentPhase < (-0.5)) ? (-1.0) - - currentPhase : currentPhase); - - double x = yp * Math.PI; - double x2 = (x * x); - /* Taylor expansion out to x**11/11! factored into multiply-adds */ - double fastsin = x - * (x2 * (x2 * (x2 * (x2 * ((x2 * (-IF11)) + IF9) - IF7) + IF5) - IF3) + 1); - return fastsin; - } -} diff --git a/src/com/jsyn/unitgen/SineOscillatorPhaseModulated.java b/src/com/jsyn/unitgen/SineOscillatorPhaseModulated.java deleted file mode 100644 index 7631dff..0000000 --- a/src/com/jsyn/unitgen/SineOscillatorPhaseModulated.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Sine oscillator with a phase modulation input. Phase modulation is similar to frequency - * modulation but is easier to use in some ways. - * - * <pre> - * output = sin(PI * (phase + modulation)) - * </pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class SineOscillatorPhaseModulated extends SineOscillator { - public UnitInputPort modulation; - - /* Define Unit Ports used by connect() and set(). */ - public SineOscillatorPhaseModulated() { - super(); - addPort(modulation = new UnitInputPort("Modulation")); - } - - @Override - public void generate(int start, int limit) { - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - double[] modulations = modulation.getValues(); - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - /* Generate sawtooth phaser to provide phase for sine generation. */ - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - double modulatedPhase = currentPhase + modulations[i]; - double value; - if (false) { - // TODO Compare benchmarks. - while (modulatedPhase >= 1.0) { - modulatedPhase -= 2.0; - } - while (modulatedPhase < -1.0) { - modulatedPhase += 2.0; - } - value = fastSin(modulatedPhase); - } else { - value = Math.sin(modulatedPhase * Math.PI); - } - outputs[i] = value * amplitudes[i]; - // System.out.format("Sine: freq = %10.4f , amp = %8.5f, out = %8.5f, phase = %8.5f, frame = %8d\n", - // frequencies[i], amplitudes[i],outputs[i],currentPhase,frame++ ); - } - - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/SpectralFFT.java b/src/com/jsyn/unitgen/SpectralFFT.java deleted file mode 100644 index f3e881a..0000000 --- a/src/com/jsyn/unitgen/SpectralFFT.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2013 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 java.util.Arrays; - -import com.jsyn.data.SpectralWindow; -import com.jsyn.data.Spectrum; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitSpectralOutputPort; -import com.softsynth.math.FourierMath; - -/** - * Periodically transform the input signal using an FFT. Output complete spectra. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @version 016 - * @see SpectralIFFT - * @see Spectrum - * @see SpectralFilter - */ -public class SpectralFFT extends UnitGenerator { - public UnitInputPort input; - /** - * Provides complete complex spectra when the FFT completes. - */ - public UnitSpectralOutputPort output; - private double[] buffer; - private int cursor; - private SpectralWindow window = RectangularWindow.getInstance(); - private int sizeLog2; - private int offset; - private boolean running; - - /* Define Unit Ports used by connect() and set(). */ - public SpectralFFT() { - this(Spectrum.DEFAULT_SIZE_LOG_2); - } - - /** - * @param sizeLog2 for example, pass 10 to get a 1024 bin FFT - */ - public SpectralFFT(int sizeLog2) { - addPort(input = new UnitInputPort("Input")); - addPort(output = new UnitSpectralOutputPort("Output", 1 << sizeLog2)); - setSizeLog2(sizeLog2); - } - - /** - * Please do not change the size of the FFT while JSyn is running. - * - * @param sizeLog2 for example, pass 9 to get a 512 bin FFT - */ - public void setSizeLog2(int sizeLog2) { - this.sizeLog2 = sizeLog2; - output.setSize(1 << sizeLog2); - buffer = output.getSpectrum().getReal(); - cursor = 0; - } - - public int getSizeLog2() { - return sizeLog2; - } - - @Override - public void generate(int start, int limit) { - if (!running) { - int mask = (1 << sizeLog2) - 1; - if (((getSynthesisEngine().getFrameCount() - offset) & mask) == 0) { - running = true; - cursor = 0; - } - } - // Don't use "else" because "running" may have changed in above block. - if (running) { - double[] inputs = input.getValues(); - for (int i = start; i < limit; i++) { - buffer[cursor] = inputs[i] * window.get(cursor); - ++cursor; - // When it is full, do the FFT. - if (cursor == buffer.length) { - Spectrum spectrum = output.getSpectrum(); - Arrays.fill(spectrum.getImaginary(), 0.0); - FourierMath.fft(buffer.length, spectrum.getReal(), spectrum.getImaginary()); - output.advance(); - cursor = 0; - } - } - } - } - - public SpectralWindow getWindow() { - return window; - } - - /** - * Multiply input data by this window before doing the FFT. The default is a RectangularWindow. - */ - public void setWindow(SpectralWindow window) { - this.window = window; - } - - /** - * The FFT will be performed on a frame that is a multiple of the size plus this offset. - * - * @param offset - */ - public void setOffset(int offset) { - this.offset = offset; - } - - public int getOffset() { - return offset; - } - -} diff --git a/src/com/jsyn/unitgen/SpectralFilter.java b/src/com/jsyn/unitgen/SpectralFilter.java deleted file mode 100644 index 758c8e7..0000000 --- a/src/com/jsyn/unitgen/SpectralFilter.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2014 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.data.SpectralWindow; -import com.jsyn.data.SpectralWindowFactory; -import com.jsyn.data.Spectrum; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.ports.UnitSpectralInputPort; -import com.jsyn.ports.UnitSpectralOutputPort; - -/** - * Process a signal using multiple overlapping FFT and IFFT pairs. For passthrough, you can connect - * the spectral outputs to the spectral inputs. Or you can connect one or more SpectralProcessors - * between them. - * - * <pre> - * for (int i = 0; i < numFFTs; i++) { - * filter.getSpectralOutput(i).connect(processors[i].input); - * processors[i].output.connect(filter.getSpectralInput(i)); - * } - * </pre> - * - * See the example program "HearSpectralFilter.java". Note that this spectral API is experimental - * and may change at any time. - * - * @author Phil Burk (C) 2014 Mobileer Inc - * @see SpectralProcessor - */ -public class SpectralFilter extends Circuit implements UnitSink, UnitSource { - public UnitInputPort input; - public UnitOutputPort output; - - private SpectralFFT[] ffts; - private SpectralIFFT[] iffts; - private PassThrough inlet; // fan out to FFTs - private PassThrough sum; // mix output of IFFTs - - /** - * Create a default sized filter with 2 FFT/IFFT pairs and a sizeLog2 of - * Spectrum.DEFAULT_SIZE_LOG_2. - */ - public SpectralFilter() { - this(2, Spectrum.DEFAULT_SIZE_LOG_2); - } - - /** - * @param numFFTs number of FFT/IFFT pairs for the overlap and add - * @param sizeLog2 for example, use 10 to get a 1024 bin FFT, 12 for 4096 - */ - public SpectralFilter(int numFFTs, int sizeLog2) { - add(inlet = new PassThrough()); - add(sum = new PassThrough()); - ffts = new SpectralFFT[numFFTs]; - iffts = new SpectralIFFT[numFFTs]; - int offset = (1 << sizeLog2) / numFFTs; - for (int i = 0; i < numFFTs; i++) { - add(ffts[i] = new SpectralFFT(sizeLog2)); - inlet.output.connect(ffts[i].input); - ffts[i].setOffset(i * offset); - - add(iffts[i] = new SpectralIFFT()); - iffts[i].output.connect(sum.input); - } - setWindow(SpectralWindowFactory.getHammingWindow(sizeLog2)); - - addPort(input = inlet.input); - addPort(output = sum.output); - } - - public SpectralWindow getWindow() { - return ffts[0].getWindow(); - } - - /** - * Specify one window to be used for all FFTs and IFFTs. The window should be the same size as - * the FFTs. - * - * @param window default is HammingWindow - * @see SpectralWindowFactory - */ - public void setWindow(SpectralWindow window) { - // Use the same window everywhere. - for (int i = 0; i < ffts.length; i++) { - ffts[i].setWindow(window); // TODO review, both sides or just one - iffts[i].setWindow(window); - } - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - - @Override - public UnitInputPort getInput() { - return input; - } - - /** - * @param i - * @return the output of the indexed FFT - */ - public UnitSpectralOutputPort getSpectralOutput(int i) { - return ffts[i].output; - } - - /** - * @param i - * @return the input of the indexed IFFT - */ - public UnitSpectralInputPort getSpectralInput(int i) { - return iffts[i].input; - } -} diff --git a/src/com/jsyn/unitgen/SpectralIFFT.java b/src/com/jsyn/unitgen/SpectralIFFT.java deleted file mode 100644 index c040e52..0000000 --- a/src/com/jsyn/unitgen/SpectralIFFT.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2013 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.data.SpectralWindow; -import com.jsyn.data.Spectrum; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.ports.UnitSpectralInputPort; -import com.softsynth.math.FourierMath; - -/** - * Periodically transform the input signal using an Inverse FFT. - * - * @author Phil Burk (C) 2013 Mobileer Inc - * @version 016 - * @see SpectralFFT - */ -public class SpectralIFFT extends UnitGenerator { - public UnitSpectralInputPort input; - public UnitOutputPort output; - private Spectrum localSpectrum; - private double[] buffer; - private int cursor; - private SpectralWindow window = RectangularWindow.getInstance(); - - /* Define Unit Ports used by connect() and set(). */ - public SpectralIFFT() { - addPort(output = new UnitOutputPort()); - addPort(input = new UnitSpectralInputPort("Input")); - } - - @Override - public void generate(int start, int limit) { - double[] outputs = output.getValues(); - - if (buffer == null) { - if (input.isAvailable()) { - Spectrum spectrum = input.getSpectrum(); - int size = spectrum.size(); - localSpectrum = new Spectrum(size); - buffer = localSpectrum.getReal(); - cursor = 0; - } else { - for (int i = start; i < limit; i++) { - outputs[i] = 0.0; - } - } - } - - if (buffer != null) { - for (int i = start; i < limit; i++) { - if (cursor == 0) { - Spectrum spectrum = input.getSpectrum(); - spectrum.copyTo(localSpectrum); - FourierMath.ifft(buffer.length, localSpectrum.getReal(), - localSpectrum.getImaginary()); - } - - outputs[i] = buffer[cursor] * window.get(cursor); - cursor += 1; - if (cursor == buffer.length) { - cursor = 0; - } - } - } - } - - public SpectralWindow getWindow() { - return window; - } - - /** - * Multiply output data by this window after doing the FFT. The default is a RectangularWindow. - */ - public void setWindow(SpectralWindow window) { - this.window = window; - } -} diff --git a/src/com/jsyn/unitgen/SpectralProcessor.java b/src/com/jsyn/unitgen/SpectralProcessor.java deleted file mode 100644 index de96877..0000000 --- a/src/com/jsyn/unitgen/SpectralProcessor.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2014 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.data.Spectrum; -import com.jsyn.ports.UnitSpectralInputPort; -import com.jsyn.ports.UnitSpectralOutputPort; - -/** - * This is a base class for implementing your own spectral processing units. You need to implement - * the processSpectrum() method. - * - * @author Phil Burk (C) 2014 Mobileer Inc - * @see Spectrum - */ -public abstract class SpectralProcessor extends UnitGenerator { - public UnitSpectralInputPort input; - public UnitSpectralOutputPort output; - private int counter; - - /* Define Unit Ports used by connect() and set(). */ - public SpectralProcessor() { - addPort(output = new UnitSpectralOutputPort()); - addPort(input = new UnitSpectralInputPort()); - } - - /* Define Unit Ports used by connect() and set(). */ - public SpectralProcessor(int size) { - addPort(output = new UnitSpectralOutputPort(size)); - addPort(input = new UnitSpectralInputPort()); - } - - @Override - public void generate(int start, int limit) { - for (int i = start; i < limit; i++) { - if (counter == 0) { - if (input.isAvailable()) { - Spectrum inputSpectrum = input.getSpectrum(); - Spectrum outputSpectrum = output.getSpectrum(); - processSpectrum(inputSpectrum, outputSpectrum); - - output.advance(); - counter = inputSpectrum.size() - 1; - } - } else { - counter--; - } - } - } - - /** - * Define this method to implement your own processor. - * - * @param inputSpectrum - * @param outputSpectrum - */ - public abstract void processSpectrum(Spectrum inputSpectrum, Spectrum outputSpectrum); - -} diff --git a/src/com/jsyn/unitgen/SquareOscillator.java b/src/com/jsyn/unitgen/SquareOscillator.java deleted file mode 100644 index aaca2d0..0000000 --- a/src/com/jsyn/unitgen/SquareOscillator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Simple square wave oscillator. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class SquareOscillator extends UnitOscillator { - - @Override - public void generate(int start, int limit) { - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - // Variables have a single value. - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - /* Generate sawtooth phasor to provide phase for square generation. */ - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - - double ampl = amplitudes[i]; - // Either full negative or positive amplitude. - outputs[i] = (currentPhase < 0.0) ? -ampl : ampl; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/SquareOscillatorBL.java b/src/com/jsyn/unitgen/SquareOscillatorBL.java deleted file mode 100644 index cb9e141..0000000 --- a/src/com/jsyn/unitgen/SquareOscillatorBL.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2009 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.engine.MultiTable; - -/** - * Band-limited square wave oscillator. This requires more CPU than a SquareOscillator but is less - * noisy at high frequencies. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class SquareOscillatorBL extends SawtoothOscillatorBL { - @Override - protected double generateBL(MultiTable multiTable, double currentPhase, - double positivePhaseIncrement, double flevel, int i) { - double val1 = multiTable.calculateSawtooth(currentPhase, positivePhaseIncrement, flevel); - - /* Generate second sawtooth so we can add them together. */ - double phase2 = currentPhase + 1.0; /* 180 degrees out of phase. */ - if (phase2 >= 1.0) { - phase2 -= 2.0; - } - double val2 = multiTable.calculateSawtooth(phase2, positivePhaseIncrement, flevel); - - /* - * Need to adjust amplitude based on positive phaseInc. little less than half at - * Nyquist/2.0! - */ - final double STARTAMP = 0.92; /* Derived by viewing waveforms with TJ_SEEOSC */ - double scale = STARTAMP - positivePhaseIncrement; - return scale * (val1 - val2); - } -} diff --git a/src/com/jsyn/unitgen/StereoStreamWriter.java b/src/com/jsyn/unitgen/StereoStreamWriter.java deleted file mode 100644 index b387836..0000000 --- a/src/com/jsyn/unitgen/StereoStreamWriter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2009 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 java.io.IOException; - -import com.jsyn.io.AudioOutputStream; -import com.jsyn.ports.UnitInputPort; - -/** - * Write two samples per audio frame to an AudioOutputStream as interleaved samples. - * - * Note that you must call start() on this unit because it does not have an output for pulling data. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class StereoStreamWriter extends UnitStreamWriter { - public StereoStreamWriter() { - addPort(input = new UnitInputPort(2, "Input")); - } - - @Override - public void generate(int start, int limit) { - double[] leftInputs = input.getValues(0); - double[] rightInputs = input.getValues(1); - AudioOutputStream output = outputStream; - if (output != null) { - try { - for (int i = start; i < limit; i++) { - output.write(leftInputs[i]); - output.write(rightInputs[i]); - } - } catch (IOException e) { - e.printStackTrace(); - output = null; - } - } - } -} diff --git a/src/com/jsyn/unitgen/StochasticGrainScheduler.java b/src/com/jsyn/unitgen/StochasticGrainScheduler.java deleted file mode 100644 index 1f79877..0000000 --- a/src/com/jsyn/unitgen/StochasticGrainScheduler.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.util.PseudoRandom; - -/** - * Use a random function to schedule grains. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class StochasticGrainScheduler implements GrainScheduler { - PseudoRandom pseudoRandom = new PseudoRandom(); - - @Override - public double nextDuration(double duration) { - return duration; - } - - @Override - public double nextGap(double duration, double density) { - if (density < 0.00000001) { - density = 0.00000001; - } - double gapRange = duration * (1.0 - density) / density; - return pseudoRandom.random() * gapRange; - } - -} diff --git a/src/com/jsyn/unitgen/Subtract.java b/src/com/jsyn/unitgen/Subtract.java deleted file mode 100644 index d9ca035..0000000 --- a/src/com/jsyn/unitgen/Subtract.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * This unit performs a signed subtraction on its two inputs. - * - * <pre> - * output = inputA - inputB - * </pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @version 016 - * @see MultiplyAdd - * @see Subtract - */ -public class Subtract extends UnitBinaryOperator { - @Override - public void generate(int start, int limit) { - double[] aValues = inputA.getValues(); - double[] bValues = inputB.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = aValues[i] - bValues[i]; - } - } -} diff --git a/src/com/jsyn/unitgen/TriangleOscillator.java b/src/com/jsyn/unitgen/TriangleOscillator.java deleted file mode 100644 index ada2d6e..0000000 --- a/src/com/jsyn/unitgen/TriangleOscillator.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Simple triangle wave oscillator. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class TriangleOscillator extends UnitOscillator { - int frame; - - public TriangleOscillator() { - super(); - phase.setValue(-0.5); - } - - @Override - public void generate(int start, int limit) { - - double[] frequencies = frequency.getValues(); - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - // Variables have a single value. - double currentPhase = phase.getValue(); - - for (int i = start; i < limit; i++) { - /* Generate sawtooth phasor to provide phase for triangle generation. */ - double phaseIncrement = convertFrequencyToPhaseIncrement(frequencies[i]); - currentPhase = incrementWrapPhase(currentPhase, phaseIncrement); - - /* Map phase to triangle waveform. */ - /* 0 - 0.999 => 0.5-p => +0.5 - -0.5 */ - /* -1.0 - 0.0 => 0.5+p => -0.5 - +0.5 */ - double triangle = (currentPhase >= 0.0) ? (0.5 - currentPhase) : (0.5 + currentPhase); - - outputs[i] = triangle * 2.0 * amplitudes[i]; - } - - // Value needs to be saved for next time. - phase.setValue(currentPhase); - } - -} diff --git a/src/com/jsyn/unitgen/TunableFilter.java b/src/com/jsyn/unitgen/TunableFilter.java deleted file mode 100644 index d2c9f66..0000000 --- a/src/com/jsyn/unitgen/TunableFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2009 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. - */ -/** - * Aug 26, 2009 - * com.jsyn.engine.units.TunableFilter.java - */ - -package com.jsyn.unitgen; - -import com.jsyn.ports.UnitInputPort; - -/** - * A UnitFilter with a frequency port. - * - * @author Phil Burk (C) 2009 Mobileer Inc Translated from 'C' to Java by Lisa - * Tolentino. - */ -public abstract class TunableFilter extends UnitFilter { - - static final double DEFAULT_FREQUENCY = 400; - public UnitInputPort frequency; - - public TunableFilter() { - addPort(frequency = new UnitInputPort("Frequency")); - frequency.setup(40.0, DEFAULT_FREQUENCY, 6000.0); - } - -} diff --git a/src/com/jsyn/unitgen/TwoInDualOut.java b/src/com/jsyn/unitgen/TwoInDualOut.java deleted file mode 100644 index a8fea48..0000000 --- a/src/com/jsyn/unitgen/TwoInDualOut.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2004 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; - -/** - * This unit combines two discrete inputs into a dual (stereo) output. - * - * <pre> - * output[0] = inputA - * output[1] = inputB - * </pre> - * - * @author (C) 2004-2009 Phil Burk, SoftSynth.com - */ - -public class TwoInDualOut extends UnitGenerator { - public UnitInputPort inputA; - public UnitInputPort inputB; - public UnitOutputPort output; - - public TwoInDualOut() { - addPort(inputA = new UnitInputPort("InputA")); - addPort(inputB = new UnitInputPort("InputB")); - addPort(output = new UnitOutputPort(2, "OutputB")); - } - - @Override - public void generate(int start, int limit) { - double[] inputAs = inputA.getValues(); - double[] inputBs = inputB.getValues(); - double[] output0s = output.getValues(0); - double[] output1s = output.getValues(1); - - for (int i = start; i < limit; i++) { - output0s[i] = inputAs[i]; - output1s[i] = inputBs[i]; - } - } -} diff --git a/src/com/jsyn/unitgen/UnitBinaryOperator.java b/src/com/jsyn/unitgen/UnitBinaryOperator.java deleted file mode 100644 index c5675ff..0000000 --- a/src/com/jsyn/unitgen/UnitBinaryOperator.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; - -/** - * Base class for binary arithmetic operators like Add and Compare. - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public abstract class UnitBinaryOperator extends UnitGenerator { - public UnitInputPort inputA; - public UnitInputPort inputB; - public UnitOutputPort output; - - /* Define Unit Ports used by connect() and set(). */ - public UnitBinaryOperator() { - addPort(inputA = new UnitInputPort("InputA")); - addPort(inputB = new UnitInputPort("InputB")); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public abstract void generate(int start, int limit); -} diff --git a/src/com/jsyn/unitgen/UnitFilter.java b/src/com/jsyn/unitgen/UnitFilter.java deleted file mode 100644 index 49976ba..0000000 --- a/src/com/jsyn/unitgen/UnitFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2009 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; - -/** - * Base class for all filters. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public abstract class UnitFilter extends UnitGenerator implements UnitSink, UnitSource { - public UnitInputPort input; - public UnitOutputPort output; - - /* Define Unit Ports used by connect() and set(). */ - public UnitFilter() { - addPort(input = new UnitInputPort("Input")); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public UnitInputPort getInput() { - return input; - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - -} diff --git a/src/com/jsyn/unitgen/UnitGate.java b/src/com/jsyn/unitgen/UnitGate.java deleted file mode 100644 index 59144c2..0000000 --- a/src/com/jsyn/unitgen/UnitGate.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012 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.UnitGatePort; -import com.jsyn.ports.UnitOutputPort; - -/** - * Base class for other envelopes. - * - * @author Phil Burk (C) 2012 Mobileer Inc - */ -public abstract class UnitGate extends UnitGenerator implements UnitSource { - /** - * Input that triggers the envelope. Use amplitude port if you want to connect a signal to be - * modulated by the envelope. - */ - public UnitGatePort input; - public UnitOutputPort output; - - public UnitGate() { - addPort(input = new UnitGatePort("Input")); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - - /** - * Specify a unit to be disabled when the envelope finishes. - * - * @param unit - */ - public void setupAutoDisable(UnitGenerator unit) { - input.setupAutoDisable(unit); - } - -} diff --git a/src/com/jsyn/unitgen/UnitGenerator.java b/src/com/jsyn/unitgen/UnitGenerator.java deleted file mode 100644 index 1e87ae6..0000000 --- a/src/com/jsyn/unitgen/UnitGenerator.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright 2009 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 java.io.PrintStream; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.logging.Logger; - -import com.jsyn.Synthesizer; -import com.jsyn.engine.SynthesisEngine; -import com.jsyn.ports.ConnectableInput; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.ports.UnitPort; -import com.softsynth.shared.time.TimeStamp; - -/** - * Base class for all unit generators. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public abstract class UnitGenerator { - protected static final double VERY_SMALL_FLOAT = 1.0e-26; - - // Some common port names. - public static final String PORT_NAME_INPUT = "Input"; - public static final String PORT_NAME_OUTPUT = "Output"; - public static final String PORT_NAME_PHASE = "Phase"; - public static final String PORT_NAME_FREQUENCY = "Frequency"; - public static final String PORT_NAME_FREQUENCY_SCALER = "FreqScaler"; - public static final String PORT_NAME_AMPLITUDE = "Amplitude"; - public static final String PORT_NAME_PAN = "Pan"; - public static final String PORT_NAME_TIME = "Time"; - public static final String PORT_NAME_CUTOFF = "Cutoff"; - public static final String PORT_NAME_PRESSURE = "Pressure"; - public static final String PORT_NAME_TIMBRE = "Timbre"; - - public static final double FALSE = 0.0; - public static final double TRUE = 1.0; - protected SynthesisEngine synthesisEngine; - private final LinkedHashMap<String, UnitPort> ports = new LinkedHashMap<String, UnitPort>(); - private Circuit circuit; - private long lastFrameCount; - private boolean enabled = true; - private static int nextId; - private final int id = nextId++; - - static Logger logger = Logger.getLogger(UnitGenerator.class.getName()); - - public int getId() { - return id; - } - - public int getFrameRate() { - // return frameRate; - return synthesisEngine.getFrameRate(); - } - - public double getFramePeriod() { - // return framePeriod; // TODO - Why does OldJSynTestSuite fail if I use this! - return synthesisEngine.getFramePeriod(); - } - - public void addPort(UnitPort port) { - port.setUnitGenerator(this); - // Store in a hash table by name. - ports.put(port.getName().toLowerCase(), port); - } - - public void addPort(UnitPort port, String name) { - port.setName(name); - addPort(port); - } - - /** - * Case-insensitive search for a port by name. - * @param portName - * @return matching port or null - */ - public UnitPort getPortByName(String portName) { - return ports.get(portName.toLowerCase()); - } - - public Collection<UnitPort> getPorts() { - return ports.values(); - } - - /** - * Perform essential synthesis function. - * - * @param start offset into port buffers - * @param limit limit offset into port buffers for loop - */ - public abstract void generate(int start, int limit); - - /** - * Generate a full block. - */ - public void generate() { - generate(0, Synthesizer.FRAMES_PER_BLOCK); - } - - /** - * @return the synthesisEngine - */ - public SynthesisEngine getSynthesisEngine() { - return synthesisEngine; - } - - /** - * @return the Synthesizer - */ - public Synthesizer getSynthesizer() { - return synthesisEngine; - } - - /** - * @param synthesisEngine the synthesisEngine to set - */ - public void setSynthesisEngine(SynthesisEngine synthesisEngine) { - if ((this.synthesisEngine != null) && (this.synthesisEngine != synthesisEngine)) { - throw new RuntimeException("Unit synthesisEngine already set."); - } - this.synthesisEngine = synthesisEngine; - } - - public UnitGenerator getTopUnit() { - UnitGenerator unit = this; - // Climb to top of circuit hierarchy. - while (unit.circuit != null) { - unit = unit.circuit; - } - logger.fine("getTopUnit " + this + " => " + unit); - return unit; - } - - protected void autoStop() { - synthesisEngine.autoStopUnit(getTopUnit()); - } - - /** Calculate signal based on halflife of an exponential decay. */ - public double convertHalfLifeToMultiplier(double halfLife) { - if (halfLife < (2.0 * getFramePeriod())) { - return 1.0; - } else { - // Oddly enough, this code is valid for both PeakFollower and AsymptoticRamp. - return 1.0 - Math.pow(0.5, 1.0 / (halfLife * getSynthesisEngine().getFrameRate())); - } - } - - protected double incrementWrapPhase(double currentPhase, double phaseIncrement) { - currentPhase += phaseIncrement; - - if (currentPhase >= 1.0) { - currentPhase -= 2.0; - } else if (currentPhase < -1.0) { - currentPhase += 2.0; - } - return currentPhase; - } - - /** Calculate rate based on phase going from 0.0 to 1.0 in time. */ - protected double convertTimeToRate(double time) { - double period2X = synthesisEngine.getInverseNyquist(); - if (time < period2X) { - return 1.0; - } else { - return getFramePeriod() / time; - } - } - - /** Flatten output ports so we don't output a changing signal when stopped. */ - public void flattenOutputs() { - for (UnitPort port : ports.values()) { - if (port instanceof UnitOutputPort) { - ((UnitOutputPort) port).flatten(); - } - } - } - - public void setCircuit(Circuit circuit) { - if ((this.circuit != null) && (circuit != null)) { - throw new RuntimeException("Unit is already in a circuit."); - } - // logger.info( "setCircuit in unit " + this + " with circuit " + circuit ); - this.circuit = circuit; - } - - public Circuit getCircuit() { - return circuit; - } - - public void pullData(long frameCount, int start, int limit) { - // Don't generate twice in case the paths merge. - if (enabled && (frameCount > lastFrameCount)) { - // Do this first to block recursion when there is a feedback loop. - lastFrameCount = frameCount; - // Then pull from all the units that are upstream. - for (UnitPort port : ports.values()) { - if (port instanceof ConnectableInput) { - ((ConnectableInput) port).pullData(frameCount, start, limit); - } - } - // Finally generate using outputs of the upstream units. - generate(start, limit); - } - } - - public boolean isEnabled() { - return enabled; - } - - /** - * If enabled, then a unit will execute if its output is connected to another unit that is - * executed. If not enabled then it will not execute and will not pull data from units that are - * connected to its inputs. Disabling a unit at the output of a tree of units can be used to - * turn off the entire tree, thus saving CPU cycles. - * - * @param enabled - * @see UnitGate#setupAutoDisable(UnitGenerator) - * @see start - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - if (!enabled) { - flattenOutputs(); - } - } - - /** - * Some units, for example LineOut and FixedRateMonoWriter, will only work if - * started explicitly. Other units will run when downstream units are started. - * - * @return true if you should call start() for this unit - */ - public boolean isStartRequired() { - return false; - } - - /** - * Start executing this unit directly by adding it to a "run list" of units in the synthesis - * engine. This method is normally only called for the final unit in a chain, for example a - * LineOut. When that final unit executes it will "pull" data from any units connected to its - * inputs. Those units will then pull data their inputs until the entire chain is executed. If - * units are connected in a circle then this will be detected and the infinite recursion will be - * blocked. - * - * @see setEnabled - */ - public void start() { - if (getSynthesisEngine() == null) { - throw new RuntimeException("This " + this.getClass().getName() - + " was not add()ed to a Synthesizer."); - } - getSynthesisEngine().startUnit(this); - } - - /** - * Start a unit at the specified time. - * - * @param time - * @see start - */ - public void start(double time) { - start(new TimeStamp(time)); - } - - /** - * Start a unit at the specified time. - * - * @param timeStamp - * @see start - */ - public void start(TimeStamp timeStamp) { - if (getSynthesisEngine() == null) { - throw new RuntimeException("This " + this.getClass().getName() - + " was not add()ed to a Synthesizer."); - } - getSynthesisEngine().startUnit(this, timeStamp); - } - - /** - * Stop a unit at the specified time. - * - * @param time - * @see start - */ - public void stop(double time) { - stop(new TimeStamp(time)); - } - - public void stop() { - getSynthesisEngine().stopUnit(this); - } - - public void stop(TimeStamp timeStamp) { - getSynthesisEngine().stopUnit(this, timeStamp); - } - - /** - * @deprecated ignored, frameRate comes from the SynthesisEngine - * @param rate - */ - @Deprecated - public void setFrameRate(int rate) { - } - - /** Needed by UnitSink */ - public UnitGenerator getUnitGenerator() { - return this; - } - - /** Needed by UnitVoice */ - public void setPort(String portName, double value, TimeStamp timeStamp) { - UnitInputPort port = (UnitInputPort) getPortByName(portName); - // System.out.println("setPort " + port ); - if (port == null) { - logger.warning("port was null for name " + portName + ", " + this.getClass().getName()); - } else { - port.set(value, timeStamp); - } - } - - public void printConnections() { - printConnections(System.out); - } - - public void printConnections(PrintStream out) { - printConnections(out, 0); - } - - public void printConnections(PrintStream out, int level) { - for (UnitPort port : getPorts()) { - if (port instanceof UnitInputPort) { - ((UnitInputPort) port).printConnections(out, level); - } - } - } - -} diff --git a/src/com/jsyn/unitgen/UnitOscillator.java b/src/com/jsyn/unitgen/UnitOscillator.java deleted file mode 100644 index 5d4c6fa..0000000 --- a/src/com/jsyn/unitgen/UnitOscillator.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2009 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; -import com.jsyn.ports.UnitVariablePort; -import com.softsynth.shared.time.TimeStamp; - -/** - * Base class for all oscillators. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public abstract class UnitOscillator extends UnitGenerator implements UnitVoice { - /** Frequency in Hertz. */ - public UnitInputPort frequency; - public UnitInputPort amplitude; - public UnitVariablePort phase; - public UnitOutputPort output; - - public static final double DEFAULT_FREQUENCY = 440.0; - public static final double DEFAULT_AMPLITUDE = 1.0; - - /* Define Unit Ports used by connect() and set(). */ - public UnitOscillator() { - addPort(frequency = new UnitInputPort(PORT_NAME_FREQUENCY)); - frequency.setup(40.0, DEFAULT_FREQUENCY, 8000.0); - addPort(amplitude = new UnitInputPort(PORT_NAME_AMPLITUDE, DEFAULT_AMPLITUDE)); - addPort(phase = new UnitVariablePort(PORT_NAME_PHASE)); - addPort(output = new UnitOutputPort(PORT_NAME_OUTPUT)); - } - - /** - * Convert a frequency in Hertz to a phaseIncrement in the range -1.0 to +1.0 - */ - public double convertFrequencyToPhaseIncrement(double freq) { - double phaseIncrement; - try { - phaseIncrement = freq * synthesisEngine.getInverseNyquist(); - } catch (NullPointerException e) { - throw new NullPointerException( - "Null Synth! You probably forgot to add this unit to the Synthesizer!"); - } - // Clip to range. - phaseIncrement = (phaseIncrement > 1.0) ? 1.0 : ((phaseIncrement < -1.0) ? -1.0 - : phaseIncrement); - return phaseIncrement; - } - - @Override - public UnitOutputPort getOutput() { - return output; - } - - public void noteOn(double freq, double ampl) { - frequency.set(freq); - amplitude.set(ampl); - } - - public void noteOff() { - amplitude.set(0.0); - } - - @Override - public void noteOff(TimeStamp timeStamp) { - amplitude.set(0.0, timeStamp); - } - - @Override - public void noteOn(double freq, double ampl, TimeStamp timeStamp) { - frequency.set(freq, timeStamp); - amplitude.set(ampl, timeStamp); - } - - @Override - public void usePreset(int presetIndex) { - } -} diff --git a/src/com/jsyn/unitgen/UnitSink.java b/src/com/jsyn/unitgen/UnitSink.java deleted file mode 100644 index 3e0f55e..0000000 --- a/src/com/jsyn/unitgen/UnitSink.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2009 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.softsynth.shared.time.TimeStamp; - -/** - * Interface for unit generators that have an input. - * - * @author Phil Burk, (C) 2009 Mobileer Inc - */ -public interface UnitSink { - public UnitInputPort getInput(); - - /** - * Begin execution of this unit by the Synthesizer. The input will pull data from any output - * port that is connected from it. - */ - public void start(); - - public void start(TimeStamp timeStamp); - - public void stop(); - - public void stop(TimeStamp timeStamp); - - public UnitGenerator getUnitGenerator(); -} diff --git a/src/com/jsyn/unitgen/UnitSource.java b/src/com/jsyn/unitgen/UnitSource.java deleted file mode 100644 index 5ee8134..0000000 --- a/src/com/jsyn/unitgen/UnitSource.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2009 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.UnitOutputPort; - -/** - * Interface for things that have that have an output and an associated UnitGenerator. - * - * @author Phil Burk, (C) 2009 Mobileer Inc - */ -public interface UnitSource { - public UnitOutputPort getOutput(); - - public UnitGenerator getUnitGenerator(); -} diff --git a/src/com/jsyn/unitgen/UnitStreamWriter.java b/src/com/jsyn/unitgen/UnitStreamWriter.java deleted file mode 100644 index 0c5bd8b..0000000 --- a/src/com/jsyn/unitgen/UnitStreamWriter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2009 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.io.AudioOutputStream; -import com.jsyn.ports.UnitInputPort; - -/** - * Base class for writing to an AudioOutputStream. - * - * Note that you must call start() on subclasses of this unit because it does not have an output for pulling data. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public abstract class UnitStreamWriter extends UnitGenerator implements UnitSink { - protected AudioOutputStream outputStream; - public UnitInputPort input; - - public AudioOutputStream getOutputStream() { - return outputStream; - } - - public void setOutputStream(AudioOutputStream outputStream) { - this.outputStream = outputStream; - } - - /** - * This unit won't do anything unless you start() it. - */ - @Override - public boolean isStartRequired() { - return true; - } - - @Override - public UnitInputPort getInput() { - return input; - } -} diff --git a/src/com/jsyn/unitgen/UnitVoice.java b/src/com/jsyn/unitgen/UnitVoice.java deleted file mode 100644 index 3f5e6ef..0000000 --- a/src/com/jsyn/unitgen/UnitVoice.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.unitgen; - -import com.jsyn.util.Instrument; -import com.jsyn.util.VoiceDescription; -import com.softsynth.shared.time.TimeStamp; - -/** - * A voice that can be allocated and played by the VoiceAllocator. - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see VoiceDescription - * @see Instrument - */ -public interface UnitVoice extends UnitSource { - /** - * Play whatever you consider to be a note on this voice. Do not be constrained by traditional - * definitions of notes or music. - * - * @param frequency in Hz related to the perceived pitch of the note. - * @param amplitude generally between 0.0 and 1.0 - * @param timeStamp when to play the note - */ - void noteOn(double frequency, double amplitude, TimeStamp timeStamp); - - void noteOff(TimeStamp timeStamp); - - /** - * Typically a UnitVoice will be a subclass of UnitGenerator, which just returns "this". - */ - @Override - public UnitGenerator getUnitGenerator(); - - /** - * Looks up a port using its name and sets the value. - * - * @param portName - * @param value - * @param timeStamp - */ - void setPort(String portName, double value, TimeStamp timeStamp); - - void usePreset(int presetIndex); -} diff --git a/src/com/jsyn/unitgen/Unzipper.java b/src/com/jsyn/unitgen/Unzipper.java deleted file mode 100644 index c776ffb..0000000 --- a/src/com/jsyn/unitgen/Unzipper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014 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; - -/** - * Used inside UnitGenerators for fast smoothing of inputs. - * - * @author Phil Burk (C) 2014 Mobileer Inc - */ -public class Unzipper { - private double target; - private double delta; - private double current; - private int counter; - // About 30 msec. Power of 2 so divide should be faster. - private static final int NUM_STEPS = 1024; - - public double smooth(double input) { - if (input != target) { - target = input; - delta = (target - current) / NUM_STEPS; - counter = NUM_STEPS; - } - if (counter > 0) { - if (--counter == 0) { - current = target; - } else { - current += delta; - } - } - return current; - } -} diff --git a/src/com/jsyn/unitgen/VariableRateDataReader.java b/src/com/jsyn/unitgen/VariableRateDataReader.java deleted file mode 100644 index 2ef163c..0000000 --- a/src/com/jsyn/unitgen/VariableRateDataReader.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2009 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; - -public abstract class VariableRateDataReader extends SequentialDataReader { - /** A scaler for playback rate. Nominally 1.0. */ - public UnitInputPort rate; - - public VariableRateDataReader() { - super(); - addPort(rate = new UnitInputPort("Rate", 1.0)); - } -} diff --git a/src/com/jsyn/unitgen/VariableRateMonoReader.java b/src/com/jsyn/unitgen/VariableRateMonoReader.java deleted file mode 100644 index 52b7f1e..0000000 --- a/src/com/jsyn/unitgen/VariableRateMonoReader.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2009 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.data.FloatSample; -import com.jsyn.data.SegmentedEnvelope; -import com.jsyn.data.ShortSample; -import com.jsyn.ports.UnitOutputPort; - -/** - * This reader can play any SequentialData and will interpolate between adjacent values. It can play - * both {@link SegmentedEnvelope envelopes} and {@link FloatSample samples}. - * - * <pre><code> - // Queue an envelope to the dataQueue port. - ampEnv.dataQueue.queue(ampEnvelope); -</code></pre> - * - * @author Phil Burk (C) 2009 Mobileer Inc - * @see FloatSample - * @see ShortSample - * @see SegmentedEnvelope - */ -public class VariableRateMonoReader extends VariableRateDataReader { - private double phase; // ranges from 0.0 to 1.0 - private double baseIncrement; - private double source; - private double current; - private double target; - private boolean starved; - private boolean ranout; - - public VariableRateMonoReader() { - super(); - addPort(output = new UnitOutputPort("Output")); - starved = true; - baseIncrement = 1.0; - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] rates = rate.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - // Decrement phase and advance through queued data until phase back - // in range. - if (phase >= 1.0) { - while (phase >= 1.0) { - source = target; - phase -= 1.0; - baseIncrement = advanceToNextFrame(); - } - } else if ((i == 0) && (starved || !dataQueue.isTargetValid())) { - // A starved condition can only be cured at the beginning of a - // block. - source = target = current; - phase = 0.0; - baseIncrement = advanceToNextFrame(); - } - - // Interpolate along line segment. - current = ((target - source) * phase) + source; - outputs[i] = current * amplitudes[i]; - - double phaseIncrement = baseIncrement * rates[i]; - phase += limitPhaseIncrement(phaseIncrement); - } - - if (ranout) { - ranout = false; - if (dataQueue.testAndClearAutoStop()) { - autoStop(); - } - } - } - - public double limitPhaseIncrement(double phaseIncrement) { - return phaseIncrement; - } - - private double advanceToNextFrame() { - // Fire callbacks before getting next value because we already got the - // target value previously. - dataQueue.firePendingCallbacks(); - if (dataQueue.hasMore()) { - starved = false; - target = dataQueue.readNextMonoDouble(getFramePeriod()); - - // calculate phase increment; - return getFramePeriod() * dataQueue.getNormalizedRate(); - } else { - starved = true; - ranout = true; - phase = 0.0; - return 0.0; - } - } - -} diff --git a/src/com/jsyn/unitgen/VariableRateStereoReader.java b/src/com/jsyn/unitgen/VariableRateStereoReader.java deleted file mode 100644 index 0f9fce8..0000000 --- a/src/com/jsyn/unitgen/VariableRateStereoReader.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2009 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.UnitOutputPort; - -/** - * This reader can play any SequentialData and will interpolate between adjacent values. It can play - * both envelopes and samples. - * - * @author Phil Burk (C) 2009 Mobileer Inc - */ -public class VariableRateStereoReader extends VariableRateDataReader { - private double phase; - private double baseIncrement; - private double source0; - private double current0; - private double target0; - private double source1; - private double current1; - private double target1; - private boolean starved; - private boolean ranout; - - public VariableRateStereoReader() { - dataQueue.setNumChannels(2); - addPort(output = new UnitOutputPort(2, "Output")); - starved = true; - baseIncrement = 1.0; - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] rates = rate.getValues(); - double[] output0s = output.getValues(0); - double[] output1s = output.getValues(1); - - for (int i = start; i < limit; i++) { - // Decrement phase and advance through queued data until phase back - // in range. - if (phase >= 1.0) { - while (phase >= 1.0) { - source0 = target0; - source1 = target1; - phase -= 1.0; - baseIncrement = advanceToNextFrame(); - } - } else if ((i == 0) && (starved || !dataQueue.isTargetValid())) { - // A starved condition can only be cured at the beginning of a block. - source0 = target0 = current0; - source1 = target1 = current1; - phase = 0.0; - baseIncrement = advanceToNextFrame(); - } - - // Interpolate along line segment. - current0 = ((target0 - source0) * phase) + source0; - output0s[i] = current0 * amplitudes[i]; - current1 = ((target1 - source1) * phase) + source1; - output1s[i] = current1 * amplitudes[i]; - - double phaseIncrement = baseIncrement * rates[i]; - phase += limitPhaseIncrement(phaseIncrement); - } - - if (ranout) { - ranout = false; - if (dataQueue.testAndClearAutoStop()) { - autoStop(); - } - } - } - - public double limitPhaseIncrement(double phaseIncrement) { - return phaseIncrement; - } - - private double advanceToNextFrame() { - dataQueue.firePendingCallbacks(); - if (dataQueue.hasMore()) { - starved = false; - - dataQueue.beginFrame(getFramePeriod()); - target0 = dataQueue.readCurrentChannelDouble(0); - target1 = dataQueue.readCurrentChannelDouble(1); - dataQueue.endFrame(); - - // calculate phase increment; - return synthesisEngine.getFramePeriod() * dataQueue.getNormalizedRate(); - } else { - starved = true; - ranout = true; - phase = 0.0; - return 0.0; - } - } - -} diff --git a/src/com/jsyn/unitgen/WhiteNoise.java b/src/com/jsyn/unitgen/WhiteNoise.java deleted file mode 100644 index b708e92..0000000 --- a/src/com/jsyn/unitgen/WhiteNoise.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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; -import com.jsyn.util.PseudoRandom; - -/** - * WhiteNoise unit. This unit uses a pseudo-random number generator to produce white noise. The - * energy in a white noise signal is distributed evenly across the spectrum. A new random number is - * generated every frame. - * - * @author (C) 1997-2011 Phil Burk, Mobileer Inc - * @see RedNoise - */ -public class WhiteNoise extends UnitGenerator implements UnitSource { - private PseudoRandom randomNum; - public UnitInputPort amplitude; - public UnitOutputPort output; - - public WhiteNoise() { - randomNum = new PseudoRandom(); - addPort(amplitude = new UnitInputPort("Amplitude", UnitOscillator.DEFAULT_AMPLITUDE)); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] amplitudes = amplitude.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - outputs[i] = randomNum.nextRandomDouble() * amplitudes[i]; - } - } - - @Override - public UnitOutputPort getOutput() { - return output; - } -} diff --git a/src/com/jsyn/unitgen/ZeroCrossingCounter.java b/src/com/jsyn/unitgen/ZeroCrossingCounter.java deleted file mode 100644 index 6cd36ea..0000000 --- a/src/com/jsyn/unitgen/ZeroCrossingCounter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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; - -/** - * Count zero crossings. Handy for unit tests. - * - * @author (C) 1997-2011 Phil Burk, Mobileer Inc - */ -public class ZeroCrossingCounter extends UnitGenerator { - private static final double THRESHOLD = 0.0001; - public UnitInputPort input; - public UnitOutputPort output; - - private long count; - private boolean armed; - - /* Define Unit Ports used by connect() and set(). */ - public ZeroCrossingCounter() { - addPort(input = new UnitInputPort("Input")); - addPort(output = new UnitOutputPort("Output")); - } - - @Override - public void generate(int start, int limit) { - double[] inputs = input.getValues(); - double[] outputs = output.getValues(); - - for (int i = start; i < limit; i++) { - double value = inputs[i]; - if (value < -THRESHOLD) { - armed = true; - } else if (armed & (value > THRESHOLD)) { - ++count; - armed = false; - } - outputs[i] = value; - } - } - - public long getCount() { - return count; - } -} diff --git a/src/com/jsyn/util/AudioSampleLoader.java b/src/com/jsyn/util/AudioSampleLoader.java deleted file mode 100644 index b665933..0000000 --- a/src/com/jsyn/util/AudioSampleLoader.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2009 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.util; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import com.jsyn.data.FloatSample; - -public interface AudioSampleLoader { - /** - * Load a FloatSample from a File object. - */ - public FloatSample loadFloatSample(File fileIn) throws IOException; - - /** - * Load a FloatSample from an InputStream. This is handy when loading Resources from a JAR file. - */ - public FloatSample loadFloatSample(InputStream inputStream) throws IOException; - - /** - * Load a FloatSample from a URL.. This is handy when loading Resources from a website. - */ - public FloatSample loadFloatSample(URL url) throws IOException; - -} diff --git a/src/com/jsyn/util/AudioStreamReader.java b/src/com/jsyn/util/AudioStreamReader.java deleted file mode 100644 index 5a725c3..0000000 --- a/src/com/jsyn/util/AudioStreamReader.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.util; - -import com.jsyn.Synthesizer; -import com.jsyn.io.AudioFifo; -import com.jsyn.io.AudioInputStream; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.unitgen.MonoStreamWriter; -import com.jsyn.unitgen.StereoStreamWriter; -import com.jsyn.unitgen.UnitStreamWriter; - -/** - * Reads audio signals from the background engine to a foreground application through an AudioFifo. - * Connect to the input port returned by getInput(). - * - * @author Phil Burk (C) 2010 Mobileer Inc - */ -public class AudioStreamReader implements AudioInputStream { - private UnitStreamWriter streamWriter; - private AudioFifo fifo; - - public AudioStreamReader(Synthesizer synth, int samplesPerFrame) { - if (samplesPerFrame == 1) { - streamWriter = new MonoStreamWriter(); - } else if (samplesPerFrame == 2) { - streamWriter = new StereoStreamWriter(); - } else { - throw new IllegalArgumentException("Only 1 or 2 samplesPerFrame supported."); - } - synth.add(streamWriter); - - fifo = new AudioFifo(); - fifo.setWriteWaitEnabled(!synth.isRealTime()); - fifo.setReadWaitEnabled(true); - fifo.allocate(32 * 1024); - streamWriter.setOutputStream(fifo); - streamWriter.start(); - } - - public UnitInputPort getInput() { - return streamWriter.input; - } - - /** How many values are available to read without blocking? */ - @Override - public int available() { - return fifo.available(); - } - - @Override - public void close() { - fifo.close(); - } - - @Override - public double read() { - return fifo.read(); - } - - @Override - public int read(double[] buffer) { - return fifo.read(buffer); - } - - @Override - public int read(double[] buffer, int start, int count) { - return fifo.read(buffer, start, count); - } - -} diff --git a/src/com/jsyn/util/AutoCorrelator.java b/src/com/jsyn/util/AutoCorrelator.java deleted file mode 100644 index 2996036..0000000 --- a/src/com/jsyn/util/AutoCorrelator.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2004 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.util; - -/** - * Calculate period of a repeated waveform in an array. This algorithm is based on a normalized - * auto-correlation function as dewscribed in: "A Smarter Way to Find Pitch" by Philip McLeod and - * Geoff Wyvill - * - * @author (C) 2004 Mobileer, PROPRIETARY and CONFIDENTIAL - */ -public class AutoCorrelator implements SignalCorrelator { - // A higher number will reject suboctaves more. - private static final float SUB_OCTAVE_REJECTION_FACTOR = 0.0005f; - // We can focus our analysis on the maxima - private static final int STATE_SEEKING_NEGATIVE = 0; - private static final int STATE_SEEKING_POSITIVE = 1; - private static final int STATE_SEEKING_MAXIMUM = 2; - private static final int[] tauAdvanceByState = { - 4, 2, 1 - }; - private int state; - - private float[] buffer; - // double buffer the diffs so we can view them - private float[] diffs; - private float[] diffs1; - private float[] diffs2; - private int cursor = -1; - private int tau; - - private float sumProducts; - private float sumSquares; - private float localMaximum; - private int localPosition; - private float bestMaximum; - private int bestPosition; - private int peakCounter; - // This factor was found empirically to reduce a systematic offset in the pitch. - private float pitchCorrectionFactor = 0.99988f; - - // Results of analysis. - private double period; - private double confidence; - private int minPeriod = 2; - private boolean bufferValid; - private double previousSample = 0.0; - private int maxWindowSize; - private float noiseThreshold = 0.001f; - - public AutoCorrelator(int numFrames) { - buffer = new float[numFrames]; - maxWindowSize = buffer.length / 2; - diffs1 = new float[2 + numFrames / 2]; - diffs2 = new float[diffs1.length]; - diffs = diffs1; - period = minPeriod; - reset(); - } - - // Scan assuming we will not wrap around the buffer. - private void rawDeltaScan(int last1, int last2, int count, int stride) { - for (int k = 0; k < count; k += stride) { - float d1 = buffer[last1 - k]; - float d2 = buffer[last2 - k]; - sumProducts += d1 * d2; - sumSquares += ((d1 * d1) + (d2 * d2)); - } - } - - // Do correlation when we know the splitLast will wrap around. - private void splitDeltaScan(int last1, int splitLast, int count, int stride) { - int c1 = splitLast; - rawDeltaScan(last1, splitLast, c1, stride); - rawDeltaScan(last1 - c1, buffer.length - 1, count - c1, stride); - } - - private void checkDeltaScan(int last1, int last2, int count, int stride) { - if (count > last2) { - int c1 = last2; - // Use recursion with reverse indexes to handle a double split. - checkDeltaScan(last2, last1, c1, stride); - checkDeltaScan(buffer.length - 1, last1 - c1, count - c1, stride); - } else if (count > last1) { - splitDeltaScan(last2, last1, count, stride); - } else { - rawDeltaScan(last1, last2, count, stride); - } - } - - // Perform correlation. Handle circular buffer wrap around. - // Normalized square difference function between -1.0 and +1.0. - private float topScan(int last1, int tau, int count, int stride) { - final float minimumResult = 0.00000001f; - - int last2 = last1 - tau; - if (last2 < 0) { - last2 += buffer.length; - } - sumProducts = 0.0f; - sumSquares = 0.0f; - checkDeltaScan(last1, last2, count, stride); - // Prevent divide by zero. - if (sumSquares < minimumResult) { - return minimumResult; - } - float correction = (float) Math.pow(pitchCorrectionFactor, tau); - float result = (float) (2.0 * sumProducts / sumSquares) * correction; - - return result; - } - - // Prepare for a new calculation. - private void reset() { - switchDiffs(); - int i = 0; - for (; i < minPeriod; i++) { - diffs[i] = 1.0f; - } - for (; i < diffs.length; i++) { - diffs[i] = 0.0f; - } - tau = minPeriod; - state = STATE_SEEKING_NEGATIVE; - peakCounter = 0; - bestMaximum = -1.0f; - bestPosition = -1; - } - - // Analyze new diff result. Incremental peak detection. - private void nextPeakAnalysis(int index) { - // Scale low frequency correlation down to reduce suboctave matching. - // Note that this has a side effect of reducing confidence value for low frequency sounds. - float value = diffs[index] * (1.0f - (index * SUB_OCTAVE_REJECTION_FACTOR)); - switch (state) { - case STATE_SEEKING_NEGATIVE: - if (value < -0.01f) { - state = STATE_SEEKING_POSITIVE; - } - break; - case STATE_SEEKING_POSITIVE: - if (value > 0.2f) { - state = STATE_SEEKING_MAXIMUM; - localMaximum = value; - localPosition = index; - } - break; - case STATE_SEEKING_MAXIMUM: - if (value > localMaximum) { - localMaximum = value; - localPosition = index; - } else if (value < -0.1f) { - peakCounter += 1; - if (localMaximum > bestMaximum) { - bestMaximum = localMaximum; - bestPosition = localPosition; - } - state = STATE_SEEKING_POSITIVE; - } - break; - } - } - - /** - * Generate interpolated maximum from index of absolute maximum using three point analysis. - */ - private double findPreciseMaximum(int indexMax) { - if (indexMax < 3) { - return 3.0; - } - if (indexMax == (diffs.length - 1)) { - return indexMax; - } - // Get 3 adjacent values. - double d1 = diffs[indexMax - 1]; - double d2 = diffs[indexMax]; - double d3 = diffs[indexMax + 1]; - - return interpolatePeak(d1, d2, d3) + indexMax; - } - - // Use quadratic fit to return offset between -0.5 and +0.5 from center. - protected static double interpolatePeak(double d1, double d2, double d3) { - return 0.5 * (d1 - d3) / (d1 - (2.0 * d2) + d3); - } - - // Calculate a little more for each sample. - // This spreads the CPU load out more evenly. - private boolean incrementalAnalysis() { - boolean updated = false; - if (bufferValid) { - // int windowSize = maxWindowSize; - // Interpolate between tau and maxWindowsSize based on confidence. - // If confidence is low then use bigger window. - int windowSize = (int) ((tau * confidence) + (maxWindowSize * (1.0 - confidence))); - - int stride = 1; - // int stride = (windowSize / 32) + 1; - - diffs[tau] = topScan(cursor, tau, windowSize, stride); - - // Check to see if the signal is strong enough to analyze. - // Look at sumPeriods on first correlation. - if ((tau == minPeriod) && (sumProducts < noiseThreshold)) { - // Update if we are dropping to zero confidence. - boolean result = (confidence > 0.0); - confidence = 0.0; - return result; - } - - nextPeakAnalysis(tau); - - // Reuse calculated values if we are not near a peak. - tau += 1; - int advance = tauAdvanceByState[state] - 1; - while ((advance > 0) && (tau < diffs.length)) { - diffs[tau] = diffs[tau - 1]; - tau++; - advance--; - } - - if ((peakCounter >= 4) || (tau >= maxWindowSize)) { - if (bestMaximum > 0.0) { - period = findPreciseMaximum(bestPosition); - // clip into range 0.0 to 1.0, low values are really bogus - confidence = (bestMaximum < 0.0) ? 0.0 : bestMaximum; - } else { - confidence = 0.0; - } - updated = true; - reset(); - } - } - return updated; - } - - @Override - public float[] getDiffs() { - // Return diffs that are not currently being used - return (diffs == diffs1) ? diffs2 : diffs1; - } - - private void switchDiffs() { - diffs = (diffs == diffs1) ? diffs2 : diffs1; - } - - @Override - public boolean addSample(double value) { - double average = (value + previousSample) * 0.5; - previousSample = value; - - cursor += 1; - if (cursor == buffer.length) { - cursor = 0; - bufferValid = true; - } - buffer[cursor] = (float) average; - - return incrementalAnalysis(); - } - - @Override - public double getPeriod() { - return period; - } - - @Override - public double getConfidence() { - return confidence; - } - - public float getPitchCorrectionFactor() { - return pitchCorrectionFactor; - } - - public void setPitchCorrectionFactor(float pitchCorrectionFactor) { - this.pitchCorrectionFactor = pitchCorrectionFactor; - } -} diff --git a/src/com/jsyn/util/Instrument.java b/src/com/jsyn/util/Instrument.java deleted file mode 100644 index 8a53304..0000000 --- a/src/com/jsyn/util/Instrument.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.util; - -import com.softsynth.shared.time.TimeStamp; - -/** - * A note player that references one or more voices by a noteNumber. This is similar to the MIDI - * protocol that references voices by an integer pitch or keyIndex. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public interface Instrument { - // This will be applied to the voice when noteOn is called. - void usePreset(int presetIndex, TimeStamp timeStamp); - - public void noteOn(int tag, double frequency, double amplitude, TimeStamp timeStamp); - - public void noteOff(int tag, TimeStamp timeStamp); - - public void setPort(int tag, String portName, double value, TimeStamp timeStamp); - - public void allNotesOff(TimeStamp timeStamp); -} diff --git a/src/com/jsyn/util/InstrumentLibrary.java b/src/com/jsyn/util/InstrumentLibrary.java deleted file mode 100644 index 65113dc..0000000 --- a/src/com/jsyn/util/InstrumentLibrary.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.util; - -import com.jsyn.swing.InstrumentBrowser; - -/** - * A library of instruments that can be used to play notes. - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see InstrumentBrowser - */ - -public interface InstrumentLibrary { - public String getName(); - - public VoiceDescription[] getVoiceDescriptions(); -} diff --git a/src/com/jsyn/util/JavaSoundSampleLoader.java b/src/com/jsyn/util/JavaSoundSampleLoader.java deleted file mode 100644 index 56a654e..0000000 --- a/src/com/jsyn/util/JavaSoundSampleLoader.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.util; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.UnsupportedAudioFileException; - -import com.jsyn.data.FloatSample; - -/** - * Internal class for loading audio samples. Use SampleLoader instead. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -class JavaSoundSampleLoader implements AudioSampleLoader { - /** - * Load a FloatSample from a File object. - */ - @Override - public FloatSample loadFloatSample(File fileIn) throws IOException { - try { - return loadFloatSample(AudioSystem.getAudioInputStream(fileIn)); - } catch (UnsupportedAudioFileException e) { - throw new IOException(e); - } - } - - /** - * Load a FloatSample from an InputStream. This is handy when loading Resources from a JAR file. - */ - @Override - public FloatSample loadFloatSample(InputStream inputStream) throws IOException { - try { - return loadFloatSample(AudioSystem.getAudioInputStream(inputStream)); - } catch (UnsupportedAudioFileException e) { - throw new IOException(e); - } - } - - /** - * Load a FloatSample from a URL.. This is handy when loading Resources from a website. - */ - @Override - public FloatSample loadFloatSample(URL url) throws IOException { - try { - return loadFloatSample(AudioSystem.getAudioInputStream(url)); - } catch (UnsupportedAudioFileException e) { - throw new IOException(e); - } - } - - private FloatSample loadFloatSample(javax.sound.sampled.AudioInputStream audioInputStream) - throws IOException, UnsupportedAudioFileException { - float[] floatData = null; - FloatSample sample = null; - int bytesPerFrame = audioInputStream.getFormat().getFrameSize(); - if (bytesPerFrame == AudioSystem.NOT_SPECIFIED) { - // some audio formats may have unspecified frame size - // in that case we may read any amount of bytes - bytesPerFrame = 1; - } - AudioFormat format = audioInputStream.getFormat(); - if (format.getEncoding() == AudioFormat.Encoding.PCM_SIGNED) { - floatData = loadSignedPCM(audioInputStream); - } - sample = new FloatSample(floatData, format.getChannels()); - sample.setFrameRate(format.getFrameRate()); - return sample; - } - - private float[] loadSignedPCM(AudioInputStream audioInputStream) throws IOException, - UnsupportedAudioFileException { - int totalSamplesRead = 0; - AudioFormat format = audioInputStream.getFormat(); - int numFrames = (int) audioInputStream.getFrameLength(); - int numSamples = format.getChannels() * numFrames; - float[] data = new float[numSamples]; - final int bytesPerFrame = format.getFrameSize(); - // Set an arbitrary buffer size of 1024 frames. - int numBytes = 1024 * bytesPerFrame; - byte[] audioBytes = new byte[numBytes]; - int numBytesRead = 0; - int numFramesRead = 0; - // Try to read numBytes bytes from the file. - while ((numBytesRead = audioInputStream.read(audioBytes)) != -1) { - int bytesRemainder = numBytesRead % bytesPerFrame; - if (bytesRemainder != 0) { - // TODO Read until you get enough data. - throw new IOException("Read partial block of sample data!"); - } - - if (audioInputStream.getFormat().getSampleSizeInBits() == 16) { - if (format.isBigEndian()) { - SampleLoader.decodeBigI16ToF32(audioBytes, 0, numBytesRead, data, - totalSamplesRead); - } else { - SampleLoader.decodeLittleI16ToF32(audioBytes, 0, numBytesRead, data, - totalSamplesRead); - } - } else if (audioInputStream.getFormat().getSampleSizeInBits() == 24) { - if (format.isBigEndian()) { - SampleLoader.decodeBigI24ToF32(audioBytes, 0, numBytesRead, data, - totalSamplesRead); - } else { - SampleLoader.decodeLittleI24ToF32(audioBytes, 0, numBytesRead, data, - totalSamplesRead); - } - } else if (audioInputStream.getFormat().getSampleSizeInBits() == 32) { - if (format.isBigEndian()) { - SampleLoader.decodeBigI32ToF32(audioBytes, 0, numBytesRead, data, - totalSamplesRead); - } else { - SampleLoader.decodeLittleI32ToF32(audioBytes, 0, numBytesRead, data, - totalSamplesRead); - } - } else { - throw new UnsupportedAudioFileException( - "Only 16, 24 or 32 bit PCM samples supported."); - } - - // Calculate the number of frames actually read. - numFramesRead = numBytesRead / bytesPerFrame; - totalSamplesRead += numFramesRead * format.getChannels(); - } - return data; - } - -} diff --git a/src/com/jsyn/util/JavaTools.java b/src/com/jsyn/util/JavaTools.java deleted file mode 100644 index 65e3dd1..0000000 --- a/src/com/jsyn/util/JavaTools.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2009 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.util; - -public class JavaTools { - - @SuppressWarnings("rawtypes") - public static Class loadClass(String className, boolean verbose) { - Class newClass = null; - try { - newClass = Class.forName(className); - } catch (Throwable e) { - if (verbose) - System.out.println("Caught " + e); - } - if (newClass == null) { - try { - ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); - newClass = Class.forName(className, true, systemLoader); - } catch (Throwable e) { - if (verbose) - System.out.println("Caught " + e); - } - } - return newClass; - } - - /** - * First try Class.forName(). If this fails, try Class.forName() using - * ClassLoader.getSystemClassLoader(). - * - * @return Class or null - */ - @SuppressWarnings("rawtypes") - public static Class loadClass(String className) { - /** - * First try Class.forName(). If this fails, try Class.forName() using - * ClassLoader.getSystemClassLoader(). - * - * @return Class or null - */ - return loadClass(className, true); - } - -} diff --git a/src/com/jsyn/util/MultiChannelSynthesizer.java b/src/com/jsyn/util/MultiChannelSynthesizer.java deleted file mode 100644 index b84d753..0000000 --- a/src/com/jsyn/util/MultiChannelSynthesizer.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright 2016 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.util; - -import com.jsyn.Synthesizer; -import com.jsyn.engine.SynthesisEngine; -import com.jsyn.midi.MidiConstants; -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.unitgen.ExponentialRamp; -import com.jsyn.unitgen.LinearRamp; -import com.jsyn.unitgen.Multiply; -import com.jsyn.unitgen.Pan; -import com.jsyn.unitgen.PowerOfTwo; -import com.jsyn.unitgen.SineOscillator; -import com.jsyn.unitgen.TwoInDualOut; -import com.jsyn.unitgen.UnitGenerator; -import com.jsyn.unitgen.UnitOscillator; -import com.jsyn.unitgen.UnitVoice; -import com.softsynth.math.AudioMath; -import com.softsynth.shared.time.TimeStamp; - -/** - * General purpose synthesizer with "channels" - * that could be used to implement a MIDI synthesizer. - * - * Each channel has: - * <pre><code> - * lfo -> pitchToLinear -> [VOICES] -> volume* -> panner - * bend --/ - * </code></pre> - * - * Note: this class is experimental and subject to change. - * - * @author Phil Burk (C) 2016 Mobileer Inc - */ -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; - private UnitVoice[] voices; - private VoiceAllocator allocator; - - ChannelGroupContext(int numVoices, VoiceDescription voiceDescription) { - this.voiceDescription = voiceDescription; - - voices = new UnitVoice[numVoices]; - for (int i = 0; i < numVoices; i++) { - UnitVoice voice = voiceDescription.createUnitVoice(); - UnitGenerator ugen = voice.getUnitGenerator(); - synth.add(ugen); - voices[i] = voice; - - } - allocator = new VoiceAllocator(voices); - } - } - - private class ChannelContext { - private UnitOscillator lfo; - private PowerOfTwo pitchToLinear; - private LinearRamp timbreRamp; - private LinearRamp pressureRamp; - private ExponentialRamp volumeRamp; - private Multiply volumeMultiplier; - private Pan panner; - private double vibratoRate = 5.0; - private double bendRangeOctaves = 2.0 / 12.0; - private int presetIndex; - private ChannelGroupContext groupContext; - VoiceOperation voiceOperation = new VoiceOperation() { - @Override - public void operate (UnitVoice voice) { - voice.usePreset(presetIndex); - connectVoice(voice); - } - }; - - void setup(ChannelGroupContext groupContext) { - this.groupContext = groupContext; - synth.add(pitchToLinear = new PowerOfTwo()); - synth.add(lfo = new SineOscillator()); // TODO use a MorphingOscillator or switch - // between S&H etc. - // Use a ramp to smooth out the timbre changes. - // This helps reduce pops from changing filter cutoff too abruptly. - synth.add(timbreRamp = new LinearRamp()); - timbreRamp.time.set(0.02); - synth.add(pressureRamp = new LinearRamp()); - pressureRamp.time.set(0.02); - synth.add(volumeRamp = new ExponentialRamp()); - volumeRamp.input.set(1.0); - volumeRamp.time.set(0.02); - synth.add(volumeMultiplier = new Multiply()); - synth.add(panner = new Pan()); - - pitchToLinear.input.setValueAdded(true); // so we can sum pitch bend - lfo.output.connect(pitchToLinear.input); - lfo.amplitude.set(0.0); - lfo.frequency.set(vibratoRate); - - volumeRamp.output.connect(volumeMultiplier.inputB); - 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) { - UnitGenerator ugen = voice.getUnitGenerator(); - // Hook up some channel controllers to standard ports on the voice. - UnitInputPort freqMod = (UnitInputPort) ugen - .getPortByName(UnitGenerator.PORT_NAME_FREQUENCY_SCALER); - if (freqMod != null) { - freqMod.disconnectAll(); - pitchToLinear.output.connect(freqMod); - } - UnitInputPort timbrePort = (UnitInputPort) ugen - .getPortByName(UnitGenerator.PORT_NAME_TIMBRE); - if (timbrePort != null) { - timbrePort.disconnectAll(); - timbreRamp.output.connect(timbrePort); - timbreRamp.input.setup(timbrePort); - } - UnitInputPort pressurePort = (UnitInputPort) ugen - .getPortByName(UnitGenerator.PORT_NAME_PRESSURE); - if (pressurePort != null) { - pressurePort.disconnectAll(); - pressureRamp.output.connect(pressurePort); - pressureRamp.input.setup(pressurePort); - } - voice.getOutput().disconnectAll(); - voice.getOutput().connect(volumeMultiplier.inputA); // mono mix all the voices - } - - void programChange(int program) { - int programWrapped = program % groupContext.voiceDescription.getPresetCount(); - String name = groupContext.voiceDescription.getPresetNames()[programWrapped]; - //System.out.println("Preset[" + program + "] = " + name); - presetIndex = programWrapped; - } - - void noteOff(int noteNumber, double amplitude) { - groupContext.allocator.noteOff(noteNumber, synth.createTimeStamp()); - } - - void noteOff(int noteNumber, double amplitude, TimeStamp timeStamp) { - groupContext.allocator.noteOff(noteNumber, timeStamp); - } - - void noteOn(int noteNumber, double amplitude) { - noteOn(noteNumber, amplitude, synth.createTimeStamp()); - } - - void noteOn(int noteNumber, double amplitude, TimeStamp timeStamp) { - double frequency = AudioMath.pitchToFrequency(noteNumber); - //System.out.println("noteOn(noteNumber) -> " + frequency + " Hz"); - groupContext.allocator.noteOn(noteNumber, frequency, amplitude, voiceOperation, timeStamp); - } - - public void setPitchBend(double offset) { - pitchToLinear.input.set(bendRangeOctaves * offset); - } - - public void setBendRange(double semitones) { - bendRangeOctaves = semitones / 12.0; - } - - public void setVibratoDepth(double semitones) { - lfo.amplitude.set(semitones); - } - - public void setVolume(double volume) { - double min = SynthesisEngine.DB96; - double max = 1.0; - double ratio = max / min; - double value = min * Math.pow(ratio, volume); - volumeRamp.input.set(value); - } - - public void setPan(double pan) { - panner.pan.set(pan); - } - - /* - * @param timbre normalized 0 to 1 - */ - public void setTimbre(double timbre) { - double min = timbreRamp.input.getMinimum(); - double max = timbreRamp.input.getMaximum(); - double value = min + (timbre * (max - min)); - timbreRamp.input.set(value); - } - - /* - * @param pressure normalized 0 to 1 - */ - public void setPressure(double pressure) { - double min = pressureRamp.input.getMinimum(); - double max = pressureRamp.input.getMaximum(); - double ratio = max / min; - double value = min * Math.pow(ratio, pressure); - pressureRamp.input.set(value); - } - } - - /** - * Construct a synthesizer with a maximum of 16 channels like MIDI. - */ - public MultiChannelSynthesizer() { - this(MidiConstants.MAX_CHANNELS); - } - - - public MultiChannelSynthesizer(int maxChannels) { - channels = new ChannelContext[maxChannels]; - for (int i = 0; i < channels.length; i++) { - channels[i] = new ChannelContext(); - } - } - - /** - * Specify a VoiceDescription to use with multiple channels. - * - * @param synth - * @param startChannel channel index is zero based - * @param numChannels - * @param voicesPerChannel - * @param voiceDescription - */ - public void setup(Synthesizer synth, int startChannel, int numChannels, int voicesPerChannel, - VoiceDescription voiceDescription) { - this.synth = synth; - if (outputUnit == null) { - synth.add(outputUnit = new TwoInDualOut()); - } - ChannelGroupContext groupContext = new ChannelGroupContext(voicesPerChannel, - voiceDescription); - for (int i = 0; i < numChannels; i++) { - channels[startChannel + i].setup(groupContext); - } - } - - public void programChange(int channel, int program) { - ChannelContext channelContext = channels[channel]; - 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, amplitude * mMasterAmplitude); - } - - /** - * 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, TimeStamp timeStamp) { - ChannelContext channelContext = channels[channel]; - channelContext.noteOff(noteNumber, amplitude * mMasterAmplitude, timeStamp); - } - - /** - * 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, TimeStamp timeStamp) { - ChannelContext channelContext = channels[channel]; - channelContext.noteOn(noteNumber, amplitude * mMasterAmplitude, timeStamp); - } - - /** - * 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, amplitude * mMasterAmplitude); - } - - /** - * Set a pitch offset that will be scaled by the range for the channel. - * - * @param channel - * @param offset ranges from -1.0 to +1.0 - */ - public void setPitchBend(int channel, double offset) { - //System.out.println("setPitchBend[" + channel + "] = " + offset); - ChannelContext channelContext = channels[channel]; - channelContext.setPitchBend(offset); - } - - public void setBendRange(int channel, double semitones) { - ChannelContext channelContext = channels[channel]; - channelContext.setBendRange(semitones); - } - - public void setPressure(int channel, double pressure) { - ChannelContext channelContext = channels[channel]; - channelContext.setPressure(pressure); - } - - public void setVibratoDepth(int channel, double semitones) { - ChannelContext channelContext = channels[channel]; - channelContext.setVibratoDepth(semitones); - } - - public void setTimbre(int channel, double timbre) { - ChannelContext channelContext = channels[channel]; - channelContext.setTimbre(timbre); - } - - /** - * Set volume for entire channel. - * - * @param channel - * @param volume normalized between 0.0 and 1.0 - */ - public void setVolume(int channel, double volume) { - ChannelContext channelContext = channels[channel]; - channelContext.setVolume(volume); - } - - /** - * Pan from left to right. - * - * @param channel - * @param pan ranges from -1.0 to +1.0 - */ - public void setPan(int channel, double pan) { - ChannelContext channelContext = channels[channel]; - 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/NumericOutput.java b/src/com/jsyn/util/NumericOutput.java deleted file mode 100644 index 79afaf1..0000000 --- a/src/com/jsyn/util/NumericOutput.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 1999 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.util; - -/** - * Formatted numeric output. Convert integers and floats to strings based on field widths and - * desired decimal places. - * - * @author Phil Burk (C) 1999 SoftSynth.com - */ - -public class NumericOutput { - static char digitToChar(int digit) { - if (digit > 9) { - return (char) ('A' + digit - 10); - } else { - return (char) ('0' + digit); - } - } - - public static String integerToString(int n, int width, boolean leadingZeros) { - return integerToString(n, width, leadingZeros, 10); - } - - public static String integerToString(int n, int width) { - return integerToString(n, width, false, 10); - } - - public static String integerToString(int n, int width, boolean leadingZeros, int radix) { - if (width > 32) - width = 32; - StringBuffer buf = new StringBuffer(); - long ln = n; - boolean ifNeg = false; - // only do sign if decimal - if (radix != 10) { - // System.out.println("MASK before : ln = " + ln ); - ln = ln & 0x00000000FFFFFFFFL; - // System.out.println("MASK after : ln = " + ln ); - } else if (ln < 0) { - ifNeg = true; - ln = -ln; - } - if (ln == 0) { - buf.append('0'); - } else { - // System.out.println(" ln = " + ln ); - while (ln > 0) { - int rem = (int) (ln % radix); - buf.append(digitToChar(rem)); - ln = ln / radix; - } - } - if (leadingZeros) { - int pl = width; - if (ifNeg) - pl -= 1; - for (int i = buf.length(); i < pl; i++) - buf.append('0'); - } - if (ifNeg) - buf.append('-'); - // leading spaces - for (int i = buf.length(); i < width; i++) - buf.append(' '); - // reverse buffer to put characters in correct order - buf.reverse(); - - return buf.toString(); - } - - /** - * Convert double to string. - * - * @param width = minimum width of formatted string - * @param places = number of digits displayed after decimal point - */ - public static String doubleToString(double value, int width, int places) { - return doubleToString(value, width, places, false); - } - - /** - * Convert double to string. - * - * @param width = minimum width of formatted string - * @param places = number of digits displayed after decimal point - */ - public static String doubleToString(double value, int width, int places, boolean leadingZeros) { - if (width > 32) - width = 32; - if (places > 16) - places = 16; - - boolean ifNeg = false; - if (value < 0.0) { - ifNeg = true; - value = -value; - } - // round at relevant decimal place - value += 0.5 * Math.pow(10.0, 0 - places); - int ival = (int) Math.floor(value); - // get portion after decimal point as an integer - int fval = (int) ((value - Math.floor(value)) * Math.pow(10.0, places)); - String result = ""; - - result += integerToString(ival, 0, false, 10); - result += "."; - result += integerToString(fval, places, true, 10); - - if (leadingZeros) { - // prepend leading zeros and {-} - int zw = width; - if (ifNeg) - zw -= 1; - while (result.length() < zw) - result = "0" + result; - if (ifNeg) - result = "-" + result; - } else { - // prepend {-} and leading spaces - if (ifNeg) - result = "-" + result; - while (result.length() < width) - result = " " + result; - } - return result; - } - - static void testInteger(int n) { - System.out.println("Test " + n + ", 0x" + Integer.toHexString(n) + ", %" - + Integer.toBinaryString(n)); - System.out.println(" +,8,t,10 = " + integerToString(n, 8, true, 10)); - System.out.println(" +,8,f,10 = " + integerToString(n, 8, false, 10)); - System.out.println(" -,8,t,10 = " + integerToString(-n, 8, true, 10)); - System.out.println(" -,8,f,10 = " + integerToString(-n, 8, false, 10)); - System.out.println(" +,8,t,16 = " + integerToString(n, 8, true, 16)); - System.out.println(" +,8,f,16 = " + integerToString(n, 8, false, 16)); - System.out.println(" -,8,t,16 = " + integerToString(-n, 8, true, 16)); - System.out.println(" -,8,f,16 = " + integerToString(-n, 8, false, 16)); - System.out.println(" +,8,t, 2 = " + integerToString(n, 8, true, 2)); - System.out.println(" +,8,f, 2 = " + integerToString(n, 8, false, 2)); - } - - static void testDouble(double value) { - System.out.println("Test " + value); - System.out.println(" +,5,1 = " + doubleToString(value, 5, 1)); - System.out.println(" -,5,1 = " + doubleToString(-value, 5, 1)); - - System.out.println(" +,14,3 = " + doubleToString(value, 14, 3)); - System.out.println(" -,14,3 = " + doubleToString(-value, 14, 3)); - - System.out.println(" +,6,2,true = " + doubleToString(value, 6, 2, true)); - System.out.println(" -,6,2,true = " + doubleToString(-value, 6, 2, true)); - } - - public static void main(String argv[]) { - System.out.println("Test NumericOutput"); - testInteger(0); - testInteger(1); - testInteger(16); - testInteger(23456); - testInteger(0x23456); - testInteger(0x89ABC); - testDouble(0.0); - testDouble(0.0678); - testDouble(0.1234567); - testDouble(1.234567); - testDouble(12.34567); - testDouble(123.4567); - testDouble(1234.5678); - - } -} diff --git a/src/com/jsyn/util/PolyphonicInstrument.java b/src/com/jsyn/util/PolyphonicInstrument.java deleted file mode 100644 index 08460d0..0000000 --- a/src/com/jsyn/util/PolyphonicInstrument.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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.util; - -import com.jsyn.ports.UnitInputPort; -import com.jsyn.ports.UnitOutputPort; -import com.jsyn.ports.UnitPort; -import com.jsyn.unitgen.Circuit; -import com.jsyn.unitgen.Multiply; -import com.jsyn.unitgen.PassThrough; -import com.jsyn.unitgen.UnitGenerator; -import com.jsyn.unitgen.UnitSource; -import com.jsyn.unitgen.UnitVoice; -import com.softsynth.shared.time.TimeStamp; - -/** - * The API for this class is likely to change. Please comment on its usefulness. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ - -public class PolyphonicInstrument extends Circuit implements UnitSource, Instrument { - private Multiply mixer; - private UnitVoice[] voices; - private VoiceAllocator voiceAllocator; - public UnitInputPort amplitude; - - public PolyphonicInstrument(UnitVoice[] voices) { - this.voices = voices; - voiceAllocator = new VoiceAllocator(voices); - add(mixer = new Multiply()); - // Mix all the voices to one output. - for (UnitVoice voice : voices) { - UnitGenerator unit = voice.getUnitGenerator(); - boolean wasEnabled = unit.isEnabled(); - // This overrides the enabled property of the voice. - add(unit); - voice.getOutput().connect(mixer.inputA); - // restore - unit.setEnabled(wasEnabled); - } - - addPort(amplitude = mixer.inputB, "Amplitude"); - amplitude.setup(0.0001, 0.4, 2.0); - exportAllInputPorts(); - } - - /** - * Connect a PassThrough unit to the input ports of the voices so that they can be controlled - * together using a single port. Note that this will prevent their individual use. So the - * "Frequency" and "Amplitude" ports are excluded. Note that this method is a bit funky and is - * likely to change. - */ - public void exportAllInputPorts() { - // Iterate through the ports. - for (UnitPort port : voices[0].getUnitGenerator().getPorts()) { - if (port instanceof UnitInputPort) { - UnitInputPort inputPort = (UnitInputPort) port; - String voicePortName = inputPort.getName(); - // FIXME Need better way to identify ports that are per note. - if (!voicePortName.equals("Frequency") && !voicePortName.equals("Amplitude")) { - exportNamedInputPort(voicePortName); - } - } - } - } - - /** - * Create a UnitInputPort for the circuit that is connected to the named port on each voice - * through a PassThrough unit. This allows you to control all of the voices at once. - * - * @param portName - * @see exportAllInputPorts - */ - public void exportNamedInputPort(String portName) { - UnitInputPort voicePort = null; - PassThrough fanout = new PassThrough(); - for (UnitVoice voice : voices) { - voicePort = (UnitInputPort) voice.getUnitGenerator().getPortByName(portName); - fanout.output.connect(voicePort); - } - if (voicePort != null) { - addPort(fanout.input, portName); - fanout.input.setup(voicePort); - } - } - - @Override - public UnitOutputPort getOutput() { - return mixer.output; - } - - @Override - public void usePreset(int presetIndex) { - usePreset(presetIndex, getSynthesisEngine().createTimeStamp()); - } - - // FIXME - no timestamp on UnitVoice - @Override - public void usePreset(int presetIndex, TimeStamp timeStamp) { - // Apply preset to all voices. - for (UnitVoice voice : voices) { - voice.usePreset(presetIndex); - } - // Then copy values from first voice to instrument. - for (UnitPort port : voices[0].getUnitGenerator().getPorts()) { - if (port instanceof UnitInputPort) { - UnitInputPort inputPort = (UnitInputPort) port; - // FIXME Need better way to identify ports that are per note. - UnitInputPort fanPort = (UnitInputPort) getPortByName(inputPort.getName()); - if ((fanPort != null) && (fanPort != amplitude)) { - fanPort.set(inputPort.get()); - } - } - } - } - - @Override - public void noteOn(int tag, double frequency, double amplitude, TimeStamp timeStamp) { - voiceAllocator.noteOn(tag, frequency, amplitude, timeStamp); - } - - @Override - public void noteOff(int tag, TimeStamp timeStamp) { - voiceAllocator.noteOff(tag, timeStamp); - } - - @Override - public void setPort(int tag, String portName, double value, TimeStamp timeStamp) { - voiceAllocator.setPort(tag, portName, value, timeStamp); - } - - @Override - public void allNotesOff(TimeStamp timeStamp) { - voiceAllocator.allNotesOff(timeStamp); - } - - public synchronized boolean isOn(int tag) { - return voiceAllocator.isOn(tag); - } -} diff --git a/src/com/jsyn/util/PseudoRandom.java b/src/com/jsyn/util/PseudoRandom.java deleted file mode 100644 index e92b669..0000000 --- a/src/com/jsyn/util/PseudoRandom.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2009 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. - */ -/** - * Sep 9, 2009 - * com.jsyn.engine.units.SynthRandom.java - */ - -package com.jsyn.util; - -import java.util.Random; - -/** - * Pseudo-random numbers using predictable and fast linear-congruential method. - * - * @author Phil Burk (C) 2009 Mobileer Inc Translated from 'C' to Java by Lisa - * Tolentino. - */ -public class PseudoRandom { - // We must shift 1L or else we get a negative number! - private static final double INT_TO_DOUBLE = (1.0 / (1L << 31)); - private long seed = 99887766; - - /** - * Create an instance of SynthRandom. - */ - public PseudoRandom() { - this(new Random().nextInt()); - } - - /** - * Create an instance of PseudoRandom. - */ - public PseudoRandom(int seed) { - setSeed(seed); - } - - public void setSeed(int seed) { - this.seed = (long) seed; - } - - public int getSeed() { - return (int) seed; - } - - /** - * Returns the next random double from 0.0 to 1.0 - * - * @return value from 0.0 to 1.0 - */ - public double random() { - int positiveInt = nextRandomInteger() & 0x7FFFFFFF; - return positiveInt * INT_TO_DOUBLE; - } - - /** - * Returns the next random double from -1.0 to 1.0 - * - * @return value from -1.0 to 1.0 - */ - public double nextRandomDouble() { - return nextRandomInteger() * INT_TO_DOUBLE; - } - - /** Calculate random 32 bit number using linear-congruential method. */ - public int nextRandomInteger() { - // Use values for 64-bit sequence from MMIX by Donald Knuth. - seed = (seed * 6364136223846793005L) + 1442695040888963407L; - return (int) (seed >> 32); // The higher bits have a longer sequence. - } - - public int choose(int range) { - long positiveInt = nextRandomInteger() & 0x7FFFFFFF; - long temp = positiveInt * range; - return (int) (temp >> 31); - } -} diff --git a/src/com/jsyn/util/RecursiveSequenceGenerator.java b/src/com/jsyn/util/RecursiveSequenceGenerator.java deleted file mode 100644 index 53dbdf9..0000000 --- a/src/com/jsyn/util/RecursiveSequenceGenerator.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * 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.util; - -import java.util.Random; - -/** - * Generate a sequence of integers based on a recursive mining of previous material. Notes are - * generated by one of the following formula: - * - * <pre> - * <code> - * value[n] = value[n-delay] + offset; - * </code> - * </pre> - * - * The parameters delay and offset are randomly generated. This algorithm was first developed in - * 1977 for a class project in FORTRAN. It was ported to Forth for HMSL in the late 80's. It was - * then ported to Java for JSyn in 1997. - * - * @author Phil Burk (C) 1997,2011 Mobileer Inc - */ -public class RecursiveSequenceGenerator { - private int delay = 1; - private int maxValue; - private int maxInterval; - private double desiredDensity = 0.5; - - private int offset; - private int values[]; - private boolean enables[]; - private int cursor; - private int countdown = -1; - private double actualDensity; - private int beatsPerMeasure = 8; - private Random random; - - public RecursiveSequenceGenerator() { - this(25, 7, 64); - } - - public RecursiveSequenceGenerator(int maxValue, int maxInterval, int arraySize) { - values = new int[arraySize]; - enables = new boolean[arraySize]; - this.maxValue = maxValue; - this.maxInterval = maxInterval; - for (int i = 0; i < values.length; i++) { - values[i] = maxValue / 2; - enables[i] = isNextEnabled(false); - } - } - - /** Set density of notes. 0.0 to 1.0 */ - public void setDensity(double density) { - desiredDensity = density; - } - - public double getDensity() { - return desiredDensity; - } - - /** Set maximum for generated value. */ - public void setMaxValue(int maxValue) { - this.maxValue = maxValue; - } - - public int getMaxValue() { - return maxValue; - } - - /** Set maximum for generated value. */ - public void setMaxInterval(int maxInterval) { - this.maxInterval = maxInterval; - } - - public int getMaxInterval() { - return maxInterval; - } - - /* Determine whether next in sequence should occur. */ - public boolean isNextEnabled(boolean preferance) { - /* Calculate note density using low pass IIR filter. */ - double newDensity = (actualDensity * 0.9) + (preferance ? 0.1 : 0.0); - /* Invert enable to push density towards desired level, with hysteresis. */ - if (preferance && (newDensity > ((desiredDensity * 0.7) + 0.3))) - preferance = false; - else if (!preferance && (newDensity < (desiredDensity * 0.7))) - preferance = true; - actualDensity = (actualDensity * 0.9) + (preferance ? 0.1 : 0.0); - return preferance; - } - - public int randomPowerOf2(int maxExp) { - return (1 << (int) (random.nextDouble() * (maxExp + 1))); - } - - /** Random number evenly distributed from -maxInterval to +maxInterval */ - public int randomEvenInterval() { - return (int) (random.nextDouble() * ((maxInterval * 2) + 1)) - maxInterval; - } - - void calcNewOffset() { - offset = randomEvenInterval(); - } - - public void randomize() { - - delay = randomPowerOf2(4); - calcNewOffset(); - // System.out.println("NewSeq: delay = " + delay + ", offset = " + - // offset ); - } - - /** Change parameters based on random countdown. */ - public int next() { - // If this sequence is finished, start a new one. - if (countdown-- < 0) { - randomize(); - countdown = randomPowerOf2(3); - } - return nextValue(); - } - - /** Change parameters using a probability based on beatIndex. */ - public int next(int beatIndex) { - int beatMod = beatIndex % beatsPerMeasure; - switch (beatMod) { - case 0: - if (Math.random() < 0.90) - randomize(); - break; - case 2: - case 6: - if (Math.random() < 0.15) - randomize(); - break; - case 4: - if (Math.random() < 0.30) - randomize(); - break; - default: - if (Math.random() < 0.07) - randomize(); - break; - } - return nextValue(); - } - - /** Generate nextValue based on current delay and offset */ - public int nextValue() { - // Generate index into circular value buffer. - int idx = (cursor - delay); - if (idx < 0) - idx += values.length; - - // Generate new value. Calculate new offset if too high or low. - int nextVal = 0; - int timeout = 100; - while (timeout > 0) { - nextVal = values[idx] + offset; - if ((nextVal >= 0) && (nextVal < maxValue)) - break; - // Prevent endless loops when maxValue changes. - if (nextVal > (maxValue + maxInterval - 1)) { - nextVal = maxValue; - break; - } - calcNewOffset(); - timeout--; - // System.out.println("NextVal = " + nextVal + ", offset = " + - // offset ); - } - if (timeout <= 0) { - System.err.println("RecursiveSequence: nextValue timed out. offset = " + offset); - nextVal = maxValue / 2; - offset = 0; - } - - // Save new value in circular buffer. - values[cursor] = nextVal; - - boolean playIt = enables[cursor] = isNextEnabled(enables[idx]); - cursor++; - if (cursor >= values.length) - cursor = 0; - - // System.out.println("nextVal = " + nextVal ); - - return playIt ? nextVal : -1; - } - - public Random getRandom() { - return random; - } - - public void setRandom(Random random) { - this.random = random; - } - -} diff --git a/src/com/jsyn/util/SampleLoader.java b/src/com/jsyn/util/SampleLoader.java deleted file mode 100644 index 170b4cb..0000000 --- a/src/com/jsyn/util/SampleLoader.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.util; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import com.jsyn.data.FloatSample; -import com.jsyn.util.soundfile.CustomSampleLoader; - -/** - * Load a FloatSample from various sources. The default loader uses custom code to load WAV or AIF - * files. Supported data formats are 16, 24 and 32 bit PCM, and 32-bit float. Compressed formats - * such as unsigned 8-bit, uLaw, A-Law and MP3 are not support. If you need to load one of those - * files try setJavaSoundPreferred(true). Or convert it to a supported format using Audacity or Sox - * or some other sample file tool. Here is an example of loading a sample from a file. - * - * <pre> - * <code> - * File sampleFile = new File("guitar.wav"); - * FloatSample sample = SampleLoader.loadFloatSample( sampleFile ); - * </code> - * </pre> - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class SampleLoader { - private static boolean javaSoundPreferred = false; - private static final String JS_LOADER_NAME = "com.jsyn.util.JavaSoundSampleLoader"; - - /** - * Try to create an implementation of AudioSampleLoader. - * - * @return A device supported on this platform. - */ - private static AudioSampleLoader createLoader() { - AudioSampleLoader loader = null; - try { - if (javaSoundPreferred) { - loader = (AudioSampleLoader) JavaTools.loadClass(JS_LOADER_NAME).newInstance(); - } else { - loader = new CustomSampleLoader(); - } - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return loader; - } - - /** - * Load a FloatSample from a File object. - */ - public static FloatSample loadFloatSample(File fileIn) throws IOException { - AudioSampleLoader loader = SampleLoader.createLoader(); - return loader.loadFloatSample(fileIn); - } - - /** - * Load a FloatSample from an InputStream. This is handy when loading Resources from a JAR file. - */ - public static FloatSample loadFloatSample(InputStream inputStream) throws IOException { - AudioSampleLoader loader = SampleLoader.createLoader(); - return loader.loadFloatSample(inputStream); - } - - /** - * Load a FloatSample from a URL.. This is handy when loading Resources from a website. - */ - public static FloatSample loadFloatSample(URL url) throws IOException { - AudioSampleLoader loader = SampleLoader.createLoader(); - return loader.loadFloatSample(url); - } - - public static boolean isJavaSoundPreferred() { - return javaSoundPreferred; - } - - /** - * If set true then the audio file parser from JavaSound will be used. Note that JavaSound - * cannot load audio files containing floating point data. But it may be able to load some - * compressed data formats such as uLaw. - * - * Note: JavaSound is not supported on Android. - * - * @param javaSoundPreferred - */ - public static void setJavaSoundPreferred(boolean javaSoundPreferred) { - SampleLoader.javaSoundPreferred = javaSoundPreferred; - } - - /** - * Decode 24 bit samples from a BigEndian byte array into a float array. The samples will be - * normalized into the range -1.0 to +1.0. - * - * @param audioBytes raw data from an audio file - * @param offset first element of byte array - * @param numBytes number of bytes to process - * @param data array to be filled with floats - * @param outputOffset first element of float array to be filled - */ - public static void decodeBigI24ToF32(byte[] audioBytes, int offset, int numBytes, float[] data, - int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int hi = ((audioBytes[byteCursor++]) & 0x00FF); - int mid = ((audioBytes[byteCursor++]) & 0x00FF); - int lo = ((audioBytes[byteCursor++]) & 0x00FF); - int value = (hi << 24) | (mid << 16) | (lo << 8); - data[floatCursor++] = value * (1.0f / Integer.MAX_VALUE); - } - } - - public static void decodeBigI16ToF32(byte[] audioBytes, int offset, int numBytes, float[] data, - int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int hi = ((audioBytes[byteCursor++]) & 0x00FF); - int lo = ((audioBytes[byteCursor++]) & 0x00FF); - short value = (short) ((hi << 8) | lo); - data[floatCursor++] = value * (1.0f / 32768); - } - } - - public static void decodeBigF32ToF32(byte[] audioBytes, int offset, int numBytes, float[] data, - int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int bits = audioBytes[byteCursor++]; - bits = (bits << 8) | ((audioBytes[byteCursor++]) & 0x00FF); - bits = (bits << 8) | ((audioBytes[byteCursor++]) & 0x00FF); - bits = (bits << 8) | ((audioBytes[byteCursor++]) & 0x00FF); - data[floatCursor++] = Float.intBitsToFloat(bits); - } - } - - public static void decodeBigI32ToF32(byte[] audioBytes, int offset, int numBytes, float[] data, - int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int value = audioBytes[byteCursor++]; // MSB - value = (value << 8) | ((audioBytes[byteCursor++]) & 0x00FF); - value = (value << 8) | ((audioBytes[byteCursor++]) & 0x00FF); - value = (value << 8) | ((audioBytes[byteCursor++]) & 0x00FF); - data[floatCursor++] = value * (1.0f / Integer.MAX_VALUE); - } - } - - public static void decodeLittleF32ToF32(byte[] audioBytes, int offset, int numBytes, - float[] data, int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int bits = ((audioBytes[byteCursor++]) & 0x00FF); // LSB - bits += ((audioBytes[byteCursor++]) & 0x00FF) << 8; - bits += ((audioBytes[byteCursor++]) & 0x00FF) << 16; - bits += (audioBytes[byteCursor++]) << 24; - data[floatCursor++] = Float.intBitsToFloat(bits); - } - } - - public static void decodeLittleI32ToF32(byte[] audioBytes, int offset, int numBytes, - float[] data, int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int value = ((audioBytes[byteCursor++]) & 0x00FF); - value += ((audioBytes[byteCursor++]) & 0x00FF) << 8; - value += ((audioBytes[byteCursor++]) & 0x00FF) << 16; - value += (audioBytes[byteCursor++]) << 24; - data[floatCursor++] = value * (1.0f / Integer.MAX_VALUE); - } - } - - public static void decodeLittleI24ToF32(byte[] audioBytes, int offset, int numBytes, - float[] data, int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int lo = ((audioBytes[byteCursor++]) & 0x00FF); - int mid = ((audioBytes[byteCursor++]) & 0x00FF); - int hi = ((audioBytes[byteCursor++]) & 0x00FF); - int value = (hi << 24) | (mid << 16) | (lo << 8); - data[floatCursor++] = value * (1.0f / Integer.MAX_VALUE); - } - } - - public static void decodeLittleI16ToF32(byte[] audioBytes, int offset, int numBytes, - float[] data, int outputOffset) { - int lastByte = offset + numBytes; - int byteCursor = offset; - int floatCursor = outputOffset; - while (byteCursor < lastByte) { - int lo = ((audioBytes[byteCursor++]) & 0x00FF); - int hi = ((audioBytes[byteCursor++]) & 0x00FF); - short value = (short) ((hi << 8) | lo); - float sample = value * (1.0f / 32768); - data[floatCursor++] = sample; - } - } - -} diff --git a/src/com/jsyn/util/SignalCorrelator.java b/src/com/jsyn/util/SignalCorrelator.java deleted file mode 100644 index ebdd46b..0000000 --- a/src/com/jsyn/util/SignalCorrelator.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.util; - -/** - * Interface used to evaluate various algorithms for pitch detection. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public interface SignalCorrelator { - /** - * Add a sample to be analyzed. The samples will generally be held in a circular buffer. - * - * @param value - * @return true if a new period value has been generated - */ - public boolean addSample(double value); - - /** - * @return the estimated period of the waveform in samples - */ - public double getPeriod(); - - /** - * Measure of how confident the analyzer is of the last result. - * - * @return quality of the estimate between 0.0 and 1.0 - */ - public double getConfidence(); - - /** For internal debugging. */ - public float[] getDiffs(); - -} diff --git a/src/com/jsyn/util/StreamingThread.java b/src/com/jsyn/util/StreamingThread.java deleted file mode 100644 index 682f476..0000000 --- a/src/com/jsyn/util/StreamingThread.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.util; - -import java.io.IOException; - -import com.jsyn.io.AudioInputStream; -import com.jsyn.io.AudioOutputStream; - -/** - * Read from an AudioInputStream and write to an AudioOutputStream as a background thread. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class StreamingThread extends Thread { - private AudioInputStream inputStream; - private AudioOutputStream outputStream; - private int framesPerBuffer = 1024; - private volatile boolean go = true; - private TransportModel transportModel; - private long framePosition; - private long maxFrames; - private int samplesPerFrame = 1; - - public StreamingThread(AudioInputStream inputStream, AudioOutputStream outputStream) { - this.inputStream = inputStream; - this.outputStream = outputStream; - } - - @Override - public void run() { - double[] buffer = new double[framesPerBuffer * samplesPerFrame]; - try { - transportModel.firePositionChanged(framePosition); - transportModel.fireStateChanged(TransportModel.STATE_RUNNING); - int framesToRead = geteFramesToRead(buffer); - while (go && (framesToRead > 0)) { - int samplesToRead = framesToRead * samplesPerFrame; - while (samplesToRead > 0) { - int samplesRead = inputStream.read(buffer, 0, samplesToRead); - outputStream.write(buffer, 0, samplesRead); - samplesToRead -= samplesRead; - } - framePosition += framesToRead; - transportModel.firePositionChanged(framePosition); - framesToRead = geteFramesToRead(buffer); - } - transportModel.fireStateChanged(TransportModel.STATE_STOPPED); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private int geteFramesToRead(double[] buffer) { - if (maxFrames > 0) { - long numToRead = maxFrames - framePosition; - if (numToRead < 0) { - return 0; - } else if (numToRead > framesPerBuffer) { - numToRead = framesPerBuffer; - } - return (int) numToRead; - } else { - return framesPerBuffer; - } - } - - public int getFramesPerBuffer() { - return framesPerBuffer; - } - - /** - * Only call this before the thread has started. - * - * @param framesPerBuffer - */ - public void setFramesPerBuffer(int framesPerBuffer) { - this.framesPerBuffer = framesPerBuffer; - } - - public void requestStop() { - go = false; - } - - public TransportModel getTransportModel() { - return transportModel; - } - - public void setTransportModel(TransportModel transportModel) { - this.transportModel = transportModel; - } - - /** - * @param maxFrames - */ - public void setMaxFrames(long maxFrames) { - this.maxFrames = maxFrames; - } - - public int getSamplesPerFrame() { - return samplesPerFrame; - } - - public void setSamplesPerFrame(int samplesPerFrame) { - this.samplesPerFrame = samplesPerFrame; - } -} diff --git a/src/com/jsyn/util/TransportListener.java b/src/com/jsyn/util/TransportListener.java deleted file mode 100644 index 3c8b048..0000000 --- a/src/com/jsyn/util/TransportListener.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2009 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.util; - -public interface TransportListener { - /** - * @param transportModel - * @param framePosition position in frames - */ - void positionChanged(TransportModel transportModel, long framePosition); - - /** - * @param transportModel - * @param state for example TransportModel.STATE_STOPPED - */ - void stateChanged(TransportModel transportModel, int state); -} diff --git a/src/com/jsyn/util/TransportModel.java b/src/com/jsyn/util/TransportModel.java deleted file mode 100644 index bcc75be..0000000 --- a/src/com/jsyn/util/TransportModel.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2009 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.util; - -import java.util.concurrent.CopyOnWriteArrayList; - -public class TransportModel { - public static final int STATE_STOPPED = 0; - public static final int STATE_PAUSED = 1; - public static final int STATE_RUNNING = 2; - - private CopyOnWriteArrayList<TransportListener> listeners = new CopyOnWriteArrayList<TransportListener>(); - private int state = STATE_STOPPED; - private long position; - - public void addTransportListener(TransportListener listener) { - listeners.add(listener); - } - - public void removeTransportListener(TransportListener listener) { - listeners.remove(listener); - } - - public void setState(int newState) { - state = newState; - fireStateChanged(newState); - } - - public int getState() { - return state; - } - - public void setPosition(long newPosition) { - position = newPosition; - firePositionChanged(newPosition); - } - - public long getPosition() { - return position; - } - - public void fireStateChanged(int newState) { - for (TransportListener listener : listeners) { - listener.stateChanged(this, newState); - } - } - - public void firePositionChanged(long newPosition) { - for (TransportListener listener : listeners) { - listener.positionChanged(this, newPosition); - } - } -} diff --git a/src/com/jsyn/util/VoiceAllocator.java b/src/com/jsyn/util/VoiceAllocator.java deleted file mode 100644 index f20f7a5..0000000 --- a/src/com/jsyn/util/VoiceAllocator.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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.util; - -import com.jsyn.Synthesizer; -import com.jsyn.unitgen.UnitVoice; -import com.softsynth.shared.time.ScheduledCommand; -import com.softsynth.shared.time.TimeStamp; - -/** - * Allocate voices based on an integer tag. The tag could, for example, be a MIDI note number. Or a - * tag could be an int that always increments. Use the same tag to refer to a voice for noteOn() and - * noteOff(). If no new voices are available then a voice in use will be stolen. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class VoiceAllocator implements Instrument { - private int maxVoices; - private VoiceTracker[] trackers; - private long tick; - private Synthesizer synthesizer; - private static final int UNASSIGNED_PRESET = -1; - private int mPresetIndex = UNASSIGNED_PRESET; - - /** - * Create an allocator for the array of UnitVoices. The array must be full of instantiated - * UnitVoices that are connected to some kind of mixer. - * - * @param voices - */ - public VoiceAllocator(UnitVoice[] voices) { - maxVoices = voices.length; - trackers = new VoiceTracker[maxVoices]; - for (int i = 0; i < maxVoices; i++) { - trackers[i] = new VoiceTracker(); - trackers[i].voice = voices[i]; - } - } - - public Synthesizer getSynthesizer() { - if (synthesizer == null) { - synthesizer = trackers[0].voice.getUnitGenerator().getSynthesizer(); - } - return synthesizer; - } - - private class VoiceTracker { - UnitVoice voice; - int tag = -1; - int presetIndex = UNASSIGNED_PRESET; - long when; - boolean on; - - public void off() { - on = false; - when = tick++; - } - } - - /** - * @return number of UnitVoices passed to the allocator. - */ - public int getVoiceCount() { - return maxVoices; - } - - private VoiceTracker findVoice(int tag) { - for (VoiceTracker tracker : trackers) { - if (tracker.tag == tag) { - return tracker; - } - } - return null; - } - - private VoiceTracker stealVoice() { - VoiceTracker bestOff = null; - VoiceTracker bestOn = null; - for (VoiceTracker tracker : trackers) { - if (tracker.voice == null) { - return tracker; - } - // If we have a bestOff voice then don't even bother with on voices. - else if (bestOff != null) { - // Older off voice? - if (!tracker.on && (tracker.when < bestOff.when)) { - bestOff = tracker; - } - } else if (tracker.on) { - if (bestOn == null) { - bestOn = tracker; - } else if (tracker.when < bestOn.when) { - bestOn = tracker; - } - } else { - bestOff = tracker; - } - } - if (bestOff != null) { - return bestOff; - } else { - return bestOn; - } - } - - /** - * Allocate a Voice associated with this tag. It will first pick a voice already assigned to - * that tag. Next it will pick the oldest voice that is off. Next it will pick the oldest voice - * that is on. If you are using timestamps to play the voice in the future then you should use - * the noteOn() noteOff() and setPort() methods. - * - * @param tag - * @return Voice that is most available. - */ - protected synchronized UnitVoice allocate(int tag) { - VoiceTracker tracker = allocateTracker(tag); - return tracker.voice; - } - - private VoiceTracker allocateTracker(int tag) { - VoiceTracker tracker = findVoice(tag); - if (tracker == null) { - tracker = stealVoice(); - } - tracker.tag = tag; - tracker.when = tick++; - tracker.on = true; - return tracker; - } - - protected synchronized boolean isOn(int tag) { - VoiceTracker tracker = findVoice(tag); - if (tracker != null) { - return tracker.on; - } - return false; - } - - protected synchronized UnitVoice off(int tag) { - VoiceTracker tracker = findVoice(tag); - if (tracker != null) { - tracker.off(); - return tracker.voice; - } - return null; - } - - /** Turn off all the note currently on. */ - @Override - public void allNotesOff(TimeStamp timeStamp) { - getSynthesizer().scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - for (VoiceTracker tracker : trackers) { - if (tracker.on) { - tracker.voice.noteOff(getSynthesizer().createTimeStamp()); - tracker.off(); - } - } - } - }); - } - - /** - * Play a note on the voice and associate it with the given tag. if needed a new voice will be - * allocated and an old voice may be turned off. - */ - @Override - public void noteOn(final int tag, final double frequency, final double amplitude, - TimeStamp timeStamp) { - getSynthesizer().scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - VoiceTracker voiceTracker = allocateTracker(tag); - if (voiceTracker.presetIndex != mPresetIndex) { - voiceTracker.voice.usePreset(mPresetIndex); - voiceTracker.presetIndex = mPresetIndex; - } - voiceTracker.voice.noteOn(frequency, amplitude, getSynthesizer().createTimeStamp()); - } - }); - } - - /** - * Play a note on the voice and associate it with the given tag. if needed a new voice will be - * allocated and an old voice may be turned off. - * Apply an operation to the voice. - */ - public void noteOn(final int tag, - final double frequency, - final double amplitude, - final VoiceOperation operation, - TimeStamp timeStamp) { - getSynthesizer().scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - VoiceTracker voiceTracker = allocateTracker(tag); - operation.operate(voiceTracker.voice); - voiceTracker.voice.noteOn(frequency, amplitude, getSynthesizer().createTimeStamp()); - } - }); - } - - /** Turn off the voice associated with the given tag if allocated. */ - @Override - public void noteOff(final int tag, TimeStamp timeStamp) { - getSynthesizer().scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - VoiceTracker voiceTracker = findVoice(tag); - if (voiceTracker != null) { - voiceTracker.voice.noteOff(getSynthesizer().createTimeStamp()); - off(tag); - } - } - }); - } - - /** Set a port on the voice associated with the given tag if allocated. */ - @Override - public void setPort(final int tag, final String portName, final double value, - TimeStamp timeStamp) { - getSynthesizer().scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - VoiceTracker voiceTracker = findVoice(tag); - if (voiceTracker != null) { - voiceTracker.voice.setPort(portName, value, getSynthesizer().createTimeStamp()); - } - } - }); - } - - @Override - public void usePreset(final int presetIndex, TimeStamp timeStamp) { - getSynthesizer().scheduleCommand(timeStamp, new ScheduledCommand() { - @Override - public void run() { - mPresetIndex = presetIndex; - } - }); - } - -} diff --git a/src/com/jsyn/util/VoiceDescription.java b/src/com/jsyn/util/VoiceDescription.java deleted file mode 100644 index b7be044..0000000 --- a/src/com/jsyn/util/VoiceDescription.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.util; - -import com.jsyn.unitgen.UnitVoice; - -/** - * Describe a voice so that a user can pick it out of an InstrumentLibrary. - * - * @author Phil Burk (C) 2011 Mobileer Inc - * @see PolyphonicInstrument - */ -public abstract class VoiceDescription { - private String name; - private String[] presetNames; - - public VoiceDescription(String name, String[] presetNames) { - this.name = name; - this.presetNames = presetNames; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getPresetCount() { - return presetNames.length; - } - - public String[] getPresetNames() { - return presetNames; - } - - public abstract String[] getTags(int presetIndex); - - /** - * Instantiate one of these voices. You may want to call usePreset(n) on the voice after - * instantiating it. - * - * @return a voice - */ - public abstract UnitVoice createUnitVoice(); - - public abstract String getVoiceClassName(); - - @Override - public String toString() { - return name + "[" + getPresetCount() + "]"; - } -} diff --git a/src/com/jsyn/util/VoiceOperation.java b/src/com/jsyn/util/VoiceOperation.java deleted file mode 100644 index cd3b48e..0000000 --- a/src/com/jsyn/util/VoiceOperation.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.jsyn.util; - -import com.jsyn.unitgen.UnitVoice; - -public interface VoiceOperation { - public void operate(UnitVoice voice); -} diff --git a/src/com/jsyn/util/WaveFileWriter.java b/src/com/jsyn/util/WaveFileWriter.java deleted file mode 100644 index 32e9995..0000000 --- a/src/com/jsyn/util/WaveFileWriter.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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.util; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.RandomAccessFile; - -import com.jsyn.io.AudioOutputStream; - -/** - * Write audio data to a WAV file. - * - * <pre> - * <code> - * WaveFileWriter writer = new WaveFileWriter(file); - * writer.setFrameRate(22050); - * writer.setBitsPerSample(24); - * writer.write(floatArray); - * writer.close(); - * </code> - * </pre> - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class WaveFileWriter implements AudioOutputStream { - private static final short WAVE_FORMAT_PCM = 1; - private OutputStream outputStream; - private long riffSizePosition = 0; - private long dataSizePosition = 0; - private int frameRate = 44100; - private int samplesPerFrame = 1; - private int bitsPerSample = 16; - private int bytesWritten; - private File outputFile; - private boolean headerWritten = false; - private final static int PCM24_MIN = -(1 << 23); - private final static int PCM24_MAX = (1 << 23) - 1; - - /** - * Create a writer that will write to the specified file. - * - * @param outputFile - * @throws FileNotFoundException - */ - public WaveFileWriter(File outputFile) throws FileNotFoundException { - this.outputFile = outputFile; - FileOutputStream fileOut = new FileOutputStream(outputFile); - outputStream = new BufferedOutputStream(fileOut); - } - - /** - * @param frameRate default is 44100 - */ - public void setFrameRate(int frameRate) { - this.frameRate = frameRate; - } - - public int getFrameRate() { - return frameRate; - } - - /** For stereo, set this to 2. Default is 1. */ - public void setSamplesPerFrame(int samplesPerFrame) { - this.samplesPerFrame = samplesPerFrame; - } - - public int getSamplesPerFrame() { - return samplesPerFrame; - } - - /** Only 16 or 24 bit samples supported at the moment. Default is 16. */ - public void setBitsPerSample(int bits) { - if ((bits != 16) && (bits != 24)) { - throw new IllegalArgumentException("Only 16 or 24 bits per sample allowed. Not " + bits); - } - bitsPerSample = bits; - } - - public int getBitsPerSample() { - return bitsPerSample; - } - - @Override - public void close() throws IOException { - outputStream.close(); - fixSizes(); - } - - /** Write entire buffer of audio samples to the WAV file. */ - @Override - public void write(double[] buffer) throws IOException { - write(buffer, 0, buffer.length); - } - - /** Write audio to the WAV file. */ - public void write(float[] buffer) throws IOException { - write(buffer, 0, buffer.length); - } - - /** Write single audio data value to the WAV file. */ - @Override - public void write(double value) throws IOException { - if (!headerWritten) { - writeHeader(); - } - - if (bitsPerSample == 24) { - writePCM24(value); - } else { - writePCM16(value); - } - } - - private void writePCM24(double value) throws IOException { - // Offset before casting so that we can avoid using floor(). - // Also round by adding 0.5 so that very small signals go to zero. - double temp = (PCM24_MAX * value) + 0.5 - PCM24_MIN; - int sample = ((int) temp) + PCM24_MIN; - // clip to 24-bit range - if (sample > PCM24_MAX) { - sample = PCM24_MAX; - } else if (sample < PCM24_MIN) { - sample = PCM24_MIN; - } - // encode as little-endian - writeByte(sample); // little end - writeByte(sample >> 8); // middle - writeByte(sample >> 16); // big end - } - - private void writePCM16(double value) throws IOException { - // Offset before casting so that we can avoid using floor(). - // Also round by adding 0.5 so that very small signals go to zero. - double temp = (Short.MAX_VALUE * value) + 0.5 - Short.MIN_VALUE; - int sample = ((int) temp) + Short.MIN_VALUE; - if (sample > Short.MAX_VALUE) { - sample = Short.MAX_VALUE; - } else if (sample < Short.MIN_VALUE) { - sample = Short.MIN_VALUE; - } - writeByte(sample); // little end - writeByte(sample >> 8); // big end - } - - /** Write audio to the WAV file. */ - @Override - public void write(double[] buffer, int start, int count) throws IOException { - for (int i = 0; i < count; i++) { - write(buffer[start + i]); - } - } - - /** Write audio to the WAV file. */ - public void write(float[] buffer, int start, int count) throws IOException { - for (int i = 0; i < count; i++) { - write(buffer[start + i]); - } - } - - // Write lower 8 bits. Upper bits ignored. - private void writeByte(int b) throws IOException { - outputStream.write(b); - bytesWritten += 1; - } - - /** - * Write a 32 bit integer to the stream in Little Endian format. - */ - public void writeIntLittle(int n) throws IOException { - writeByte(n); - writeByte(n >> 8); - writeByte(n >> 16); - writeByte(n >> 24); - } - - /** - * Write a 16 bit integer to the stream in Little Endian format. - */ - public void writeShortLittle(short n) throws IOException { - writeByte(n); - writeByte(n >> 8); - } - - /** - * Write a simple WAV header for PCM data. - */ - private void writeHeader() throws IOException { - writeRiffHeader(); - writeFormatChunk(); - writeDataChunkHeader(); - outputStream.flush(); - headerWritten = true; - } - - /** - * Write a 'RIFF' file header and a 'WAVE' ID to the WAV file. - */ - private void writeRiffHeader() throws IOException { - writeByte('R'); - writeByte('I'); - writeByte('F'); - writeByte('F'); - riffSizePosition = bytesWritten; - writeIntLittle(Integer.MAX_VALUE); - writeByte('W'); - writeByte('A'); - writeByte('V'); - writeByte('E'); - } - - /** - * Write an 'fmt ' chunk to the WAV file containing the given information. - */ - public void writeFormatChunk() throws IOException { - int bytesPerSample = (bitsPerSample + 7) / 8; - - writeByte('f'); - writeByte('m'); - writeByte('t'); - writeByte(' '); - writeIntLittle(16); // chunk size - writeShortLittle(WAVE_FORMAT_PCM); - writeShortLittle((short) samplesPerFrame); - writeIntLittle(frameRate); - // bytes/second - writeIntLittle(frameRate * samplesPerFrame * bytesPerSample); - // block align - writeShortLittle((short) (samplesPerFrame * bytesPerSample)); - writeShortLittle((short) bitsPerSample); - } - - /** - * Write a 'data' chunk header to the WAV file. This should be followed by call to - * writeShortLittle() to write the data to the chunk. - */ - public void writeDataChunkHeader() throws IOException { - writeByte('d'); - writeByte('a'); - writeByte('t'); - writeByte('a'); - dataSizePosition = bytesWritten; - writeIntLittle(Integer.MAX_VALUE); // size - } - - /** - * Fix RIFF and data chunk sizes based on final size. Assume data chunk is the last chunk. - */ - private void fixSizes() throws IOException { - RandomAccessFile randomFile = new RandomAccessFile(outputFile, "rw"); - try { - // adjust RIFF size - long end = bytesWritten; - int riffSize = (int) (end - riffSizePosition) - 4; - randomFile.seek(riffSizePosition); - writeRandomIntLittle(randomFile, riffSize); - // adjust data size - int dataSize = (int) (end - dataSizePosition) - 4; - randomFile.seek(dataSizePosition); - writeRandomIntLittle(randomFile, dataSize); - } finally { - randomFile.close(); - } - } - - private void writeRandomIntLittle(RandomAccessFile randomFile, int n) throws IOException { - byte[] buffer = new byte[4]; - buffer[0] = (byte) n; - buffer[1] = (byte) (n >> 8); - buffer[2] = (byte) (n >> 16); - buffer[3] = (byte) (n >> 24); - randomFile.write(buffer); - } - -} diff --git a/src/com/jsyn/util/WaveRecorder.java b/src/com/jsyn/util/WaveRecorder.java deleted file mode 100644 index 059863b..0000000 --- a/src/com/jsyn/util/WaveRecorder.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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.util; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; - -import com.jsyn.Synthesizer; -import com.jsyn.ports.UnitInputPort; - -/** - * Connect a unit generator to the input. Then start() recording. The signal will be written to a - * WAV format file that can be read by other programs. - * - * @author Phil Burk (C) 2011 Mobileer Inc - */ -public class WaveRecorder { - private AudioStreamReader reader; - private WaveFileWriter writer; - private StreamingThread thread; - private Synthesizer synth; - private TransportModel transportModel = new TransportModel(); - private double maxRecordingTime; - - /** - * Create a stereo 16-bit recorder. - * - * @param synth - * @param outputFile - * @throws FileNotFoundException - */ - public WaveRecorder(Synthesizer synth, File outputFile) throws FileNotFoundException { - this(synth, outputFile, 2, 16); - } - - public WaveRecorder(Synthesizer synth, File outputFile, int samplesPerFrame) - throws FileNotFoundException { - this(synth, outputFile, samplesPerFrame, 16); - } - - /** - * @param synth - * @param outputFile - * @param samplesPerFrame 1 for mono, 2 for stereo - * @param bitsPerSample 16 or 24 - * @throws FileNotFoundException - */ - public WaveRecorder(Synthesizer synth, File outputFile, int samplesPerFrame, int bitsPerSample) - throws FileNotFoundException { - this.synth = synth; - reader = new AudioStreamReader(synth, samplesPerFrame); - - writer = new WaveFileWriter(outputFile); - writer.setFrameRate(synth.getFrameRate()); - writer.setSamplesPerFrame(samplesPerFrame); - writer.setBitsPerSample(bitsPerSample); - } - - public UnitInputPort getInput() { - return reader.getInput(); - } - - public void start() { - stop(); - thread = new StreamingThread(reader, writer); - thread.setTransportModel(transportModel); - thread.setSamplesPerFrame(writer.getSamplesPerFrame()); - updateMaxRecordingTime(); - thread.start(); - } - - public void stop() { - if (thread != null) { - thread.requestStop(); - try { - thread.join(500); - } catch (InterruptedException e) { - } - thread = null; - } - } - - /** Close and disconnect any connected inputs. */ - public void close() throws IOException { - stop(); - if (writer != null) { - writer.close(); - writer = null; - } - if (reader != null) { - reader.close(); - for (int i = 0; i < reader.getInput().getNumParts(); i++) { - reader.getInput().disconnectAll(i); - } - reader = null; - } - } - - public void addTransportListener(TransportListener listener) { - transportModel.addTransportListener(listener); - } - - public void removeTransportListener(TransportListener listener) { - transportModel.removeTransportListener(listener); - } - - public void setMaxRecordingTime(double maxRecordingTime) { - this.maxRecordingTime = maxRecordingTime; - updateMaxRecordingTime(); - } - - private void updateMaxRecordingTime() { - StreamingThread streamingThread = thread; - if (streamingThread != null) { - long maxFrames = (long) (maxRecordingTime * synth.getFrameRate()); - streamingThread.setMaxFrames(maxFrames); - } - } -} diff --git a/src/com/jsyn/util/soundfile/AIFFFileParser.java b/src/com/jsyn/util/soundfile/AIFFFileParser.java deleted file mode 100644 index 2b09d78..0000000 --- a/src/com/jsyn/util/soundfile/AIFFFileParser.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2009 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.util.soundfile; - -import java.io.EOFException; -import java.io.IOException; - -import com.jsyn.data.FloatSample; -import com.jsyn.data.SampleMarker; -import com.jsyn.util.SampleLoader; - -public class AIFFFileParser extends AudioFileParser { - private static final String SUPPORTED_FORMATS = "Only 16 and 24 bit PCM or 32-bit float AIF files supported."; - static final int AIFF_ID = ('A' << 24) | ('I' << 16) | ('F' << 8) | 'F'; - static final int AIFC_ID = ('A' << 24) | ('I' << 16) | ('F' << 8) | 'C'; - static final int COMM_ID = ('C' << 24) | ('O' << 16) | ('M' << 8) | 'M'; - static final int SSND_ID = ('S' << 24) | ('S' << 16) | ('N' << 8) | 'D'; - static final int MARK_ID = ('M' << 24) | ('A' << 16) | ('R' << 8) | 'K'; - static final int INST_ID = ('I' << 24) | ('N' << 16) | ('S' << 8) | 'T'; - static final int NONE_ID = ('N' << 24) | ('O' << 16) | ('N' << 8) | 'E'; - static final int FL32_ID = ('F' << 24) | ('L' << 16) | ('3' << 8) | '2'; - static final int FL32_ID_LC = ('f' << 24) | ('l' << 16) | ('3' << 8) | '2'; - - int sustainBeginID = -1; - int sustainEndID = -1; - int releaseBeginID = -1; - int releaseEndID = -1; - boolean typeFloat = false; - - @Override - FloatSample finish() throws IOException { - setLoops(); - - if ((byteData == null)) { - throw new IOException("No data found in audio sample."); - } - float[] floatData = new float[numFrames * samplesPerFrame]; - if (bitsPerSample == 16) { - SampleLoader.decodeBigI16ToF32(byteData, 0, byteData.length, floatData, 0); - } else if (bitsPerSample == 24) { - SampleLoader.decodeBigI24ToF32(byteData, 0, byteData.length, floatData, 0); - } else if (bitsPerSample == 32) { - if (typeFloat) { - SampleLoader.decodeBigF32ToF32(byteData, 0, byteData.length, floatData, 0); - } else { - SampleLoader.decodeBigI32ToF32(byteData, 0, byteData.length, floatData, 0); - } - } else { - throw new IOException(SUPPORTED_FORMATS + " size = " + bitsPerSample); - } - - return makeSample(floatData); - } - - double read80BitFloat() throws IOException { - /* - * This is not a full decoding of the 80 bit number but it should suffice for the range we - * expect. - */ - byte[] bytes = new byte[10]; - parser.read(bytes); - int exp = ((bytes[0] & 0x3F) << 8) | (bytes[1] & 0xFF); - int mant = ((bytes[2] & 0xFF) << 16) | ((bytes[3] & 0xFF) << 8) | (bytes[4] & 0xFF); - // System.out.println( "exp = " + exp + ", mant = " + mant ); - return mant / (double) (1 << (22 - exp)); - } - - void parseCOMMChunk(IFFParser parser, int ckSize) throws IOException { - samplesPerFrame = parser.readShortBig(); - numFrames = parser.readIntBig(); - bitsPerSample = parser.readShortBig(); - frameRate = read80BitFloat(); - if (ckSize > 18) { - int format = parser.readIntBig(); - // Validate data format. - if ((format == FL32_ID) || (format == FL32_ID_LC)) { - typeFloat = true; - } else if (format == NONE_ID) { - typeFloat = false; - } else { - throw new IOException(SUPPORTED_FORMATS + " format " + IFFParser.IDToString(format)); - } - } - - bytesPerSample = (bitsPerSample + 7) / 8; - bytesPerFrame = bytesPerSample * samplesPerFrame; - } - - /* parse tuning and multi-sample info */ - @SuppressWarnings("unused") - void parseINSTChunk(IFFParser parser, int ckSize) throws IOException { - int baseNote = parser.readByte(); - int detune = parser.readByte(); - originalPitch = baseNote + (0.01 * detune); - - int lowNote = parser.readByte(); - int highNote = parser.readByte(); - - parser.skip(2); /* lo,hi velocity */ - int gain = parser.readShortBig(); - - int playMode = parser.readShortBig(); /* sustain */ - sustainBeginID = parser.readShortBig(); - sustainEndID = parser.readShortBig(); - - playMode = parser.readShortBig(); /* release */ - releaseBeginID = parser.readShortBig(); - releaseEndID = parser.readShortBig(); - } - - private void setLoops() { - SampleMarker cuePoint = cueMap.get(sustainBeginID); - if (cuePoint != null) { - sustainBegin = cuePoint.position; - } - cuePoint = cueMap.get(sustainEndID); - if (cuePoint != null) { - sustainEnd = cuePoint.position; - } - } - - void parseSSNDChunk(IFFParser parser, int ckSize) throws IOException { - long numRead; - // System.out.println("parseSSNDChunk()"); - int offset = parser.readIntBig(); - parser.readIntBig(); /* blocksize */ - parser.skip(offset); - dataPosition = parser.getOffset(); - int numBytes = ckSize - 8 - offset; - if (ifLoadData) { - byteData = new byte[numBytes]; - numRead = parser.read(byteData); - } else { - numRead = parser.skip(numBytes); - } - if (numRead != numBytes) - throw new EOFException("AIFF data chunk too short!"); - } - - void parseMARKChunk(IFFParser parser, int ckSize) throws IOException { - long startOffset = parser.getOffset(); - int numCuePoints = parser.readShortBig(); - // System.out.println( "parseCueChunk: numCuePoints = " + numCuePoints - // ); - for (int i = 0; i < numCuePoints; i++) { - // Some AIF files have a bogus numCuePoints so check to see if we - // are at end. - long numInMark = parser.getOffset() - startOffset; - if (numInMark >= ckSize) { - System.out.println("Reached end of MARK chunk with bogus numCuePoints = " - + numCuePoints); - break; - } - - int uniqueID = parser.readShortBig(); - int position = parser.readIntBig(); - int len = parser.read(); - String markerName = parseString(parser, len); - if ((len & 1) == 0) { - parser.skip(1); /* skip pad byte */ - } - - SampleMarker cuePoint = findOrCreateCuePoint(uniqueID); - cuePoint.position = position; - cuePoint.name = markerName; - - if (IFFParser.debug) { - System.out.println("AIFF Marker at " + position + ", " + markerName); - } - } - } - - /** - * Called by parse() method to handle FORM chunks in an AIFF specific manner. - * - * @param ckID four byte chunk ID such as 'data' - * @param ckSize size of chunk in bytes - * @exception IOException If parsing fails, or IO error occurs. - */ - @Override - public void handleForm(IFFParser parser, int ckID, int ckSize, int type) throws IOException { - if ((ckID == IFFParser.FORM_ID) && (type != AIFF_ID) && (type != AIFC_ID)) - throw new IOException("Bad AIFF form type = " + IFFParser.IDToString(type)); - } - - /** - * Called by parse() method to handle chunks in an AIFF specific manner. - * - * @param ckID four byte chunk ID such as 'data' - * @param ckSize size of chunk in bytes - * @exception IOException If parsing fails, or IO error occurs. - */ - @Override - public void handleChunk(IFFParser parser, int ckID, int ckSize) throws IOException { - switch (ckID) { - case COMM_ID: - parseCOMMChunk(parser, ckSize); - break; - case SSND_ID: - parseSSNDChunk(parser, ckSize); - break; - case MARK_ID: - parseMARKChunk(parser, ckSize); - break; - case INST_ID: - parseINSTChunk(parser, ckSize); - break; - default: - break; - } - } - -} diff --git a/src/com/jsyn/util/soundfile/AudioFileParser.java b/src/com/jsyn/util/soundfile/AudioFileParser.java deleted file mode 100644 index e7bb066..0000000 --- a/src/com/jsyn/util/soundfile/AudioFileParser.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2001 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.util.soundfile; - -import java.io.IOException; -import java.util.HashMap; - -import com.jsyn.data.FloatSample; -import com.jsyn.data.SampleMarker; - -/** - * Base class for various types of audio specific file parsers. - * - * @author (C) 2001 Phil Burk, SoftSynth.com - */ - -abstract class AudioFileParser implements ChunkHandler { - IFFParser parser; - protected byte[] byteData; - boolean ifLoadData = true; /* If true, load sound data into memory. */ - long dataPosition; /* - * Number of bytes from beginning of file where sound data resides. - */ - protected int bitsPerSample; - protected int bytesPerFrame; // in the file - protected int bytesPerSample; // in the file - protected HashMap<Integer, SampleMarker> cueMap = new HashMap<Integer, SampleMarker>(); - protected short samplesPerFrame; - protected double frameRate; - protected int numFrames; - protected double originalPitch = 60.0; - protected int sustainBegin = -1; - protected int sustainEnd = -1; - - public AudioFileParser() { - } - - /** - * @return Number of bytes from beginning of stream where sound data resides. - */ - public long getDataPosition() { - return dataPosition; - } - - /** - * This can be read by another thread when load()ing a sample to determine how many bytes have - * been read so far. - */ - public synchronized long getNumBytesRead() { - IFFParser p = parser; // prevent race - if (p != null) - return p.getOffset(); - else - return 0; - } - - /** - * This can be read by another thread when load()ing a sample to determine how many bytes need - * to be read. - */ - public synchronized long getFileSize() { - IFFParser p = parser; // prevent race - if (p != null) - return p.getFileSize(); - else - return 0; - } - - protected SampleMarker findOrCreateCuePoint(int uniqueID) { - SampleMarker cuePoint = cueMap.get(uniqueID); - if (cuePoint == null) { - cuePoint = new SampleMarker(); - cueMap.put(uniqueID, cuePoint); - } - return cuePoint; - } - - public FloatSample load(IFFParser parser) throws IOException { - this.parser = parser; - parser.parseAfterHead(this); - return finish(); - } - - abstract FloatSample finish() throws IOException; - - FloatSample makeSample(float[] floatData) throws IOException { - FloatSample floatSample = new FloatSample(floatData, samplesPerFrame); - - floatSample.setChannelsPerFrame(samplesPerFrame); - floatSample.setFrameRate(frameRate); - floatSample.setPitch(originalPitch); - - if (sustainBegin >= 0) { - floatSample.setSustainBegin(sustainBegin); - floatSample.setSustainEnd(sustainEnd); - } - - for (SampleMarker marker : cueMap.values()) { - floatSample.addMarker(marker); - } - - /* Set Sustain Loop by assuming first two markers are loop points. */ - if (floatSample.getMarkerCount() >= 2) { - floatSample.setSustainBegin(floatSample.getMarker(0).position); - floatSample.setSustainEnd(floatSample.getMarker(1).position); - } - return floatSample; - } - - protected String parseString(IFFParser parser, int textLength) throws IOException { - byte[] bar = new byte[textLength]; - parser.read(bar); - return new String(bar); - } -} diff --git a/src/com/jsyn/util/soundfile/ChunkHandler.java b/src/com/jsyn/util/soundfile/ChunkHandler.java deleted file mode 100644 index 6dfe26d..0000000 --- a/src/com/jsyn/util/soundfile/ChunkHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.util.soundfile; - -import java.io.IOException; - -/** - * Handle IFF Chunks as they are parsed from an IFF or RIFF file. - * - * @see IFFParser - * @see AudioSampleAIFF - * @author (C) 1997 Phil Burk, SoftSynth.com - */ -interface ChunkHandler { - /** - * The parser will call this when it encounters a FORM or LIST chunk that contains other chunks. - * This handler can either read the form's chunks, or let the parser find them and call - * handleChunk(). - * - * @param ID a 4 byte identifier such as FORM_ID that identifies the IFF chunk type. - * @param numBytes number of bytes contained in the FORM, not counting the FORM type. - * @param type a 4 byte identifier such as AIFF_ID that identifies the FORM type. - */ - public void handleForm(IFFParser parser, int ID, int numBytes, int type) throws IOException; - - /** - * The parser will call this when it encounters a chunk that is not a FORM or LIST. This handler - * can either read the chunk's, or ignore it. The parser will skip over any unread data. Do NOT - * read past the end of the chunk! - * - * @param ID a 4 byte identifier such as SSND_ID that identifies the IFF chunk type. - * @param numBytes number of bytes contained in the chunk, not counting the ID and size field. - */ - public void handleChunk(IFFParser parser, int ID, int numBytes) throws IOException; -} diff --git a/src/com/jsyn/util/soundfile/CustomSampleLoader.java b/src/com/jsyn/util/soundfile/CustomSampleLoader.java deleted file mode 100644 index 14efde9..0000000 --- a/src/com/jsyn/util/soundfile/CustomSampleLoader.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2009 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.util.soundfile; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import com.jsyn.data.FloatSample; -import com.jsyn.util.AudioSampleLoader; - -public class CustomSampleLoader implements AudioSampleLoader { - - @Override - public FloatSample loadFloatSample(File fileIn) throws IOException { - FileInputStream fileStream = new FileInputStream(fileIn); - BufferedInputStream inputStream = new BufferedInputStream(fileStream); - return loadFloatSample(inputStream); - } - - @Override - public FloatSample loadFloatSample(URL url) throws IOException { - InputStream rawStream = url.openStream(); - BufferedInputStream inputStream = new BufferedInputStream(rawStream); - return loadFloatSample(inputStream); - } - - @Override - public FloatSample loadFloatSample(InputStream inputStream) throws IOException { - AudioFileParser fileParser; - IFFParser parser = new IFFParser(inputStream); - parser.readHead(); - if (parser.isRIFF()) { - fileParser = new WAVEFileParser(); - } else if (parser.isIFF()) { - fileParser = new AIFFFileParser(); - } else { - throw new IOException("Unsupported audio file type."); - } - return fileParser.load(parser); - } - -} diff --git a/src/com/jsyn/util/soundfile/IFFParser.java b/src/com/jsyn/util/soundfile/IFFParser.java deleted file mode 100644 index f429657..0000000 --- a/src/com/jsyn/util/soundfile/IFFParser.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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.util.soundfile; - -import java.io.EOFException; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Parse Electronic Arts style IFF File. IFF is a file format that allows "chunks" of data to be - * placed in a hierarchical file. It was designed by Jerry Morrison at Electronic Arts for the Amiga - * computer and is now used extensively by Apple Computer and other companies. IFF is an open - * standard. - * - * @see RIFFParser - * @see AudioSampleAIFF - * @author (C) 1997 Phil Burk, SoftSynth.com - */ - -class IFFParser extends FilterInputStream { - private long numBytesRead = 0; - private long totalSize = 0; - private int fileId; - static boolean debug = false; - - public static final int RIFF_ID = ('R' << 24) | ('I' << 16) | ('F' << 8) | 'F'; - public static final int LIST_ID = ('L' << 24) | ('I' << 16) | ('S' << 8) | 'T'; - public static final int FORM_ID = ('F' << 24) | ('O' << 16) | ('R' << 8) | 'M'; - - IFFParser(InputStream stream) { - super(stream); - numBytesRead = 0; - } - - /** - * Size of file based on outermost chunk size plus 8. Can be used to report progress when - * loading samples. - * - * @return Number of bytes in outer chunk plus header. - */ - public long getFileSize() { - return totalSize; - } - - /** - * Since IFF files use chunks with explicit size, it is important to keep track of how many - * bytes have been read from the file. Can be used to report progress when loading samples. - * - * @return Number of bytes read from stream, or skipped. - */ - public long getOffset() { - return numBytesRead; - } - - /** @return Next byte from stream. Increment offset by 1. */ - @Override - public int read() throws IOException { - numBytesRead++; - return super.read(); - } - - /** @return Next byte array from stream. Increment offset by len. */ - @Override - public int read(byte[] bar) throws IOException { - return read(bar, 0, bar.length); - } - - /** @return Next byte array from stream. Increment offset by len. */ - @Override - public int read(byte[] bar, int off, int len) throws IOException { - // Reading from a URL can return before all the bytes are available. - // So we keep reading until we get the whole thing. - int cursor = off; - int numLeft = len; - // keep reading data until we get it all - while (numLeft > 0) { - int numRead = super.read(bar, cursor, numLeft); - if (numRead < 0) - return numRead; - cursor += numRead; - numBytesRead += numRead; - numLeft -= numRead; - // System.out.println("read " + numRead + ", cursor = " + cursor + - // ", len = " + len); - } - return cursor - off; - } - - /** @return Skip forward in stream and add numBytes to offset. */ - @Override - public long skip(long numBytes) throws IOException { - numBytesRead += numBytes; - return super.skip(numBytes); - } - - /** Read 32 bit signed integer assuming Big Endian byte order. */ - public int readIntBig() throws IOException { - int result = read() & 0xFF; - result = (result << 8) | (read() & 0xFF); - result = (result << 8) | (read() & 0xFF); - int data = read(); - if (data == -1) - throw new EOFException("readIntBig() - EOF in middle of word at offset " + numBytesRead); - result = (result << 8) | (data & 0xFF); - return result; - } - - /** Read 32 bit signed integer assuming Little Endian byte order. */ - public int readIntLittle() throws IOException { - int result = read() & 0xFF; // LSB - result |= ((read() & 0xFF) << 8); - result |= ((read() & 0xFF) << 16); - int data = read(); - if (data == -1) - throw new EOFException("readIntLittle() - EOF in middle of word at offset " - + numBytesRead); - result |= (data << 24); - return result; - } - - /** Read 16 bit signed short assuming Big Endian byte order. */ - public short readShortBig() throws IOException { - short result = (short) ((read() << 8)); // MSB - int data = read(); - if (data == -1) - throw new EOFException("readShortBig() - EOF in middle of word at offset " - + numBytesRead); - result |= data & 0xFF; - return result; - } - - /** Read 16 bit signed short assuming Little Endian byte order. */ - public short readShortLittle() throws IOException { - short result = (short) (read() & 0xFF); // LSB - int data = read(); // MSB - if (data == -1) - throw new EOFException("readShortLittle() - EOF in middle of word at offset " - + numBytesRead); - result |= data << 8; - return result; - } - - public int readUShortLittle() throws IOException { - return (readShortLittle()) & 0x0000FFFF; - } - - /** Read 8 bit signed byte. */ - public byte readByte() throws IOException { - return (byte) read(); - } - - /** Read 32 bit signed int assuming IFF order. */ - public int readChunkSize() throws IOException { - if (isRIFF()) { - return readIntLittle(); - } - { - return readIntBig(); - } - } - - /** Convert a 4 character IFF ID to a String */ - public static String IDToString(int ID) { - byte bar[] = new byte[4]; - bar[0] = (byte) (ID >> 24); - bar[1] = (byte) (ID >> 16); - bar[2] = (byte) (ID >> 8); - bar[3] = (byte) ID; - return new String(bar); - } - - /** - * Parse the stream after reading the first ID and pass the forms and chunks to the ChunkHandler - */ - public void parseAfterHead(ChunkHandler handler) throws IOException { - int numBytes = readChunkSize(); - totalSize = numBytes + 8; - parseChunk(handler, fileId, numBytes); - if (debug) - System.out.println("parse() ------- end"); - } - - /** - * Parse the FORM and pass the chunks to the ChunkHandler The cursor should be positioned right - * after the type field. - */ - void parseForm(ChunkHandler handler, int ID, int numBytes, int type) throws IOException { - if (debug) { - System.out.println("IFF: parseForm >>>>>>>>>>>>>>>>>> BEGIN"); - } - while (numBytes > 8) { - int ckid = readIntBig(); - int size = readChunkSize(); - numBytes -= 8; - if (debug) { - System.out.println("chunk( " + IDToString(ckid) + ", " + size + " )"); - } - if (size < 0) { - throw new IOException("Bad IFF chunk Size: " + IDToString(ckid) + " = 0x" - + Integer.toHexString(ckid) + ", Size = " + size); - } - parseChunk(handler, ckid, size); - if ((size & 1) == 1) - size++; // even-up - numBytes -= size; - if (debug) { - System.out.println("parseForm: numBytes left in form = " + numBytes); - } - } - if (debug) { - System.out.println("IFF: parseForm <<<<<<<<<<<<<<<<<<<< END"); - } - - if (numBytes > 0) { - System.out.println("IFF Parser detected " + numBytes - + " bytes of garbage at end of FORM."); - skip(numBytes); - } - } - - /* - * Parse one chunk from IFF file. After calling handler, make sure stream is positioned at end - * of chunk. - */ - void parseChunk(ChunkHandler handler, int ckid, int numBytes) throws IOException { - long startOffset, endOffset; - int numRead; - startOffset = getOffset(); - if (isForm(ckid)) { - int type = readIntBig(); - if (debug) - System.out.println("parseChunk: form = " + IDToString(ckid) + ", " + numBytes - + ", " + IDToString(type)); - handler.handleForm(this, ckid, numBytes - 4, type); - endOffset = getOffset(); - numRead = (int) (endOffset - startOffset); - if (numRead < numBytes) - parseForm(handler, ckid, (numBytes - numRead), type); - } else { - handler.handleChunk(this, ckid, numBytes); - } - endOffset = getOffset(); - numRead = (int) (endOffset - startOffset); - if (debug) { - System.out.println("parseChunk: endOffset = " + endOffset); - System.out.println("parseChunk: numRead = " + numRead); - } - if ((numBytes & 1) == 1) - numBytes++; // even-up - if (numRead < numBytes) - skip(numBytes - numRead); - } - - public void readHead() throws IOException { - if (debug) - System.out.println("parse() ------- begin"); - numBytesRead = 0; - fileId = readIntBig(); - } - - public boolean isRIFF() { - return (fileId == RIFF_ID); - } - - public boolean isIFF() { - return (fileId == FORM_ID); - } - - /** - * Does the following chunk ID correspond to a container type like FORM? - */ - public boolean isForm(int ckid) { - if (isRIFF()) { - switch (ckid) { - case LIST_ID: - case RIFF_ID: - return true; - default: - return false; - } - } else { - switch (ckid) { - case LIST_ID: - case FORM_ID: - return true; - default: - return false; - } - } - } - -} diff --git a/src/com/jsyn/util/soundfile/WAVEFileParser.java b/src/com/jsyn/util/soundfile/WAVEFileParser.java deleted file mode 100644 index ec9350c..0000000 --- a/src/com/jsyn/util/soundfile/WAVEFileParser.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2009 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.util.soundfile; - -import java.io.EOFException; -import java.io.IOException; - -import com.jsyn.data.FloatSample; -import com.jsyn.data.SampleMarker; -import com.jsyn.util.SampleLoader; - -class WAVEFileParser extends AudioFileParser implements ChunkHandler { - static final short WAVE_FORMAT_PCM = 1; - static final short WAVE_FORMAT_IEEE_FLOAT = 3; - static final short WAVE_FORMAT_EXTENSIBLE = (short) 0xFFFE; - - static final byte[] KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { - 3, 0, 0, 0, 0, 0, 16, 0, -128, 0, 0, -86, 0, 56, -101, 113 - }; - static final byte[] KSDATAFORMAT_SUBTYPE_PCM = { - 1, 0, 0, 0, 0, 0, 16, 0, -128, 0, 0, -86, 0, 56, -101, 113 - }; - - static final int WAVE_ID = ('W' << 24) | ('A' << 16) | ('V' << 8) | 'E'; - static final int FMT_ID = ('f' << 24) | ('m' << 16) | ('t' << 8) | ' '; - static final int DATA_ID = ('d' << 24) | ('a' << 16) | ('t' << 8) | 'a'; - static final int CUE_ID = ('c' << 24) | ('u' << 16) | ('e' << 8) | ' '; - static final int FACT_ID = ('f' << 24) | ('a' << 16) | ('c' << 8) | 't'; - static final int SMPL_ID = ('s' << 24) | ('m' << 16) | ('p' << 8) | 'l'; - static final int LTXT_ID = ('l' << 24) | ('t' << 16) | ('x' << 8) | 't'; - static final int LABL_ID = ('l' << 24) | ('a' << 16) | ('b' << 8) | 'l'; - - int samplesPerBlock = 0; - int blockAlign = 0; - private int numFactSamples = 0; - private short format; - - WAVEFileParser() { - } - - @Override - FloatSample finish() throws IOException { - if ((byteData == null)) { - throw new IOException("No data found in audio sample."); - } - float[] floatData = new float[numFrames * samplesPerFrame]; - if (bitsPerSample == 16) { - SampleLoader.decodeLittleI16ToF32(byteData, 0, byteData.length, floatData, 0); - } else if (bitsPerSample == 24) { - SampleLoader.decodeLittleI24ToF32(byteData, 0, byteData.length, floatData, 0); - } else if (bitsPerSample == 32) { - if (format == WAVE_FORMAT_IEEE_FLOAT) { - SampleLoader.decodeLittleF32ToF32(byteData, 0, byteData.length, floatData, 0); - } else if (format == WAVE_FORMAT_PCM) { - SampleLoader.decodeLittleI32ToF32(byteData, 0, byteData.length, floatData, 0); - } else { - throw new IOException("WAV: Unsupported format = " + format); - } - } else { - throw new IOException("WAV: Unsupported bitsPerSample = " + bitsPerSample); - } - - return makeSample(floatData); - } - - // typedef struct { - // long dwIdentifier; - // long dwPosition; - // ID fccChunk; - // long dwChunkStart; - // long dwBlockStart; - // long dwSampleOffset; - // } CuePoint; - - /* Parse various chunks encountered in WAV file. */ - void parseCueChunk(IFFParser parser, int ckSize) throws IOException { - int numCuePoints = parser.readIntLittle(); - if (IFFParser.debug) { - System.out.println("WAV: numCuePoints = " + numCuePoints); - } - if ((ckSize - 4) != (6 * 4 * numCuePoints)) - throw new EOFException("Cue chunk too short!"); - for (int i = 0; i < numCuePoints; i++) { - int dwName = parser.readIntLittle(); /* dwName */ - int position = parser.readIntLittle(); // dwPosition - parser.skip(3 * 4); // fccChunk, dwChunkStart, dwBlockStart - int sampleOffset = parser.readIntLittle(); // dwPosition - - if (IFFParser.debug) { - System.out.println("WAV: parseCueChunk: #" + i + ", dwPosition = " + position - + ", dwName = " + dwName + ", dwSampleOffset = " + sampleOffset); - } - SampleMarker cuePoint = findOrCreateCuePoint(dwName); - cuePoint.position = position; - } - } - - void parseLablChunk(IFFParser parser, int ckSize) throws IOException { - int dwName = parser.readIntLittle(); - int textLength = (ckSize - 4) - 1; // don't read NUL terminator - String text = parseString(parser, textLength); - if (IFFParser.debug) { - System.out.println("WAV: label id = " + dwName + ", text = " + text); - } - SampleMarker cuePoint = findOrCreateCuePoint(dwName); - cuePoint.name = text; - } - - void parseLtxtChunk(IFFParser parser, int ckSize) throws IOException { - int dwName = parser.readIntLittle(); - int dwSampleLength = parser.readIntLittle(); - parser.skip(4 + (4 * 2)); // purpose through codepage - int textLength = (ckSize - ((4 * 4) + (4 * 2))) - 1; // don't read NUL - // terminator - if (textLength > 0) { - String text = parseString(parser, textLength); - if (IFFParser.debug) { - System.out.println("WAV: ltxt id = " + dwName + ", dwSampleLength = " - + dwSampleLength + ", text = " + text); - } - SampleMarker cuePoint = findOrCreateCuePoint(dwName); - cuePoint.comment = text; - } - } - - void parseFmtChunk(IFFParser parser, int ckSize) throws IOException { - format = parser.readShortLittle(); - samplesPerFrame = parser.readShortLittle(); - frameRate = parser.readIntLittle(); - parser.readIntLittle(); /* skip dwAvgBytesPerSec */ - blockAlign = parser.readShortLittle(); - bitsPerSample = parser.readShortLittle(); - - if (IFFParser.debug) { - System.out.println("WAV: format = 0x" + Integer.toHexString(format)); - System.out.println("WAV: bitsPerSample = " + bitsPerSample); - System.out.println("WAV: samplesPerFrame = " + samplesPerFrame); - } - bytesPerFrame = blockAlign; - bytesPerSample = bytesPerFrame / samplesPerFrame; - samplesPerBlock = (8 * blockAlign) / bitsPerSample; - - if (format == WAVE_FORMAT_EXTENSIBLE) { - int extraSize = parser.readShortLittle(); - short validBitsPerSample = parser.readShortLittle(); - int channelMask = parser.readIntLittle(); - byte[] guid = new byte[16]; - parser.read(guid); - if (IFFParser.debug) { - System.out.println("WAV: extraSize = " + extraSize); - System.out.println("WAV: validBitsPerSample = " + validBitsPerSample); - System.out.println("WAV: channelMask = " + channelMask); - System.out.print("guid = {"); - for (int i = 0; i < guid.length; i++) { - System.out.print(guid[i] + ", "); - } - System.out.println("}"); - } - if (matchBytes(guid, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { - format = WAVE_FORMAT_IEEE_FLOAT; - } else if (matchBytes(guid, KSDATAFORMAT_SUBTYPE_PCM)) { - format = WAVE_FORMAT_PCM; - } - } - if ((format != WAVE_FORMAT_PCM) && (format != WAVE_FORMAT_IEEE_FLOAT)) { - throw new IOException( - "Only WAVE_FORMAT_PCM and WAVE_FORMAT_IEEE_FLOAT supported. format = " + format); - } - if ((bitsPerSample != 16) && (bitsPerSample != 24) && (bitsPerSample != 32)) { - throw new IOException( - "Only 16 and 24 bit PCM or 32-bit float WAV files supported. width = " - + bitsPerSample); - } - } - - private boolean matchBytes(byte[] bar1, byte[] bar2) { - if (bar1.length != bar2.length) - return false; - for (int i = 0; i < bar1.length; i++) { - if (bar1[i] != bar2[i]) - return false; - } - return true; - } - - private int convertByteToFrame(int byteOffset) throws IOException { - if (blockAlign == 0) { - throw new IOException("WAV file has bytesPerBlock = zero"); - } - if (samplesPerFrame == 0) { - throw new IOException("WAV file has samplesPerFrame = zero"); - } - int nFrames = (samplesPerBlock * byteOffset) / (samplesPerFrame * blockAlign); - return nFrames; - } - - private int calculateNumFrames(int numBytes) throws IOException { - int nFrames; - if (numFactSamples > 0) { - // nFrames = numFactSamples / samplesPerFrame; - nFrames = numFactSamples; // FIXME which is right - } else { - nFrames = convertByteToFrame(numBytes); - } - return nFrames; - } - - // Read fraction in range of 0 to 0xFFFFFFFF and - // convert to 0.0 to 1.0 range. - private double readFraction(IFFParser parser) throws IOException { - // Put L at end or we get -1. - long maxFraction = 0x0FFFFFFFFL; - // Get unsigned fraction. Have to fit in long. - long fraction = (parser.readIntLittle()) & maxFraction; - return (double) fraction / (double) maxFraction; - } - - void parseSmplChunk(IFFParser parser, int ckSize) throws IOException { - parser.readIntLittle(); // Manufacturer - parser.readIntLittle(); // Product - parser.readIntLittle(); // Sample Period - int unityNote = parser.readIntLittle(); - double pitchFraction = readFraction(parser); - originalPitch = unityNote + pitchFraction; - - parser.readIntLittle(); // SMPTE Format - parser.readIntLittle(); // SMPTE Offset - int numLoops = parser.readIntLittle(); - parser.readIntLittle(); // Sampler Data - - int lastCueID = Integer.MAX_VALUE; - for (int i = 0; i < numLoops; i++) { - int cueID = parser.readIntLittle(); - parser.readIntLittle(); // type - int loopStartPosition = parser.readIntLittle(); - // Point to sample one after. - int loopEndPosition = parser.readIntLittle() + 1; - // TODO handle fractional loop sizes? - double endFraction = readFraction(parser); - parser.readIntLittle(); // playCount - - // Use lowest numbered cue. - if (cueID < lastCueID) { - sustainBegin = loopStartPosition; - sustainEnd = loopEndPosition; - } - } - } - - void parseFactChunk(IFFParser parser, int ckSize) throws IOException { - numFactSamples = parser.readIntLittle(); - } - - void parseDataChunk(IFFParser parser, int ckSize) throws IOException { - long numRead; - dataPosition = parser.getOffset(); - if (ifLoadData) { - byteData = new byte[ckSize]; - numRead = parser.read(byteData); - } else { - numRead = parser.skip(ckSize); - } - if (numRead != ckSize) { - throw new EOFException("WAV data chunk too short! Read " + numRead + " instead of " - + ckSize); - } - numFrames = calculateNumFrames(ckSize); - } - - @Override - public void handleForm(IFFParser parser, int ckID, int ckSize, int type) throws IOException { - if ((ckID == IFFParser.RIFF_ID) && (type != WAVE_ID)) - throw new IOException("Bad WAV form type = " + IFFParser.IDToString(type)); - } - - /** - * Called by parse() method to handle chunks in a WAV specific manner. - * - * @param ckID four byte chunk ID such as 'data' - * @param ckSize size of chunk in bytes - * @return number of bytes left in chunk - */ - @Override - public void handleChunk(IFFParser parser, int ckID, int ckSize) throws IOException { - switch (ckID) { - case FMT_ID: - parseFmtChunk(parser, ckSize); - break; - case DATA_ID: - parseDataChunk(parser, ckSize); - break; - case CUE_ID: - parseCueChunk(parser, ckSize); - break; - case FACT_ID: - parseFactChunk(parser, ckSize); - break; - case SMPL_ID: - parseSmplChunk(parser, ckSize); - break; - case LABL_ID: - parseLablChunk(parser, ckSize); - break; - case LTXT_ID: - parseLtxtChunk(parser, ckSize); - break; - default: - break; - } - } - - /* - * (non-Javadoc) - * @see com.softsynth.javasonics.util.AudioSampleLoader#isLittleEndian() - */ - boolean isLittleEndian() { - return true; - } - -} |