构建 Vue.js 钢琴、斯克里亚宾的联觉、Tone.js 中的合成器/采样器、学习音阶和琶音等等!Sforzando 目录 我看到的只有金发、棕发、红发…… 简介 我目前的想法和实验 Sforzando 的下一步计划是什么? 想法、建议、反馈? 链接

2025-06-10

关于构建 Vue.js 钢琴、斯克里亚宾的联觉、Tone.js 中的合成器/采样器、学习音阶和琶音等等!

强音

目录

我看到的都是金发、黑发、红发……

介绍

我目前的想法和实验

Sforzando 的下一步计划是什么?

想法、建议、反馈?

链接

有遗漏或错误的地方?本文来源于 Github

请随时打开问题发送 PR

强音

音乐符号 sforzando 的图片,大致翻译为

目录

返回顶部

我看到的都是金发、黑发、红发……

这篇文章的代码量相当大,但如果你不是程序员,那么至少有几个部分仍然可以欣赏,特别是如果你是一名音乐家,或者只是对音乐感兴趣。

我甚至认为上面链接的部分比与代码相关的部分更有趣。:)

返回顶部


这是电影《黑客帝国》中著名的滚动代码场景的图片 - 许多重叠的柱子、无尽的绿色溪流、以及外星人模样的人物。

我看到的都是 90 年代的特效。


介绍

哈欠!介绍部分可能是最无聊的部分了——只是提醒一下而已。

本文介绍了我的(众多)宠物项目之一 - Sforzando。

由于我在升级操作系统时忘记备份少量文件和文件夹(是的......),因此初始原型丢失了 - 只有视频记录幸存下来。

我打算用力量把它带回来。或者应该说,用强音。:)

我不能100%确定它会变成什么样,但基本上我设想的是某种应用程序,可以让你以多种多样且高度互动的方式尝试音乐理论、和声和作曲。它目前仍处于早期原型阶段。

与我的大多数项目一样,我创建它的原因是:

  • 只是因为我对音乐理论、和声和作曲感兴趣
  • 尝试新的想法、新技术、新工艺等。
  • 因为我肯定会从中学到一些东西,而且我喜欢学习

与我的大多数项目不同,我决定将它开源。多年来,我一直不敢分享我的代码,但如果我想找到工作,就需要开始撰写和分享我的项目(以及为其他人的项目做贡献),所以。

您正在使用什么库?

最值得注意的是:

  • TonalJS,一个音乐理论库。
  • ToneJS,一个网络音频框架。
  • VuejS,一个 UI 库。

为什么叫这个名字?

Sforzando 是一个音乐术语(意大利语),据我所知,它的意思类似于“突然的力量”。它强调一个音符——基本上是指示演奏者把这个音符演奏得比周围的其他音符更响/更用力,以使它更加突出

我希望这款应用也能从其他同类应用中脱颖而出,至少最终能做到!正因如此,我觉得这个名字还不错。

返回顶部


这是在比利时孔蒂希拍摄的一架立式钢琴的照片,从钢琴的右侧/高音部分拍摄。随着八度音阶的下降,音符变得越来越模糊。

我有 88 把钥匙,但我仍然无法打开我的门。


我目前的想法和实验

钢琴组件

这是浏览器窗口的屏幕截图,其中 Vue 开发者工具已打开,并突出显示了 Sforzando Piano Vue 组件。钢琴音阶范围从 A1 到 C#5。开发者工具中可以看到各种数据和计算属性,例如八度起始、八度结束、数值八度、钢琴状态等等。

首先,我着手创建一个可以生成钢琴的 UI 组件。

我在 CodePen、JSFiddle 和 CodeSandbox 上寻找想法和灵感一段时间,然后开始着手创建自己的任务。

它是完全动态的,因此您可以告诉它应该从哪个八度开始和结束等等。

它主要使用CSS 网格和少量Flexbox

示例用法:

<piano
  octave-start="3"
  octave-end="6"
  note-start="A"
  note-end="C" />
Enter fullscreen mode Exit fullscreen mode

