用 tone.js 制作一架钢琴!钢琴

2025-06-10

使用 tone.js 制作钢琴!

钢琴

 

钢琴

这就是我们要构建的最终产品!您可以点击它,或者在键盘上输入匹配的字母。

什么是 Tone.js?

Tone.js 是一个非常流行的 Web Audio API 库,其GitHub 仓库中拥有超过 8000 个 star 。在 Web Audio API 出现之前,浏览器必须使用音频文件来播放声音和音乐。这不仅增大了应用程序的体积,而且修改声音意味着每次都需要引入不同的音频文件。那么,Web Audio API 能为我们做些什么呢?

Web Audio API 提供了一个强大且多功能的系统来控制 Web 上的音频,允许开发人员选择音频源、为音频添加效果、创建音频可视化、应用空间效果(例如平移)等等。

出处: https: //developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API

它的一个非常强大的功能是,现在只需 JavaScript 即可生成数字声音,无需使用音频文件!只需掌握一些音乐概念,例如振荡器和频率,我们就能创建各种符合我们需求的音频。使用纯 Web Audio API 会有些困难,因为它涉及一些底层概念,所以我们将在项目中使用 Tone.js,它可以抽象出底层方法。

HTML

<ul id="piano">
  <li data-note="C4" class="key">
    <div data-note="C#4" class="black-key">R</div>
    D
  </li>
  <li data-note="D4" class="key">
    <div data-note="D#4" class="black-key">T</div>
    F
  </li>
  <li data-note="E4" class="key">
    G
  </li>
  <li data-note="F4" class="key">
    <div data-note="F#4" class="black-key">U</div>
    H
  </li>
  <li data-note="G4" class="key">
    <div data-note="G#4" class="black-key">I</div>
    J
  </li>
  <li data-note="A4" class="key">
    <div data-note="A#4" class="black-key">O</div>
    K
  </li>
  <li data-note="B4" class="key">
    L
  </li>
</ul>

我们的标记相当简单。白键用“key”类表示,黑键用“black-key”类表示。注意,在HTML层次结构中,黑键被包裹在白键内部,以便相对定位。每个键还具有 data-note 属性,并带有相应的音符。

CSS

@import url('https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap');
 body {
     font-family: 'Roboto', sans-serif;
     display: flex;
     justify-content: center;
     align-items: center;
     min-height: 100vh;
}
 ul {
     list-style: none;
     display: flex;
}
 ul .key {
     position: relative;
     width: 60px;
     height: 180px;
     border: 1px solid black;
     border-right: none;
     background: #fffff0;
     border-radius: 5px;
     box-shadow: 0px 3px 5px #666;
     cursor: pointer;
     display: flex;
     justify-content: center;
     align-items: flex-end;
     padding-bottom: 10px;
     font-weight: bold;
}
 ul .key:last-child {
     border-right: 1px solid black;
}
 ul .black-key {
     position: absolute;
     top: -1px;
     left: 37.5px;
     width: 45px;
     height: 120px;
     background: black;
     border-radius: 5px;
     box-shadow: 0px 3px 5px #666;
     z-index: 999;
     display: flex;
     justify-content: center;
     align-items: flex-end;
     padding-bottom: 10px;
     color: white;
}

.key 为我们的白键设置样式。它用于align-items: flex-end将字母放置在键的底部。

JavaScript

// Tone.Synth is a basic synthesizer with a single oscillator
const synth = new Tone.Synth();
// Set the tone to sine
synth.oscillator.type = "sine";
// connect it to the master output (your speakers)
synth.toMaster();

const piano = document.getElementById("piano");

piano.addEventListener("mousedown", e => {
  // fires off a note continously until trigger is released
  synth.triggerAttack(e.target.dataset.note);
});

piano.addEventListener("mouseup", e => {
  // stops the trigger
  synth.triggerRelease();
});

// handles keyboard events
document.addEventListener("keydown", e => {
  // e object has the key property to tell which key was pressed
  switch (e.key) {
    case "d":
      return synth.triggerAttack("C4");
    case "r":
      return synth.triggerAttack("C#4");
    case "f":
      return synth.triggerAttack("D4");
    case "t":
      return synth.triggerAttack("D#4");
    case "g":
      return synth.triggerAttack("E4");
    case "h":
      return synth.triggerAttack("F4");
    case "u":
      return synth.triggerAttack("F#4");
    case "j":
      return synth.triggerAttack("G4");
    case "i":
      return synth.triggerAttack("G#4");
    case "k":
      return synth.triggerAttack("A4");
    case "o":
      return synth.triggerAttack("A#4");
    case "l":
      return synth.triggerAttack("B4");
    default:
      return;
  }
});
// when the key is released, audio is released as well
document.addEventListener("keyup", e => {
  switch (e.key) {
    case "d":
    case "r":
    case "f":
    case "t":
    case "g":
    case "h":
    case "u":
    case "j":
    case "i":
    case "k":
    case "o":
    case "l":
       synth.triggerRelease(); 
  }
});

让我们分解一下。前三行使用了 Tone.js 提供的方法并设置了声音。然后,我们将事件监听器附加到钢琴 div 上,它会使用事件冒泡来识别在监听到点击事件后被定位到的元素。我们获取元素的 data-note 属性来播放其声音。

我们无法对键盘事件做同样的事情,因为键盘按下时生成的事件对象与鼠标点击生成的事件对象不同。这就是为什么我们必须手动将键盘字母映射到相应的音符。

结局

希望这个演示易于理解,并能克服你探索 Web Audio API 的恐惧!如有任何疑问或想法,欢迎在评论区留言!感谢阅读这篇博客!😆😊😃

鏂囩珷鏉ユ簮锛�https://dev.to/shimphillip/building-a-piano-with-tone-js-5c2f
PREV
尝试学习 Go - 构建下载器 第 01 部分 尝试学习 Go
NEXT
保留一份吹牛文件 输入吹牛文件 帕累托原则频率 与您的经理合作 结束语