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

2023-12-21

简而言之,按下按钮我想使用PolySynth and a Sequence。如果用户反复按下按钮,我希望停止正在播放的内容,然后重新开始。

问题:无论我尝试什么,我都无法完全取消/静音之前播放的音符,以防序列再次启动(再次单击按钮)。这很可能是由于包络的衰减/维持造成的。

我的合成器:

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 是如何产生声音的。

  1. 您正在将 Synth(它获取 MIDI 音符并生成声音)连接到输出
  2. 您正在传输上安排一些 MIDI 音符
  3. 你开始运输
  4. 一旦传输达到音符的预定时间,该 MIDI 值就会发送到合成器。
  5. 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:
    • MIDI 音符在假想的传输时间轴上有一个起点和终点。
    • Start 触发 Envelope 的 ADS 部分。
    • End 触发包络的 R 部分。
    • 一旦您的 MIDI 音符触发了包络,就会生成声音。

那么,当你停止运输或序列本身时,会发生什么? 如果 MIDI 音符已触发包络,则包络将接收 MIDI 结束触发器并触发释放包络。

因此,您的合成器总会有拖尾声音,因为 MIDI 音符无法确定您的合成器的起点和终点,但会触发您的包络的部分内容。所以实际上你的合成器创造了声音,它既不依赖于传输,也不可能依赖于传输。

希望这个解释对你有一点帮助。如果我误解了你的意思,我很乐意纠正。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Tone.js 完全停止所有播放声音 的相关文章

随机推荐