diff options
Diffstat (limited to 'src/com/jsyn')
-rw-r--r-- | src/com/jsyn/data/AudioSample.java | 14 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/ChannelOut.java | 14 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/FixedRateMonoWriter.java | 9 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/FixedRateStereoWriter.java | 8 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/LineOut.java | 8 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/MonoStreamWriter.java | 8 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/SequentialDataWriter.java | 16 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/StereoStreamWriter.java | 9 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/UnitGenerator.java | 14 | ||||
-rw-r--r-- | src/com/jsyn/unitgen/UnitStreamWriter.java | 16 | ||||
-rw-r--r-- | src/com/jsyn/util/MultiChannelSynthesizer.java | 111 |
11 files changed, 151 insertions, 76 deletions
diff --git a/src/com/jsyn/data/AudioSample.java b/src/com/jsyn/data/AudioSample.java index 42d8501..dcbbae5 100644 --- a/src/com/jsyn/data/AudioSample.java +++ b/src/com/jsyn/data/AudioSample.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,13 +20,13 @@ 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; - private double frameRate; + protected int channelsPerFrame = 1; + private double frameRate = 44100.0; private double pitch; private ArrayList<SampleMarker> markers; @@ -61,7 +61,7 @@ public abstract class AudioSample extends SequentialDataCommon { /** * Set the recorded pitch as a fractional MIDI semitone value where 60 is Middle C. - * + * * @param pitch */ public void setPitch(double pitch) { @@ -89,7 +89,7 @@ public abstract class AudioSample extends SequentialDataCommon { /** * 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) { diff --git a/src/com/jsyn/unitgen/ChannelOut.java b/src/com/jsyn/unitgen/ChannelOut.java index 5eafacc..89f778b 100644 --- a/src/com/jsyn/unitgen/ChannelOut.java +++ b/src/com/jsyn/unitgen/ChannelOut.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +20,7 @@ import com.jsyn.ports.UnitInputPort; /** * Provides access to one channel of the audio output. - * + * * @author Phil Burk (C) 2009 Mobileer Inc * @see ChannelIn */ @@ -40,6 +40,14 @@ public class ChannelOut extends UnitGenerator { 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); diff --git a/src/com/jsyn/unitgen/FixedRateMonoWriter.java b/src/com/jsyn/unitgen/FixedRateMonoWriter.java index 4dd9f2a..c215c55 100644 --- a/src/com/jsyn/unitgen/FixedRateMonoWriter.java +++ b/src/com/jsyn/unitgen/FixedRateMonoWriter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,11 +21,14 @@ 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")); } diff --git a/src/com/jsyn/unitgen/FixedRateStereoWriter.java b/src/com/jsyn/unitgen/FixedRateStereoWriter.java index 9f4e38d..e4502f9 100644 --- a/src/com/jsyn/unitgen/FixedRateStereoWriter.java +++ b/src/com/jsyn/unitgen/FixedRateStereoWriter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,7 +21,9 @@ 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 */ diff --git a/src/com/jsyn/unitgen/LineOut.java b/src/com/jsyn/unitgen/LineOut.java index d58f211..29c8ce7 100644 --- a/src/com/jsyn/unitgen/LineOut.java +++ b/src/com/jsyn/unitgen/LineOut.java @@ -42,6 +42,14 @@ public class LineOut extends UnitGenerator implements UnitSink { } } + /** + * 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/MonoStreamWriter.java b/src/com/jsyn/unitgen/MonoStreamWriter.java index 0184766..283af81 100644 --- a/src/com/jsyn/unitgen/MonoStreamWriter.java +++ b/src/com/jsyn/unitgen/MonoStreamWriter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,7 +23,9 @@ 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 { diff --git a/src/com/jsyn/unitgen/SequentialDataWriter.java b/src/com/jsyn/unitgen/SequentialDataWriter.java index 5a5febb..cb3bb11 100644 --- a/src/com/jsyn/unitgen/SequentialDataWriter.java +++ b/src/com/jsyn/unitgen/SequentialDataWriter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,7 +21,9 @@ 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 { @@ -31,4 +33,12 @@ public abstract class SequentialDataWriter extends UnitGenerator { 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/StereoStreamWriter.java b/src/com/jsyn/unitgen/StereoStreamWriter.java index 072974b..b387836 100644 --- a/src/com/jsyn/unitgen/StereoStreamWriter.java +++ b/src/com/jsyn/unitgen/StereoStreamWriter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,7 +23,9 @@ 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 { @@ -48,5 +50,4 @@ public class StereoStreamWriter extends UnitStreamWriter { } } } - } diff --git a/src/com/jsyn/unitgen/UnitGenerator.java b/src/com/jsyn/unitgen/UnitGenerator.java index f8278ae..1e87ae6 100644 --- a/src/com/jsyn/unitgen/UnitGenerator.java +++ b/src/com/jsyn/unitgen/UnitGenerator.java @@ -59,8 +59,6 @@ public abstract class UnitGenerator { private boolean enabled = true; private static int nextId; private final int id = nextId++; - private int frameRate; - private double framePeriod; static Logger logger = Logger.getLogger(UnitGenerator.class.getName()); @@ -245,6 +243,16 @@ public abstract class UnitGenerator { } /** + * 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 @@ -310,8 +318,6 @@ public abstract class UnitGenerator { */ @Deprecated public void setFrameRate(int rate) { - this.frameRate = rate; - this.framePeriod = 1.0 / rate; } /** Needed by UnitSink */ diff --git a/src/com/jsyn/unitgen/UnitStreamWriter.java b/src/com/jsyn/unitgen/UnitStreamWriter.java index ecc231d..0c5bd8b 100644 --- a/src/com/jsyn/unitgen/UnitStreamWriter.java +++ b/src/com/jsyn/unitgen/UnitStreamWriter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,7 +21,9 @@ 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 { @@ -36,6 +38,14 @@ public abstract class UnitStreamWriter extends UnitGenerator implements UnitSink 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/util/MultiChannelSynthesizer.java b/src/com/jsyn/util/MultiChannelSynthesizer.java index c2d0e86..6db0790 100644 --- a/src/com/jsyn/util/MultiChannelSynthesizer.java +++ b/src/com/jsyn/util/MultiChannelSynthesizer.java @@ -22,9 +22,9 @@ 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.LinearRamp; import com.jsyn.unitgen.PowerOfTwo; import com.jsyn.unitgen.SineOscillator; import com.jsyn.unitgen.TwoInDualOut; @@ -53,10 +53,27 @@ public class MultiChannelSynthesizer { private TwoInDualOut outputUnit; private ChannelContext[] channels; - private class ChannelContext { + 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; @@ -65,12 +82,20 @@ public class MultiChannelSynthesizer { private Multiply volumeMultiplier; private Pan panner; private double vibratoRate = 5.0; - private double bendRangeOctaves = 24.0 / 12.0; + private double bendRangeOctaves = 2.0 / 12.0; // private double bendRangeOctaves = 0.0 / 12.0; private int presetIndex; + private ChannelGroupContext groupContext; + VoiceOperation voiceOperation = new VoiceOperation() { + @Override + public void operate (UnitVoice voice) { + voice.usePreset(presetIndex); + connectVoice(voice); + } + }; - void setup(int numVoices, VoiceDescription voiceDescription) { - this.voiceDescription = voiceDescription; + 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. @@ -91,60 +116,57 @@ public class MultiChannelSynthesizer { lfo.amplitude.set(0.0); lfo.frequency.set(vibratoRate); - voices = new UnitVoice[numVoices]; - for (int i = 0; i < numVoices; i++) { - UnitVoice voice = voiceDescription.createUnitVoice(); - UnitGenerator ugen = voice.getUnitGenerator(); - synth.add(ugen); - - // Hook up some channel controllers to standard ports on the voice. - UnitInputPort freqMod = (UnitInputPort) ugen - .getPortByName(UnitGenerator.PORT_NAME_FREQUENCY_SCALER); - if (freqMod != null) { - pitchToLinear.output.connect(freqMod); - } - UnitInputPort timbrePort = (UnitInputPort) ugen - .getPortByName(UnitGenerator.PORT_NAME_TIMBRE); - if (timbrePort != null) { - timbreRamp.output.connect(timbrePort); - timbreRamp.input.setup(timbrePort); - } - UnitInputPort pressurePort = (UnitInputPort) ugen - .getPortByName(UnitGenerator.PORT_NAME_PRESSURE); - if (pressurePort != null) { - pressureRamp.output.connect(pressurePort); - pressureRamp.input.setup(pressurePort); - } - voice.getOutput().connect(volumeMultiplier.inputA); // mono mix all the voices - voices[i] = voice; - } - 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); - allocator = new VoiceAllocator(voices); + } + + 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 % voiceDescription.getPresetCount(); - String name = voiceDescription.getPresetNames()[programWrapped]; - System.out.println("Preset[" + program + "] = " + name); + int programWrapped = program % groupContext.voiceDescription.getPresetCount(); + String name = groupContext.voiceDescription.getPresetNames()[programWrapped]; + //System.out.println("Preset[" + program + "] = " + name); presetIndex = programWrapped; } void noteOff(int noteNumber, int velocity) { - allocator.noteOff(noteNumber, synth.createTimeStamp()); + groupContext.allocator.noteOff(noteNumber, synth.createTimeStamp()); } void noteOn(int noteNumber, int velocity) { double frequency = AudioMath.pitchToFrequency(noteNumber); double amplitude = velocity / (4 * 128.0); TimeStamp timeStamp = synth.createTimeStamp(); - allocator.usePreset(presetIndex, timeStamp); - // System.out.println("noteOn(noteNumber) -> " + frequency + " Hz"); - allocator.noteOn(noteNumber, frequency, amplitude, timeStamp); + //System.out.println("noteOn(noteNumber) -> " + frequency + " Hz"); + groupContext.allocator.noteOn(noteNumber, frequency, amplitude, voiceOperation, timeStamp); } public void setPitchBend(double offset) { @@ -223,8 +245,10 @@ public class MultiChannelSynthesizer { 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(voicesPerChannel, voiceDescription); + channels[startChannel + i].setup(groupContext); } } @@ -250,6 +274,7 @@ public class MultiChannelSynthesizer { * @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); } @@ -289,7 +314,7 @@ public class MultiChannelSynthesizer { * Pan from left to right. * * @param channel - * @param offset ranges from -1.0 to +1.0 + * @param pan ranges from -1.0 to +1.0 */ public void setPan(int channel, double pan) { ChannelContext channelContext = channels[channel]; |