|
1 | 1 | package processing.sound;
|
2 | 2 |
|
3 | 3 | import com.jsyn.data.SegmentedEnvelope;
|
| 4 | +import com.jsyn.ports.QueueDataCommand; |
| 5 | +import com.jsyn.ports.QueueDataEvent; |
| 6 | +import com.jsyn.ports.UnitDataQueueCallback; |
4 | 7 | import com.jsyn.unitgen.VariableRateMonoReader;
|
5 |
| -import com.softsynth.shared.time.TimeStamp; |
6 | 8 |
|
7 | 9 | import processing.core.PApplet;
|
8 | 10 |
|
@@ -35,23 +37,43 @@ public void play(SoundObject input, float attackTime, float sustainTime, float s
|
35 | 37 | sustainTime, sustainLevel * input.amp, // sustain
|
36 | 38 | releaseTime, 0.0 });
|
37 | 39 |
|
38 |
| - // TODO re-use player from fixed or dynamic pool |
| 40 | + // fire-and-forget envelope player |
39 | 41 | VariableRateMonoReader player = new VariableRateMonoReader();
|
40 |
| - |
41 |
| - // this would make sense to me but breaks the envelope for some reason |
42 |
| -// input.amplitude.disconnectAll(); |
43 |
| - player.output.connect(input.amplitude); |
44 | 42 | Engine.getEngine().add(player);
|
| 43 | + // we need to start the player explicitly, otherwise if it gets disconnected |
| 44 | + // by another envelope kicking in before it has completed, it would stop |
| 45 | + // prematurely and the callback (which removes it from the synth for garbage |
| 46 | + // collection) would never get called! |
| 47 | + player.start(); |
45 | 48 |
|
46 |
| - player.dataQueue.queue(env); |
| 49 | + input.amplitude.disconnectAll(); |
| 50 | + player.output.connect(input.amplitude); |
47 | 51 | if (!input.isPlaying()) {
|
48 | 52 | input.play();
|
49 | 53 | }
|
50 | 54 |
|
51 |
| - // disconnect player from amplitude port after finished and set amplitude to 0 |
52 |
| - TimeStamp envFinished = Engine.getEngine().synth.createTimeStamp().makeRelative(attackTime + sustainTime + releaseTime); |
53 |
| - player.output.disconnect(0, input.amplitude, 0, envFinished); |
54 |
| - // TODO better: trigger unit stop() so that isPlaying() is set to false as well? |
55 |
| - input.amplitude.set(0, envFinished); |
| 55 | + QueueDataCommand cmd = player.dataQueue.createQueueDataCommand(env, 0, env.getNumFrames()); |
| 56 | + // need to set auto stop for the remove() inside the callback to work |
| 57 | + cmd.setAutoStop(true); |
| 58 | + cmd.setCallback(new UnitDataQueueCallback() { |
| 59 | + public void finished(QueueDataEvent event) { |
| 60 | + // check if this output has maybe already been disconnected (by a new |
| 61 | + // envelope that has taken over) |
| 62 | + if (player.output.isConnected()) { |
| 63 | + player.output.disconnectAll(); |
| 64 | + // TODO what to do with the input soundobject after the envelope is |
| 65 | + // finished? just silence it, but then it isn't automatically garbage |
| 66 | + // collected? should we trigger the object's stop() as well? |
| 67 | + input.amplitude.set(0); |
| 68 | + } |
| 69 | + Engine.getEngine().remove(player); |
| 70 | + } |
| 71 | + public void looped(QueueDataEvent event) { |
| 72 | + } |
| 73 | + public void started(QueueDataEvent event) { |
| 74 | + } |
| 75 | + }); |
| 76 | + |
| 77 | + player.getSynthesizer().queueCommand(cmd); |
56 | 78 | }
|
57 | 79 | }
|
0 commit comments