aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/jsyn/engine/SynthesisEngine.java
diff options
context:
space:
mode:
authorPhil Burk <[email protected]>2016-08-09 19:28:26 -0700
committerGitHub <[email protected]>2016-08-09 19:28:26 -0700
commita6583e89166f7477a675cf3094a91b303ba7850a (patch)
treed8ed90f9edeea55903c6f5fd8ca9ecf8c6676791 /src/com/jsyn/engine/SynthesisEngine.java
parenteb36cf83f1cca79e76c4ad44fc78077c9428790b (diff)
parente83baf9bf34cc41097e7f38f16dee0df2f80554a (diff)
Merge pull request #31 from philburk/startstop
Fix race condition when stopping and restarting the synthesizer.
Diffstat (limited to 'src/com/jsyn/engine/SynthesisEngine.java')
-rw-r--r--src/com/jsyn/engine/SynthesisEngine.java165
1 files changed, 88 insertions, 77 deletions
diff --git a/src/com/jsyn/engine/SynthesisEngine.java b/src/com/jsyn/engine/SynthesisEngine.java
index 8413e29..e966b30 100644
--- a/src/com/jsyn/engine/SynthesisEngine.java
+++ b/src/com/jsyn/engine/SynthesisEngine.java
@@ -52,17 +52,17 @@ import com.softsynth.shared.time.TimeStamp;
* @author Phil Burk (C) 2009 Mobileer Inc
* @see Synthesizer
*/
-public class SynthesisEngine implements Runnable, 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 AudioDeviceOutputStream audioOutputStream;
- private AudioDeviceInputStream audioInputStream;
- private Thread audioThread;
+ private EngineThread engineThread;
private final ScheduledQueue<ScheduledCommand> commandQueue = new ScheduledQueue<ScheduledCommand>();
- private volatile boolean go;
private InterleavingBuffer inputBuffer;
private InterleavingBuffer outputBuffer;
@@ -85,6 +85,8 @@ public class SynthesisEngine implements Runnable, Synthesizer {
// 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. */
@@ -235,20 +237,12 @@ public class SynthesisEngine implements Runnable, Synthesizer {
inverseNyquist = 2.0 / frameRate;
if (useRealTime) {
- if (numInputChannels > 0) {
- audioInputStream = audioDeviceManager.createInputStream(inputDeviceID, frameRate,
- numInputChannels);
- }
- if (numOutputChannels > 0) {
- audioOutputStream = audioDeviceManager.createOutputStream(outputDeviceID,
- frameRate, numOutputChannels);
- }
- audioThread = new Thread(this);
- logger.fine("Synth thread old priority = " + audioThread.getPriority());
- audioThread.setPriority(audioThread.getPriority() + 2);
- logger.fine("Synth thread new priority = " + audioThread.getPriority());
- go = true;
- audioThread.start();
+ engineThread = new EngineThread(inputDeviceID, numInputChannels,
+ outputDeviceID, numOutputChannels);
+ logger.fine("Synth thread old priority = " + engineThread.getPriority());
+ engineThread.setPriority(engineThread.getPriority() + 2);
+ logger.fine("Synth thread new priority = " + engineThread.getPriority());
+ engineThread.start();
}
started = true;
@@ -256,7 +250,8 @@ public class SynthesisEngine implements Runnable, Synthesizer {
@Override
public boolean isRunning() {
- return go;
+ Thread thread = engineThread;
+ return (thread != null) && thread.isAlive();
}
@Override
@@ -268,13 +263,11 @@ public class SynthesisEngine implements Runnable, Synthesizer {
if (useRealTime) {
// Stop audio synthesis and all units.
- go = false;
- if (audioThread != null) {
+ if (engineThread != null) {
try {
// Interrupt now, otherwise audio thread will wait for audio I/O.
- audioThread.interrupt();
-
- audioThread.join(1000);
+ engineThread.requestStop();
+ engineThread.join(MAX_THREAD_STOP_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
@@ -286,58 +279,84 @@ public class SynthesisEngine implements Runnable, Synthesizer {
started = false;
}
- @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();
- String msg = String.format("Input Latency in = %5.1f msec",
- 1000 * audioInputStream.getLatency());
- logger.fine(msg);
+ 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 (audioOutputStream != null) {
- logger.finer("JSyn synthesis thread trying to start audio OUTPUT!");
- audioOutputStream.start();
- String msg = String.format("Output Latency = %5.1f msec",
- 1000 * audioOutputStream.getLatency());
- logger.fine(msg);
- // Buy some time while we fill the buffer.
- audioOutputStream.write(outputBuffer.interleavedBuffer);
+ if (numOutputChannels > 0) {
+ audioOutputStream = audioDeviceManager.createOutputStream(outputDeviceID,
+ frameRate, numOutputChannels);
}
- loadAnalyzer = new LoadAnalyzer();
- while (go) {
- if (audioInputStream != null) {
- audioInputStream.read(inputBuffer.interleavedBuffer);
- }
+ }
- loadAnalyzer.start();
- runAudioTasks();
- generateNextBuffer();
- loadAnalyzer.stop();
+ 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) {
- // This call will block when the output is full.
+ 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) {
+ if (audioInputStream != null) {
+ audioInputStream.read(inputBuffer.interleavedBuffer);
+ }
+
+ loadAnalyzer.start();
+ runAudioTasks();
+ generateNextBuffer();
+ loadAnalyzer.stop();
+
+ if (audioOutputStream != null) {
+ // This call will block when the output is full.
+ audioOutputStream.write(outputBuffer.interleavedBuffer);
+ }
+ }
- } catch (Throwable e) {
- e.printStackTrace();
- go = false;
+ } 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();
+ } 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.");
}
- logger.fine("JSyn synthesis thread exiting.");
}
private void runAudioTasks() {
@@ -395,7 +414,7 @@ public class SynthesisEngine implements Runnable, Synthesizer {
@Override
public void scheduleCommand(TimeStamp timeStamp, ScheduledCommand command) {
- if ((Thread.currentThread() == audioThread) && (timeStamp.getTime() <= getCurrentTime())) {
+ if ((Thread.currentThread() == engineThread) && (timeStamp.getTime() <= getCurrentTime())) {
command.run();
} else {
logger.fine("scheduling " + command + ", at time " + timeStamp.getTime());
@@ -622,19 +641,11 @@ public class SynthesisEngine implements Runnable, Synthesizer {
}
public double getOutputLatency() {
- if (audioOutputStream != null) {
- return audioOutputStream.getLatency();
- } else {
- return 0;
- }
+ return mOutputLatency;
}
public double getInputLatency() {
- if (audioInputStream != null) {
- return audioInputStream.getLatency();
- } else {
- return 0;
- }
+ return mInputLatency;
}
@Override