Javascript Tone.js完全停止所有播放声音

Javascript Tone.js完全停止所有播放声音,javascript,typescript,audio,tone.js,Javascript,Typescript,Audio,Tone.js,简而言之,按下一个按钮,我想用PolySynth和序列播放几个音符。如果用户反复按下按钮,我希望任何正在播放的都停止,然后重新开始。这很可能是因为封套的衰减/维持 问题:无论我如何尝试,我都无法完全取消/静音先前播放的音符,以防序列再次启动(再次单击按钮) 我的合成器: import { PolySynth } from 'tone' const synth = new PolySynth(Synth, { oscillator: { type: 'sine4', volu

简而言之,按下一个按钮,我想用
PolySynth
序列播放几个音符。如果用户反复按下按钮,我希望任何正在播放的都停止,然后重新开始。这很可能是因为封套的衰减/维持

问题:无论我如何尝试,我都无法完全取消/静音先前播放的音符,以防序列再次启动(再次单击按钮)

我的合成器:

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
我的顺序:

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),
})
按照我的播放方式,这是一个事件处理程序:

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()
}
在开始播放之前,我怎样才能完全消除所有声音(如果有) 仔细想想,如果我理解正确的话,这实际上是一种故意的行为。 您正在触发Synth(基本上是AudioWorkletNode)上的注释。所以一旦一个音符触发了合成器,这个音符就消失了。停止播放该音符的唯一方法是使合成器本身静音

长话短说 在你所说的评论中,你可能在概念上遗漏了一些东西,我认为你在这方面是正确的

让我们考虑一下如何使用MIDI生成声音

  • 您正在将Synth(用于录制MIDI音符并生成声音)连接到输出
  • 您正在安排一些MIDI音符
  • 你启动交通工具
  • 一旦传输到达一个音符的预定时间,该MIDI值将被发送到合成器
  • 由于Synth基本上是一个带有信封生成器的AudioWorkletNode,因此Synth接收MIDI音符并触发内部声音生成(通过信封)。因此,在特定时间点的MIDI音符会触发特定长度的声音生成(这将是广告部分)。在您的示例中,即使MIDI音符的持续时间只有1ms,声音生成也会保持至少1.001秒(释放加上1毫秒的MIDI持续时间)。让我们进一步细分一下:
    • MIDI音符在想象的传输时间线上有一个起点和终点
    • 开始触发信封的广告部分
    • End触发信封的R部分
    • 一旦MIDI音符触发了封套,声音就会产生
  • 那么,当你停止传输或序列本身时,会发生什么? 如果MIDI音符已触发信封,信封将接收MIDI结束触发器并触发释放信封

    因此,Synth始终会有一个尾声,因为MIDI音符并不确定Synth的起点和终点,而是触发信封的一部分。所以实际上,你的合成器产生了声音,这既不与传输有关,也不可能

    希望这个解释能对你有所帮助。如果我误解了你,我很乐意纠正。

    使用Tone.Transport.pause()

    如果您有一个“暂停播放”类的播放/暂停按钮,请参见下面的示例:

    $( '.pause-play' ).on('click', function(e) {
    
        if (Tone.Transport.state === "paused" ) {  
              Tone.Transport.start("+0.1") })
        else {
              Tone.Transport.pause()  }
        }
    )
    

    我想您必须停止序列本身,因为它没有与传输同步。因此,在按钮回调中使用
    sequence.stop()
    。我浏览了api方法,从概念上看,我似乎遗漏了一些东西。停止序列似乎会完全终止序列,使其无法重新启动