首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tone.js完全停止播放声音

Tone.js完全停止播放声音
EN

Stack Overflow用户
提问于 2020-09-21 14:27:28
回答 4查看 2.1K关注 0票数 4

简单地说,按一下按钮,我想用PolySynthSequence弹几个音符。如果用户重复按下按钮,我想要停止播放的任何内容,然后重新启动。

问题:,无论我尝试什么,我都不能完全取消/沉默之前播放的音符,以防序列再次启动(再次单击按钮)。这很可能是因为信封的衰败/维持。

我的合成人:

代码语言:javascript
复制
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

我的顺序:

代码语言:javascript
复制
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),
})

按照我的方式,这是一个事件处理程序:

代码语言:javascript
复制
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()
}

在开始播放之前,我怎么能完全杀死所有的声音(如果有的话)?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2020-09-30 14:48:27

简短回答

仔细想想,如果我正确地理解了你,这实际上是有意的行为。您正在触发合成器上的一个注释(基本上是一个AudioWorkletNode)。所以只要一个音符触发合成器,音符就消失了。阻止这个音符演奏的唯一方法是使合成器本身静音。

长答案

在你的评论中,你说你可能在概念上遗漏了一些东西,我认为你在正确的轨道上这样做。

让我们想想MIDI是如何产生声音的。

  1. 您正在连接一个合成器(它使用MIDI便笺并生成声音)到输出
  2. ,您正在调度传输
  3. 上的MIDI便笺,当传输到达预定时间后,MIDI值将被发送到Synth。
  4. ,因为合成器基本上是一个带有信封生成器的AudioWorkletNode,合成器接收该MIDI便条并触发内部声音生成(通过信封)。因此,一个MIDI音符在特定的时间点触发一个特定的声音生成长度(这将是广告部分)。即使在您的示例中,MIDI音符持续时间只有1ms,声音生成也至少要保持1.001秒(释放加1毫秒MIDI持续时间)。让我们再详细分析一下: MIDI音符有一个起点和结束点,在假想的传输中,timeline.
  5. Start触发Envelope.
  6. End的ADS部分触发Envelope.
  7. Once的R部分,MIDI的音符触发信封,声音得到generated.

所以,当你停止你的运输或序列本身,这会做什么?如果MIDI便条已经触发信封,则信封将接收MIDI末端触发器并触发释放信封。

所以,你的合成器总是会有尾声,因为MIDI音符并不决定你的合成器的起点和终点,而是触发了你的信封的一部分。所以,实际上,你的合成器创造了声音,它既不与运输有关,也不可能。

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

票数 2
EN

Stack Overflow用户

发布于 2022-06-25 22:51:20

该解决方案可能很难在较长的序列中实现,但在您的情况下,它应该可以工作。我曾挑战过相当类似的问题,而且成功了。

polySynth的问题是,您只能添加音符,而这些音符是播放的。但是对于正常的合成器来说,用空音符覆盖播放的音符是可以“杀死声音”的。

代码语言:javascript
复制
// 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();

可以同时播放多个合成器,因此您可以手动创建多声子合成器。

代码语言:javascript
复制
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);

构建序列要复杂得多,但是您可以通过在play函数的开头添加"soundKiller“来静音播放序列。重要的是:不要声明序列,然后通过调用“传输”来播放它,只需在事件处理程序中播放注释(因为--正如另一个人已经写过的那样--调用它之后传输不能停止)。

票数 1
EN

Stack Overflow用户

发布于 2022-03-10 13:43:03

音符继续播放,因为传输在触发后和释放之前停止。因此,一个解决方案是在您按下“停止”按钮时触发所有注释的释放。我在使用坦比安/钢琴时遇到了一个类似的问题(基于Tonejs)。

代码语言:javascript
复制
    Tone.Transport.toggle()
    if (Tone.Transport.state === 'stopped') {
      for (let i=9; i<97; i++) {
        piano.keyUp({midi: i}, '+0')
      }
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63994325

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档