Petri网作为音乐音序器
摘要
这篇博客文章描述了一个基于网页的音乐音序器,它使用Petri网而非传统时间线,通过令牌在网络中移动,从流派预设和种子生成完整音轨。文章涵盖了技术细节,包括控制网络和倒计时定时器来管理歌曲结构。
暂无内容
查看缓存全文
缓存时间: 2026/08/07 17:11
# 作为音乐音序器的 Petri 网
来源:https://blog.stackdump.com/posts/petri-net-sequencer
← 首页 (https://blog.stackdump.com/)
前往beats\.bitwrap\.io (https://beats.bitwrap.io/)。选择一个流派 — techno、jazz、ambient、drum & bass,共 19 种。点击 Generate。你会听到一首完整的曲目:鼓、贝斯、旋律、琶音。更换 seed,得到不同的曲目。重放相同的 seed,得到完全相同的曲目。
这背后没有钢琴卷帘。没有时间线网格,没有 DAW。整个系统运行在 Petri 网上——由箭头连接的圆圈,令牌在其中移动。每一个音符实际上就是一个令牌在图中移动一步。
## 一台由令牌构成的鼓机
想象一个由 8 个圆圈通过箭头连接而成的环。一个点——也就是令牌——位于第一个圆圈。每经过一个 tick,它就跳到下一个圆圈。当令牌落在某些圆圈上时,会触发底鼓。其余圆圈则静默。令牌一圈一圈地循环。于是你就有了一段节拍。
触发模式来自Bjorklund 算法 (https://en.wikipedia.org/wiki/Euclidean_rhythm)——它将 K 次触发尽可能均匀地分布在 N 个步骤中。在 8 个步骤中分布 3 次触发,你会得到tresillo (https://en.wikipedia.org/wiki/Tresillo_(rhythm)),这是一种从非洲-古巴颂乐到 Rihanna 的音乐中无处不在的节奏。
作为令牌环的 Tresillo 节奏
那个圆圈环?它被称为**Petri 网**。圆圈是*库所*,箭头穿过*变迁*,而点是*令牌*。这就是全部词汇。改变数字——在 16 个步骤中分布 4 次触发——你就得到了 four-on-the-floor techno。结构相同,节奏不同。
每种乐器都有自己的环。底鼓、军鼓、踩镲、拍手——全部并行运行。让不同环的长度不同,它们会逐渐漂移并不同步,从而免费获得**复节奏**。在 16 步底鼓之上叠加一个 6 步踩镲,听起来就像非洲-古巴和西非音乐中的交叉节奏,因为它*确实*是相同的数学。
## 一切都是环
旋律以同样的方式工作。每个步骤不是触发鼓声,而是携带一个音符——音高、力度、时值。乐理会选择在和弦上合理的音符(强拍用和弦音,弱拍用经过音,加入休止符以便呼吸),并将它们排列成一个环。
贝斯线?环。琶音?环。和声垫?你猜对了。
选择一种流派——techno、jazz、ambient、drum & bass——一个预设会填充细节:音阶、和弦、鼓模式、多少 swing、多少 humanize。生成器组装一系列环,音序器只是……运行它们。没有 AI,没有采样——乐理和带 seed 的随机数。相同的 seed,每次得到相同的曲目。
## 从循环到歌曲
循环很简单——令牌循环,模式重复。但一首*歌曲*需要前奏、Drop、Breakdown。踩镲应该消失 8 个小节,然后回来。贝斯应该在第二段主歌悄悄进入。
于是我们添加了**控制网**——这些环不发声,但会发出“静音踩镲”或“引入贝斯”之类的命令。一个由圆圈和箭头组成的小小舞台导演。
第一个版本浪费得令人捧腹:一条由 1,536 个独立步骤组成的链,每个 tick 一个步骤,每隔几百个步骤才有一条命令,其余部分什么都没有。它确实能工作!但一个 3 分钟的曲目工程文件有 22 MB。
解决办法:**倒计时定时器**。不是在段落切换前放置 384 个空步骤,而是将一个圆圈中放入 384 个令牌,每个 tick 消耗一个。一种特殊的连接(称为*抑制弧*)会阻止控制事件,直到倒计时归零。结果相同,图却简洁得多:
| | 之前 | 之后 |
|------------------------------|------|------|
| Places | 37,148 | 800 |
| Transitions | 37,120 | 800 |
| 文件大小 | 22 MB | 242 KB |
一个带有许多令牌的圆圈,完成了许多各自带一个令牌的圆圈的工作。Petri 网就是如此灵活。
## 过渡也是更多的网
Auto-DJ 会在边界处重新生成新曲目,而我们希望精调的滤波扫频、白噪声冲刷或 riser 正好落在强拍上——而不是与主线程的工程切换赛跑。
最初的尝试是在主线程定时器与 worker 端的重新生成状态之间进行协调。在大多数情况下是可行的,除非用户手势恰好与边界重叠,导致宏被静默丢弃。我们在与运行时对抗。
解决办法是停止将过渡视为旁路通道。每个 Auto-DJ 过渡现在都以一个单变迁控制网注入,并带有`fire-macro`绑定。`t0`在新曲目的第 1 个 tick 触发;worker 发出`control-fired`;主线程通过正常队列运行宏。由于 Petri 网执行器本身就是调度器,因此在构造上就是 tick 同步的。
两个时序 bug——工程交换竞争和宏队列丢弃——被合并为一个结构体。变迁只是另一个在图中移动的令牌。详情请参阅v1\.1\.0 发布说明 (https://github.com/stackdump/beats-bitwrap-io/releases/tag/v1.1.0);精选过渡池本身在v1\.0\.8 (https://github.com/stackdump/beats-bitwrap-io/releases/tag/v1.0.8) 中发布。
## 这个结构带给我们的东西
令牌状态是唯一的状态,因此相同的 seed 在任何机器上都会产生相同的曲目——没有隐藏计数器,没有漂移。用于运行音乐的同一个图可以绘制在屏幕上并实时观察:当某些声音不对时,我们可以*看到*令牌卡在错误的位置,或某个环相位错位。而且因为每种乐器都有自己的网,歌曲结构又是独立的一层,取走一个或添加另一个不会破坏其他任何东西。这些都不需要额外的工作;它们只是由一个单一原语同时承载并发、状态和调度时自然涌现出来的。
## 试试看
beats\.bitwrap\.io 演示
beats\.bitwrap\.io (https://beats.bitwrap.io/)——19 种流派,全部在客户端运行,无需安装任何东西。
衷心感谢Tone\.js (https://tonejs.github.io/),它承担了音频侧的所有繁重工作。Petri 网决定*演奏什么*和*在何时演奏*——而 Tone\.js 让声音真正好听。复音合成器、混响、压缩、亚毫秒级调度——我们几乎免费得到了这一切。它是那种你一直以为会撞上瓶颈却永远不会撞上的库之一。
Petri 网执行器大约 400 行原生 JS,另有约 700 行在音序器 worker 中。其余部分——乐理、生成器、UI——更大,但没有一行是框架代码。没有 npm,没有打包器。Tone\.js 来自 CDN,一个提供静态文件的 Go 服务器,以及一个关于圆圈和箭头的 60 年前的想法——事实证明它是一个相当不错的音序器。
来源:github\.com/stackdump/beats\-bitwrap\-io (https://github.com/stackdump/beats-bitwrap-io)
关于令牌流为何能作为计算模型的形式化理论,请参阅声明式微分模型 (https://blog.stackdump.com/posts/declarative-differential-models)。要构建和模拟你自己的网,试试pflow\.xyz (https://pflow.xyz/)。
×
### 在 Mastodon 上关注
相似文章
构建 Groovie:一款先进的基于 Web 的鼓机 / 节拍音序器
博客文章介绍 Groovie,一款开源、免费的基于 Web 的鼓机和节拍音序器,拥有150多种采样、最多32个模式、时间线音序及效果,使用 JavaScript 和 Web Audio 构建。
在浏览器中使用 Musical Spirograph 进行生成性音乐创作
Musical Spirograph 是一款基于浏览器的工具,允许用户通过交互式数学模式创建生成性音乐作品,同时支持自定义声音和视觉参数。
MuseNet
OpenAI 发布了 MuseNet,一个基于 GPT-2 架构的深度神经网络,通过从数十万个 MIDI 文件中学习模式,能够生成 4 分钟的音乐作品,包含 10 种乐器。该模型可以结合多种音乐风格并以新颖的方式融合它们。
看见声音
Mariano Salcedo 是 MIT 新设音乐技术与计算研究生项目的首批学生之一,他正在利用神经元胞自动机生成由音乐音频流驱动的自再生视觉作品。
面向程序员的音乐理论
本文从第一性原理出发,探讨如何用编程理解音乐理论,展示声音如何被表示为数字,并通过代码片段构建音阶与和弦。