内容
# 鼓手 🥁
一个开源的AI鼓手,你可以与之对话并一起演奏。
说 *"嘿,给我一个像 Brick House 一样的节奏"*,一个节奏就会通过你浏览器中的真实TR-808 / LinnDrum / MPC60样本或真正的**声学鼓组**(Salamander Drumkit)播放,其中速度选择实际的软/中/硬录音,幽灵音符是真正的幽灵音符捕获,开帽从半开嘶嘶声逐渐变为完全开放的洗音效果,当你靠近时。说 *"更多高帽,让它有摇摆感"*,改变会在下一个小节边界生效,无缝衔接。
## 为什么存在
这是一个副项目,目标是**不取代鼓手**。目标是**在音乐创作中途为音乐家提供帮助**。
如果你是一位吉他手,正在演奏一个段落,当你停止演奏去点击鼓机UI或敲击垫模式时,你就已经离开了创作的流畅状态。这里,你只需要**说出你想要的**——“给我一个懒散的半时间 shuffle”,“更多幽灵音符”,“在每个节拍的第三个十六分之一上打开帽子”——并继续演奏,同时节奏在你身下重新调整。这就像编程鼓机和指挥现场鼓手的区别,后者永远不会厌倦“再来一次,但是更复杂一点”。
当需要录制真正的东西时,请雇佣真正的鼓手——他们会比这玩意儿演奏得更好。这玩意儿只是让你在那之前继续创作。
没有应用程序和UI需要学习:它是一个[MCP](https://modelcontextprotocol.io)服务器,因此任何MCP客户端——Claude Code、Claude Desktop——都是聊天界面。LLM根据自己的歌曲和音乐理论知识编写节奏;该服务器将其编译为[Strudel](https://strudel.cc)代码,并流式传输到本地浏览器页面,循环播放。
## 快速开始(克隆 → 演奏)
要求:macOS(Linux可能有效但未经测试),Node ≥ 20,当前Chrome/Safari,互联网连接(Strudel + 样本从CDN加载),以及MCP客户端。
```bash
git clone https://github.com/rh-adrian/drummy.git
cd drummy
npm install
npm run build
```
在Claude Code中注册(`-s user`使其在每个会话中可用):
```bash
claude mcp add -s user drummy -- node "$PWD/dist/index.js"
```
对于Claude Desktop或其他MCP客户端,请复制[.mcp.json.example](.mcp.json.example)到客户端的MCP配置中,并修复绝对路径。
然后开始演奏:
1. 在MCP客户端中启动新会话(服务器随之启动)。
2. 打开**http://localhost:4747**并点击**▶ 开始**——浏览器自动播放策略要求一次点击。保持标签页打开:它显示节奏作为实时阶梯网格(每行一个鼓及其全名和音量滑动条,鼓手计数头——Bar 1 · 1 e & a …——单元格由速度点亮,一个在时间中扫描的播放头)与速度、鼓组和连接状态,以及播放/暂停按钮和编译后的Strudel代码,隐藏在“显示代码”切换后面。**点击任意单元格以循环它:关闭 → 正常 → 应激 → 幽灵 → 关闭**;每行还有一个音量滑动条,一个**M**静音和一个**✕**清除按钮,具有**↩ 撤销**(您的最后~20页编辑)和**BPM输入**在传输中。所有内容都落在LLM工作的同一个节奏中(`trackGain`/`muted`显示为 `[vol N%]`/`[muted]`并在编辑中幸存),因此在调整后说“使其具有摇摆感”会保留您的调整。暂停被尊重:您自己的编辑会在后台更新网格;只有LLM播放新内容时才会恢复音频。节奏可以携带多达6个预先编写的**填充**,在循环结束时按非周期随机时间表替换(当节奏中有填充时,会出现“填充”切换)。
3. 请求一个节奏: *"给我一个像 Brick House 一样的节奏"*, *"一个尘土飞扬的90 BPM boom-bap节奏"*, *"四分之四的house节奏在124"*。
4. 迭代: *"更忙碌的高帽"*, *"在小鼓上添加幽灵音符"*, *"把它变成半拍"*, *"试试在909上"*, *"用声学鼓组演奏"*, *"把它放慢到95"*。
没有MCP客户端? `npm run dev:jam` 通过同一个页面播放一个罐装的节奏。
## 工具(LLM驱动)
| 工具 | 功能 |
|------|--------------|
| `play_groove` | 启动(或替换)循环节奏 — 鼓-标签网格符号或节奏JSON |
| `update_groove` | 播放节奏的部分编辑 — 仅发送更改的字段 |
| `set_tempo` | 平滑地更改BPM,而不重启循环或丢失小节相位 |
| `set_kit` | 相同的模式,不同的鼓组样本(鼓机或声学鼓组) |
| `list_kits` | 可用的银行及其声音描述 + 每个鼓提供的鼓 |
| `stop` | 静音;稍后的 `play_groove` 会重新开始 |
| `now_playing` | 当前状态:节奏,速度,鼓组,播放/停止,页面连接 |
工具描述教会模型鼓手词汇(鼓缩写,幽灵音符速度约定,摇摆语义,流派草图),因此任何前沿模型都可以驱动它,无需外部文档。
节奏是小节网格 — `resolution` 步/小节 × `bars` 。编写节奏的首选方式是 **网格符号**(v1.4):鼓-标签行,每个步骤一个字符,字母携带速度 — `X` 强调(1.0),`x` 正常(0.7),`o` 软(0.5),`g` 幽灵(0.25),`-`/`.` 静止,`|` 美容节拍分隔符:
```jsonc
{
"tempoBpm": 100,
"swing": 0.12, // 0–0.6, 步长的分数;延迟每个奇数步
"bank": "RolandTR808", // 参见 list_kits
"bars": 1, // 1–4
"resolution": 16, // 步/小节:8, 12, 16, 24, 32(12/24 = 三重奏感觉)
"grid": {
"hh": "X-x-|x-o-|X-x-|x-o-", // 强调不同 — 均匀速度听起来像机器人
"sd": "----|X--g|-g--|X---", // 强拍 + 幽灵音符
"bd": "X---|--x-|----|-x--"
}
}
```
列在行之间对齐,因此低音鼓,小鼓和帽子如何相互锁定在符号本身中可见 — 表示LLM推理鼓节奏的最佳表示 ([arXiv:2505.08203](https://arxiv.org/abs/2505.08203))。工具响应使用相同的符号渲染播放中的节奏(包括您的网格点击编辑)。
JSON `voices` 形式 (`hits` 具有精确的 `vel` 和每个打击的 `micro` 推/拉) 仍然是首选,用于超出四个字母的精细控制 — 使用一个或另一个调用:
```jsonc
"voices": [
{ "drum": "sd", "hits": [ { "step": 4 }, { "step": 12, "micro": 0.03 }, // 懒散的后拍
{ "step": 6, "vel": 0.25 } ] } // 幽灵音符
]
```
## 工作原理
```
MCP客户端(Claude Code / Desktop)— 聊天界面
→ MCP服务器(stdio) src/server/tools.ts 鼓手词汇工具
→ 节奏模式 + 编译器 src/core/* 节奏JSON → Strudel代码
→ HTTP+WS侧车 src/server/sidecar.ts 提供页面,推送代码
→ 浏览器页面 page/ @strudel/web 通过CDN,循环播放
```
所有内容都在MCP客户端启动的单个进程中运行。页面通过websocket连接回来,在 **下一个小节边界** 处应用传入的模式(保留Strudel的时钟阶段,因此交换是无缝的,从不丢失位置),跳动其状态,并自动重新连接。实时控制不是目标 — 在下一个小节顶部(~2–4秒)落地更改是您如何计算一个乐队。
## 配置
| 环境变量 | 默认值 | 含义 |
|---------|---------|---------|
| `AI_DRUMMER_PORT` | `4747` | 页面 + websocket侧车端口 |
在MCP注册中设置,例如
`claude mcp add -s user drummy -e AI_DRUMMER_PORT=5757 -- node "$PWD/dist/index.js"`。
## 故障排除
- **无声音** — 您必须在每次加载页面时点击 **▶ 开始** (浏览器自动播放策略)。标签页必须保持打开;音频在后台标签页中继续播放。还要检查页面自己的播放/暂停按钮(位于节奏旁边)是否未显示 ▶ — 它会在本地暂停,而LLM不知道重启。
- **"无鼓页面已连接"** — 工具结果已经说明:打开 http://localhost:4747 并点击开始,然后再次询问。
- **"端口4747已被占用"** — 另一个Drummy会话(另一个Claude窗口?)拥有该端口。一个端口一个会话:关闭其他会话,或给予此会话自己的 `AI_DRUMMER_PORT`。
- **无互联网** — 播放需要互联网:页面在运行时从unpkg加载 `@strudel/web`,从Strudel的CDN加载样本(参见许可)。离线模式需要提供样本,这在许可验证上被阻止([SAMPLES.md](SAMPLES.md))。
- **刚切换的鼓组第一次点击声音被剪切** — 在慢速连接上首次加载样本时可能会发生;下一个小节是好的。
- **页面显示已连接,但工具说不是** — 隐藏并停止的标签页超过5分钟后,其计时器会被Chrome节流。聚焦或重新加载标签页。
## 开发
```bash
npm test # vitest — 模式、编译器、侧车、MCP工具(内存传输)
npm run dev:jam # 侧车 + 罐装节奏,无需MCP客户端
npm run e2e # 全栈:真实stdio服务器 + 无头Chrome + 音频断言
npm run capture # DSP验证工具:网格、速度、幽灵/强调RMS、摆动
```
`e2e` 和 `capture` 通过Playwright驱动无头Chrome — 运行 `npx playwright install chromium` 一次。它们记录页面的实际音频输出到WAV并对其进行断言(网格上的起始点,测量的速度,幽灵音符比强调音符更安静,小节边界交换连续性,停止后静音):音频正确性是可检查的,而不是听觉检查。开发是规范驱动的; [specs/drummer-v1/SPEC.md](specs/drummer-v1/SPEC.md) 是需求、决策和进度真相的源头。
背景阅读: [RESEARCH.md](RESEARCH.md) (景观分析和为什么符号节拍优于神经音频)和 [IDEAS.md](IDEAS.md) (停放的未来扩展,例如口语贝斯线 → 贝斯MIDI)。
## 许可
此仓库是 **MIT** — 这里的所有代码都是我们的,免费许可。
它故意不包含:
- **Strudel** (`@strudel/web`, AGPL-3.0-or-later) — 未修改,从unpkg由*您的浏览器*在运行时加载。它没有被捆绑、链接、导入或由该项目重新分发;服务器仅发出Strudel *源代码作为文本*。AGPL义务附加到Strudel本身(已经开放),而不是这个仓库。
- **鼓样本** (潮汐鼓机) — 从Strudel的CDN由浏览器流式传输。各个WAV许可证上游未经验证,因此它们完全不属于仓库。源和许可证状态在 [SAMPLES.md](SAMPLES.md) 中跟踪。
- **声学鼓组** (Salamander Drumkit by Rytmenpinne, CC BY-SA 3.0) — 由浏览器从固定的GitHub镜像流式传输;仅文件名索引( [page/acoustic.json](page/acoustic.json) )在此存储库中。属性和详细信息在 [SAMPLES.md](SAMPLES.md) 中。
权衡是刻意的:运行时需要互联网,以换取一个纯MIT的存储库,零许可模糊性。