Issue
In short on a button press I'd like to play a few notes using a PolySynth
and a Sequence
. If the user repeatedly presses the button I'd like whatever is playing to be stopped, and started again. This is most likely because of either the envelope's decay/sustain.
The issue: No matter what I try I cannot completely cancel/silence the previously played notes in case the sequence is started again (button clicked again).
My Synth:
import { PolySynth } from 'tone'
const synth = new PolySynth(Synth, {
oscillator: {
type: 'sine4',
volume: -6,
},
envelope: {
attack: 0.01,
decay: 0.5,
sustain: 0.1,
release: 1,
},
}).toDestination()
synth.maxPolyphony = 4 // max notes playing at a time, not sure if necessary
My Sequence:
import { Sequence } from 'tone'
// Play the 2 notes individually then play them together
const notes = [
{ note: 'C4', duration: '8n' },
{ note: 'G4', duration: '8n' },
{ note: ['C4', 'G4'], duration: '4n' }
]
// The sequence that should play the notes after one another
const sequence = new Sequence({
subdivision: '8n',
loop: false,
events: notes,
callback: (time, note) => synth.triggerAttackRelease(note.note, note.duration, time),
})
The way I play it, this is an event handler:
import { start, Transport } from 'tone'
// Event handler simply attached to a button's onClick
function onButtonClicked() {
// Call whatever this start is, doc says it can only happen in an event handler
start()
// Try everything to kill current sound
Transport.cancel()
Transport.stop()
// Start it again
Transport.start()
sequence.start()
}
How could I completely kill all sound (if there is any) before starting to play it?
Solution
Short Answer
Thinking about this quite a bit, If I understand you correctly this actually is intended behavior. You are triggering a a note on a Synth (which is basically an AudioWorkletNode). So as soon as a note triggered the synth, the note is gone. The only way to stop that note from playing would be to mute the synth itself.
Long Answer
In the comments you said, that you might missing something conceptually and I think you are on the right track with that.
Let's think about how a sound is generated with MIDI.
- You are connecting a Synth (which takes MIDI notes and generates Sound) to an output
- You are scheduling some MIDI notes on the transport
- You start the transport
- As soon as the transport hits the scheduled time for a note, that MIDI value will be sent to the Synth.
- Since the Synth is basically an AudioWorkletNode with an Envelope Generator, the Synth takes that MIDI note and triggers the internal sound generation (via the envelope). So a MIDI note at a specific point in time triggers a specific length of sound generation (which would be the ADS part). Even if the MIDI notes duration is only 1ms long in your example, the sound generation would hold on for at least 1.001 seconds (Release plus 1 milliseconds MIDI duration). Let's break this down a bit more:
- The MIDI note has a start and end point on the imaginary transport timeline.
- Start triggers the ADS part of the Envelope.
- End triggers the R part of the Envelope.
- Once your MIDI note triggered the Envelope the sound gets generated.
So when you stop your transport or the sequence itself, what would that do? If a MIDI note already triggered the Envelope, the Envelope will receive the MIDI end trigger and trigger the Release envelope.
So there will always be a tailing sound of your Synth, because the MIDI note does not determine your start and end point of your Synth, but triggers parts of your Envelope. So actually your Synth creates the sound and that is neither tied to the transport, nor can it be.
Hope that explanation helped you a bit. If I misunderstood you, I am happy to correct.
Answered By - Johannes Klauß
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.