admin管理员组文章数量:1319477
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.
The issue: No matter what I try I cannot pletely cancel/silence the previously played notes in case the sequence is started again (button clicked again). This is most likely because of either the envelope's decay/sustain.
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 pletely kill all sound (if there is any) before starting to play it?
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.
The issue: No matter what I try I cannot pletely cancel/silence the previously played notes in case the sequence is started again (button clicked again). This is most likely because of either the envelope's decay/sustain.
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 pletely kill all sound (if there is any) before starting to play it?
Share Improve this question edited Aug 25, 2022 at 16:16 Balázs Édes asked Sep 21, 2020 at 14:27 Balázs ÉdesBalázs Édes 13.8k7 gold badges60 silver badges104 bronze badges 2-
I guess you have to stop the sequence itself, since it is not synced to the transport. So use
sequence.stop()
in your button callback. – Johannes Klauß Commented Sep 21, 2020 at 23:32 - I went through the api methods and it seems like I'm conceptually missing something. stop on the sequence seems to pletely kill the sequence making it non-restartable – Balázs Édes Commented Sep 22, 2020 at 19:24
5 Answers
Reset to default 4Short 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 ments 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.
The note keeps playing because the transport stops after the note was triggered and before it was released. Therefore a solution is to trigger the release of all notes when you push the stop button. I hit a similar problem while using tambien/piano (based on Tonejs).
Tone.Transport.toggle()
if (Tone.Transport.state === 'stopped') {
for (let i=9; i<97; i++) {
piano.keyUp({midi: i}, '+0')
}
}
That solution could be difficult to implement in longer sequences, but in your case it should work. I've challenged quite similar problem and it worked.
The problem with the polySynth is that you can only add notes, which are played. But with the normal synth it is possible to "kill the sound" by overwriting the played note by the empty one.
// It would create continuously playing note.
synth = synth || new Tone.Synth().toMaster();
synth.triggerAttackRelease(noteToPlay);
// It would mute the sound.
synth = synth || new Tone.Synth().toMaster();
synth.triggerAttackRelease();
It is possible to play many single synths simultaneously, so you can create the polyphonic synth manually.
synth1 = synth1 || new Tone.Synth().toMaster();
synth1.triggerAttackRelease(noteToPlay);
synth2 = synth2 || new Tone.Synth().toMaster();
synth2.triggerAttackRelease(noteToPlay2);
synth3 = synth3 || new Tone.Synth().toMaster();
synth3.triggerAttackRelease(noteToPlay3);
Building the sequence would be more plicated, but you will be able to mute the playing sequence by adding the "soundKiller" at the beginning of the play function. What's important: instead of declaring the sequence and then play it by calling "Transport", just play the notes inside the event handler (because - as another person has already written - transport can't be stopped after calling it).
You can call the releaseAll() method on the PolySynth object:
polySynth.releaseAll()
This stops all currently triggered notes from playing.
Note that for the release of the note to register, Tone.Transport still have to be playing, so you might have to slightly delay the Tone.Transport.stop() call with a setTimeout.
Use Tone.Transport.pause()
See example below if you have a play/pause button with class of 'pause-play':
$( '.pause-play' ).on('click', function(e) {
if (Tone.Transport.state === "paused" ) {
Tone.Transport.start("+0.1") })
else {
Tone.Transport.pause() }
}
)
本文标签: javascriptTonejs completely stop all playing soundsStack Overflow
版权声明:本文标题:javascript - Tone.js completely stop all playing sounds - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742059044a2418471.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论