作为音乐音序器的Petri网
Petri Nets as a Music Sequencer

原始链接: https://blog.stackdump.com/posts/petri-net-sequencer

beats.bitwrap.io 上的音乐音序器能够生成基于种子的完整曲目(涵盖从电子舞曲到爵士乐的各种风格),且无需依赖传统的数字音频工作站(DAW)、钢琴卷帘或人工智能。它利用的是“佩特里网”(Petri nets)——一种由“库所”(圆圈)和沿“变迁”(箭头)移动的“令牌”组成的数学模型来触发事件。 在该系统中,每种乐器都由一个圆圈环表示。在环中循环的令牌会根据比约克隆德(Bjorklund)算法触发音符或节奏。由于这些圆环并行运行,该音序器能自然地产生复杂的复节奏。为了管理乐曲结构(如跌落或静音),开发者实现了“控制网”,利用倒计时器和抑制弧来触发指令,从而显著优化了文件大小和复杂度。 通过将佩特里网执行器作为系统调度程序,该音序器实现了完美且可复现的同步。令牌的状态决定了整个演奏过程,确保相同的种子总是产生相同的结果。该项目基于原生 JavaScript 和 Tone.js 构建,证明了一个 60 年前的数学概念——圆圈与箭头——可以成为生成式音乐创作中一种优雅且高度灵活的基础。

Hacker News 最新 | 往日 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 佩特里网(Petri Nets)作为音乐定序器 (stackdump.com) 10 分,m_kos 发布于 2 小时前 | 隐藏 | 往日 | 收藏 | 讨论 | 帮助 考虑申请 YC 2026 年秋季批次!申请截止日期为 7 月 27 日。 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文
Petri Nets as a Music Sequencer ← Home

Go to beats.bitwrap.io. Pick a genre — techno, jazz, ambient, drum & bass, 19 in total. Hit Generate. You'll hear a full track: drums, bass, melody, arpeggios. Change the seed, get a different track. Replay the same seed, get the exact same one.

There's no piano roll behind this. No timeline grid, no DAW. The whole thing runs on Petri nets — circles connected by arrows, with tokens moving through them. Every note is literally a token moving one step through the diagram.

A Drum Machine Made of Tokens

Picture a ring of 8 circles connected by arrows. One dot — a token — sits at the first circle. Every tick, it hops to the next one. Some circles trigger a kick drum when the token lands. The rest are silent. The token goes around and around. You've got a beat.

The pattern of hits comes from the Bjorklund algorithm — it spreads K hits across N steps as evenly as possible. With 3 hits across 8 steps you get the tresillo, a rhythm that shows up everywhere from Afro-Cuban son to Rihanna.

Tresillo rhythm as a token ring

That ring of circles? It's called a Petri net. The circles are places, the arrows pass through transitions, and the dot is a token. That's the whole vocabulary. Change the numbers — 4 hits across 16 steps — and you've got four-on-the-floor techno. Same structure, different rhythm.

Each instrument gets its own ring. Kick, snare, hihat, clap — all running in parallel. Make the rings different lengths and they drift in and out of sync, giving you polyrhythm for free. A 6-step hihat over a 16-step kick sounds like the cross-rhythms in Afro-Cuban and West African music, because it is the same math.

Everything Is a Ring

Melodies work the same way. Instead of drum hits, each step carries a note — pitch, velocity, duration. The music theory picks notes that make sense over the chord (chord tones on strong beats, passing tones on weak beats, rests so it can breathe), and lays them out in a ring.

Bass lines? Ring. Arpeggios? Ring. Harmony pads? You guessed it.

Pick a genre — techno, jazz, ambient, drum & bass — and a preset fills in the details: scales, chords, drum patterns, how much swing, how much humanize. The generator assembles a bunch of rings, and the sequencer just... runs them. No AI, no samples — music theory and random numbers with a seed. Same seed, same track, every time.

From Loops to Songs

Loops are easy — tokens go around, patterns repeat. But a song needs intros, drops, breakdowns. The hihat should disappear for 8 bars, then come back. The bass should sneak in during the second verse.

So we added control nets — rings that don't make sound but fire commands like "mute the hihat" or "bring in the bass." A tiny stage director made of circles and arrows.

The first version was hilariously wasteful: a chain of 1,536 individual steps, one per tick, with a command every few hundred steps and nothing in between. It worked! But the project file was 22 MB for a 3-minute track.

The fix: countdown timers. Instead of 384 empty steps before a section change, we put 384 tokens in a single circle and drain one per tick. A special connection (called an inhibitor arc) holds back the control event until the countdown hits zero. Same result, way less diagram:

Before After
Places 37,148 800
Transitions 37,120 800
File size 22 MB 242 KB

One circle with many tokens does the job of many circles with one token each. Petri nets are flexible like that.

Transitions Are Just More Net

Auto-DJ regenerates a new track at the boundary, and we wanted a curated filter sweep, white-noise wash, or riser to land on the downbeat — not race the project swap from the main thread.

The first attempt coordinated main-thread timers against worker-side regen state. It mostly worked, except when a user gesture overlapped the boundary and the macro got silently dropped. We were fighting the runtime.

The fix was to stop treating transitions as a side channel. Each Auto-DJ transition is now injected as a one-transition control net with a fire-macro binding. t0 fires on tick 1 of the new track; the worker emits control-fired; the main thread runs the macro through the normal queue. Tick-synchronized by construction, because the Petri net executor is already the scheduler.

Two timing bugs — the project-swap race and the macro-queue drop — collapsed into one piece of structure. The transition is just another token moving through the graph. Details in the v1.1.0 release notes; the curated transition pool itself shipped in v1.0.8.

What the Structure Gave Us

The token state is the only state, so the same seed produces the same track on any machine — no hidden counters, no drift. The same diagram that runs the music can be drawn on screen and watched: when something sounds wrong, we can see a token stuck in the wrong place or a ring out of phase. And because each instrument is its own net and song structure is a separate layer, pulling one out or adding another doesn't break anything else. None of this took extra work; it's just what falls out of having a single primitive carry concurrency, state, and scheduling.

Try It

beats.bitwrap.io — 19 genres, all client-side, nothing to install.

A huge shoutout to Tone.js, which does all the heavy lifting on the audio side. Petri nets decide what plays and when — Tone.js makes it actually sound good. Polyphonic synths, reverb, compression, sub-millisecond scheduling — we got all of that essentially for free. It's one of those libraries where you keep expecting to hit a wall and never do.

The Petri net executor is ~400 lines of vanilla JS, with another ~700 in the sequencer worker. The rest — music theory, generators, UI — is bigger, but none of it is framework code. No npm, no bundler. Tone.js from CDN, a Go server that serves static files, and a 60-year-old idea about circles and arrows that turned out to be a pretty good sequencer.

Source: github.com/stackdump/beats-bitwrap-io

For the formal theory behind why token flow works as a computational model, see Declarative Differential Models. To build and simulate your own nets, try pflow.xyz.

联系我们 contact @ memedata.com