返回顶部

使用 Tone.js 播放音乐

现在我有了一个动态钢琴组件,我的下一个目标是让 Tone.js 播放一些音乐(然后在钢琴上显示所述音乐)。

短暂的分心……

因此,像其他心无旁骛的人一样,我直接走到钢琴前,写了一个和弦进行曲:

  1. 厘米 (i
  2. 格(V
  3. Bb ( VII)
  4. F(V / VII
  5. 抗体 ( VI)
  6. 厘米 (i
  7. F# 7 维 ( vii° / V)
  8. Gsus4 ( Vsus4), G ( V)

...这没什么特别的,但这里的目标不是写出好的音乐。

注意:我对自己的和弦进行的和声分析很可能是不正确的……

然后我将这些和弦分解成一些基本的琶音,这里它们以代码表示:

[
  ["C2", "D#2", "G2", "C3", "G2", "D#2"],
  ["B1", "D2", "G2", "B2", "G2", "D2"],
  ["A#1", "D2", "F2", "A#2", "F2", "D2"],
  ["A1", "C2", "F2", "A2", "F2", "C2"],
  ["G#1", "C2", "D#2", "G#2", "D#2", "C2"],
  ["G1", "C2", "D#2", "G2", "D#2", "C2"],
  ["F#1", "C2", "D#2", "F#2", "D#2", "C2"],
  ["G1", "C2", "D2", "G2", "D2", "B1"]
];
Enter fullscreen mode Exit fullscreen mode

当然,我选择了 C 小调,因为这是唯一真正好的调

返回顶部


路德维希·凡·贝多芬的大型金属雕像周围散落着几座较小的金色雕像。巨大的雕像表面覆盖着一层绿锈——一层绿色的氧化层,通常形成于铜和黄铜等金属上。较小的雕像则呈金色,略显模糊。

贝多芬对我所选择的调的反应。


采样或合成...

合成器很酷(哦,我在骗谁呢 - 它们真是太棒了),当我的和弦进行被输入到合成器中时,听起来非常完美(见上文)。

但我很快就决定要使用真正的钢琴样本(主要是因为我自己就是一名钢琴家 - 这种声音听起来很舒服),所以我找到了一些免费的样本并将它们连接起来:

太棒了,只需稍加努力,我们的小和弦进行听起来就更加优美了。

什么是合成器?如果你想了解合成器,那就去看看 Ableton 全新的“学习音乐”网站吧……

...当然是在阅读了这篇文章之后。

返回顶部


从上方看,管弦乐队的弦乐部分正在演奏音乐。

问:半音的定义是什么?答:两位小提琴手齐奏。


显示钢琴上的音乐

现在我需要一种方法来突出显示钢琴上的活动音符。

首次尝试

我最初实现这个功能简直是异端邪说——居然在 Vue.js 里操作 DOM!真是令人不寒而栗。但我实在不知道还能怎么让它工作。

无论如何,它最终看起来有点像这样:

Transport.scheduleRepeat(time => {
  sampler.triggerAttackRelease(this.activeNote, "8n");

  Draw.schedule(() => {
    const notes = document.querySelectorAll("li.note");

    if (notes) {
      for (let i = 0; i < notes.length; i++) {
        notes[i].classList.remove("active");
      }
    }

    document
      .querySelector(`li.${this.activeNote}`)
      .classList.add("active");
  }, time);

  this.step();
});
Enter fullscreen mode Exit fullscreen mode

我知道,这真的很糟糕,不是吗?但它在初步的概念验证实施中确实有效。嗯,基本上……

这是一个不同步的注释,所以我不得不添加一个 hack - 一个返回前一个注释的计算属性,然后我将类添加到其中

是啊,谁能想到情况会变得更糟呢?

亲爱的读者,不要害怕,我们可以做得更好……我们马上就会做到。

Tone.Draw 有什么用处?

如果您感到疑惑 - 传递给的回调在Web WorkerTransport.schedule中运行,并且整个库(实际上是任何音乐应用程序或库)确实对时间敏感/对性能至关重要

如果我们在回调中执行任何繁重的操作,可能会(而且很可能会)破坏性能。此外,这些事件可以提前安排在您实际听到它们之前,也可以在后台选项卡中运行(当没有任何内容可看时)。

Tone.Draw通过使用requestAnimationFrame解决了这个问题。它会尽可能在 Tone 事件发生时触发我们的绘制代码。可能稍早或稍晚一些,但总是非常非常接近。

返回顶部


一张格式/缩进糟糕的计算机代码图片。它足以让你眼花缭乱。幸运的是,这段文字不会造成这种情况。

甚至上面的代码也比 Vue 中的 DOM 操作更好。


第二次尝试

我寻求建议,有人向我建议使用Vue.observable来存储活动键状态。

对于那些不知道的人来说,Vue.observable这是用来让你data在内部做出反应的 - tl;dr:这是魔法。

这就是我最终得到的结果:

import Vue from "vue";
import { createRange } from "./music";

const notes = createRange("A0", "C8");

const noteMap = notes.reduce((map, note) => {
  map[note.name] = false;
  return map;
}, {});

const pianoState = new Vue.observable(noteMap);

export default pianoState;

export function reset() {
  for (const note of notes) {
    pianoState[note.name] = false;
  }
}
Enter fullscreen mode Exit fullscreen mode

它构造一个如下所示的对象:

{
  "A0": false,
  "A#0": false,
  "B0": false,
  "C1": false
  // etc.
}
Enter fullscreen mode Exit fullscreen mode

这是三角钢琴上每个音符的一个键值对(A0-C8,88 个键)

如果某个键是,true那么该音符就被“保持”(因此应该突出显示),如果是,false那么情况正好相反。

因为它是一个 Vue 包装的反应对象,所以我们可以在计算属性等中使用它,并且每当它发生变化时它就会触发重新渲染 - 完美!

返回顶部


一张烧杯浸入某种盛有液体的玻璃容器的照片。看起来科学正在酝酿。我们或许应该先退一步。

根据初步分析,Vue 反应性比上述反应有趣 172,643%。


巴赫分心——阅读 midi 文件

为了测试这套系统,我决定放一些真正的音乐进去,所以我选了一首巴赫的前奏曲——事实上,它是最著名的一首。你可能以前就听过。

将 midi 连接到我的采样器相当简单,最终看起来像这样:

midi.tracks.forEach(track => {
  track.notes.forEach(note => {
    Transport.schedule(() => {
      piano.triggerAttackRelease(
        note.name,
        note.duration,
        Tone.now(),
        note.velocity
      );
    }, note.time + Tone.now() + 0.5);
  });
});
Enter fullscreen mode Exit fullscreen mode

当然,我们还需要将其与我们新的Vue.observable动力反应钢琴状态联系起来。

几次尝试之后,我决定采用这种方法,进行 3 次单独Transport.schedule调用。不知为何,它似乎比我尝试过的其他方法效果更好,说实话,我不明白为什么:

midi.tracks.forEach(track => {
  track.notes.forEach(note => {
    Transport.schedule(() => {
      piano.triggerAttackRelease(
        note.name,
        note.duration,
        Tone.now(),
        note.velocity
      );
    }, note.time + Tone.now() + 0.5);

    Transport.schedule(time => {
      Draw.schedule(() => {
        pianoState[note.name] = true;
      }, time);
    }, note.time + Tone.now() + 0.5);

    Transport.schedule(time => {
      Draw.schedule(() => {
        pianoState[note.name] = false;
      }, time);
    }, note.time + note.duration + Tone.now() + 0.5);
  });
});
Enter fullscreen mode Exit fullscreen mode

返回顶部


这张 Midi 键盘的照片是从侧面拍摄的,它放在窗边的桌子上。背景是一条空荡荡的街道。

我想要一个。我想要一个。我想要一个。


音乐的色彩

所以,我让它在基本层面上工作,但所有的注释都以红色突出显示,这太糟糕了。

我去 Google 查看是否有任何现有的将频率映射到颜色的技术。

光影键盘

这张 Midi 键盘的照片是从侧面拍摄的,它放在窗边的桌子上。背景是一条空荡荡的街道。

据说,俄罗斯作曲家亚历山大·斯克里亚宾患有联觉症。如果你没听说过,它的基本含义是两种感觉的“连接线”交叉了。

对于斯克里亚宾来说,他的听觉和视觉受到了影响,因此对他来说,音符是有颜色的。

在此基础上,他开发了一个系统——Clavier à lumieères(带灯的键盘)。

谢尔盖·拉赫玛尼诺夫在他的自传《回忆录》中记录了他与斯克里亚宾和尼古拉·里姆斯基-科萨科夫 关于斯克里亚宾对色彩和音乐的联想的对话。

拉赫玛尼诺夫惊讶地发现里姆斯基-科萨科夫同意斯克里亚宾关于音调与色彩关联的观点;拉赫玛尼诺夫本人持怀疑态度,他提出了明显的反对意见,认为这两位作曲家在所涉及的色彩上并不总是意见一致。

两人都坚持认为D大调是金棕色;但斯克里亚宾将降E大调与红紫色联系起来,而里姆斯基-科萨科夫则偏爱蓝色。然而,里姆斯基-科萨科夫抗议说,拉赫玛尼诺夫歌剧《吝啬的骑士》中的一段话符合他们的说法:老男爵打开宝箱,露出在火炬光芒下闪闪发光的黄金和珠宝的场景是用D大调写的。

斯克里亚宾告诉拉赫玛尼诺夫,“你的直觉在无意识中遵循着你试图否认其存在的规律。

来源:维基百科

这是一个非常酷的系统,我想找到一些方法在我的应用程序中使用它,但我选择了另一种技术......

返回顶部


钢琴键盘的一个八度,琴键的颜色是根据亚历山大·斯克里亚宾 (Alexander Scriabin) 因联觉而对音符的感知而定的。

如何让您的孩子对学习钢琴 101 产生兴趣。


将声波映射到光波

您可能知道也可能不知道,声音本质上是振动,我们使用赫兹(每秒周期数)来测量振动。

例如:

  • 音符 A4(中央 C 上方的 A)为 440 Hz
  • 音符 A5(下一个 A)是 880 Hz

光由波组成,波具有长度,我们用纳米来测量(至少对于可见光谱,其位于 400-700nm 之间)。

如果我们将其转换为赫兹,那么我们得到 430-750THz(1Hz = 10 12 Hz)。

哎哟!好多赫兹啊。

抱歉。刚才说到哪儿了?啊,是的。

所以,基本上我们可以直接将声音频率映射到光。

我尝试自己实现该算法,但遇到了一些问题,所以我只是复制粘贴了一些颜色值。

不幸的是,这意味着我要放在这里的沙箱并不存在。:(


CSS 的屏幕截图将音符映射到颜色,顺序与可见光谱相同,从 F 调(深红色)开始到 F(深紫色)。

看看复制粘贴的力量。


带有 SVG 的动画乐谱

我(刚刚)开始尝试的另一件事是使用MuseScore生成SVG,然后为其制作动画。

此外,我还尝试从头开始生成我自己的基于 SVG 的乐谱。

这个实验实际上是为我的另一个早期的音乐项目而做的,但这并不重要,因为所述实验无疑也会以某种方式、形式进入到这个项目中。

不过,我不得不说,我之前实际上从未使用过 SVG,所以这对我来说都很新,但基于我非常有限的接触 - 它非常酷。

此外,您一定要查看SVG.jsAnime.js

返回顶部


这张彩虹照片拍摄于夏威夷毛伊岛。天空多云。郁郁葱葱的绿色平原连绵起伏,还有少量丘陵,甚至有些山地。

有一片土地,我曾在一首摇篮曲中听说过……


Sforzando 的下一步计划是什么?

反射

不幸的是,我的许多项目最终都夭折了,被埋没了;通常隐藏在私人存储库中。

发生这种情况通常是由于以下一个或多个原因:

  • 我的愿景太宏大了
    • 和/或范围蔓延——试图过快地添加太多内容
  • 过早重写整个项目
    • 和/或中途改变技术选择
  • 苦苦思索如何构建 API 或模式等。

但我真的很想继续做这个。在我所有新旧项目中,这大概是我第二喜欢的想法了。

我对音乐充满热情。

所以这就是我打算做的......

是的,我会继续尝试随机的想法,例如为 SVG 制作动画、解析 MIDI 文件以及其他任何想到的东西,但同时,我会投入一些时间和精力来实际规划设计这个应用程序,而不是盲目地编写几个月的代码,直到我得到一些没有记录且无法维护的有机生长的野兽,甚至我自己都不完全理解。

返回顶部

未来的想法

每一个真正有文化的音乐学生都知道……

我想尽快添加一些与和弦、音阶、琶音等相关的东西(最初的原型就有)。

就应用程序的实际音乐(即声音制作)部分而言:

  • 可以生成和演奏琶音的琶音器
  • 让应用程序为你播放音阶的方法
  • 演奏常见和声序列/和声进行的体系
  • ETC。

以及学习/视觉辅助工具:

  • 一些有助于学习和弦转位的东西
  • 以五度圈为指导学习调号
  • 音阶指法图
  • ETC。

更不用说作曲辅助工具了:

  • 突出钢琴部分的乐器范围
  • ETC。

返回顶部

生命之环——呃,五度

我一直在研究五度圈组件(也是 SVG),并且我对使用它来可视化和声进行、全音阶和声、调号等有各种想法。

老实说,五度圈是最令人着迷的东西,我强烈建议学习它。

直到你理解为止不要停下来

返回顶部


五度圈——一种直观的辅助工具,用于理解调之间的关系。12点钟位置是C大调和C小调,两者都没有临时记号。顺时针旋转纯五度音程会在调号上添加一个升号——G(1个升号)、D(2个升号);逆时针旋转纯四度音程会在调号上添加一个降号——F(1个降号)、Bb(2个降号)等等。

音乐™的万物理论............。


为人们心中的黑暗送去光明

如果可能的话,我绝对希望它对于音乐创作有用,但我真的不确定它将如何发挥作用。

传统上和个人方面,我一直偏爱SibeliusFinale等应用程序,但最近我越来越多地使用纸质文件,主要是因为这些应用程序不适用于我的操作系统,而且我发现很难使用MuseScore

前几天,我开始玩音序器和数字音频工作站,我不得不说我真的很喜欢他们的一些想法,并且不介意窃取其中的一些。

无论如何,音乐创作是我正在尝试重新开始的事情,所以当它达到更可用的状态时,我绝对会对该应用程序/工具进行测试。

返回顶部


一只苍老的手伸出去触摸一份手稿。

我没有什么妙语可说了。


如果您喜欢这篇文章并希望我写更多,那么表达您的喜爱,因为我花了几个小时才写完这篇文章,而我本可以用这些时间来完成我的项目,或者创作音乐,或者做其他事情。

返回顶部


想法、建议、反馈?

欢迎随时在这里给我留言或回复文章,但除此之外,我随时可以联系到:

  • 在 Discord 上(持续#2329)
  • 在 Github 上(持续)

如果您符合以下情况,我将非常乐意听取您的意见:

  • 你是一名音乐老师/学生,有想法
  • 你对我如何提高写作水平有什么反馈吗

否则,请关注我以获取更多有关以下内容的帖子(可能):

  • 此应用
  • 我的其他项目
  • Vue.js、Laravel 和其他简洁技术
  • 音乐创作与制作
  • 语言学习

返回顶部

链接

返回顶部


有遗漏或错误的地方?本文来源于 Github

请随时打开问题发送 PR

鏂囩珷鏉yu簮锛�https://dev.to/sustained/sforzando-an-app-for-learning-and-experimenting-with-music-theory-harmony-composition-44cm
PREV
The missing career path for software developers
NEXT
使用这些顶级免费概念模板来提高你的工作效率