aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/jsyn/data/AudioSample.java14
-rw-r--r--src/com/jsyn/unitgen/ChannelOut.java14
-rw-r--r--src/com/jsyn/unitgen/FixedRateMonoWriter.java9
-rw-r--r--src/com/jsyn/unitgen/FixedRateStereoWriter.java8
-rw-r--r--src/com/jsyn/unitgen/LineOut.java8
-rw-r--r--src/com/jsyn/unitgen/MonoStreamWriter.java8
-rw-r--r--src/com/jsyn/unitgen/SequentialDataWriter.java16
-rw-r--r--src/com/jsyn/unitgen/StereoStreamWriter.java9
-rw-r--r--src/com/jsyn/unitgen/UnitGenerator.java14
-rw-r--r--src/com/jsyn/unitgen/UnitStreamWriter.java16
-rw-r--r--src/com/jsyn/util/MultiChannelSynthesizer.java111
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];