Soundgen is a Rust workspace for generating 8-bit/chiptune sound effects, UI sounds, and ambient textures for game audio assets. It features JSON-first sound specs, an MCP server for LLM tool-use, an egui GUI editor, and a runtime library with NES-authentic DAC emulation. Features: - 6 voice types: pulse, triangle, noise, DPCM, wavetable, FM - Effects: ADSR envelope, frequency sweep, biquad filter, vibrato - 13 built-in presets (SFX/UI/ambient) as JSON data files - MCP server: list_presets, generate_sfx, render_sound tools - Pattern-based sequencer (JSON song format) - egui GUI: virtual keyboard, preset browser, channel editor, undo/redo - Runtime: NES nonlinear DAC + SoundBank for game embedding - 90 tests, 0 warnings Crates: - soundgen-core: synthesis engine (no I/O) - soundgen-fmt: SoundSpec JSON schema + PresetRegistry - soundgen-io: WAV writer + audio playback - soundgen-seq: sequencer (patterns, songs) - soundgen-cli: gen/render/render-song/list-presets - soundgen-mcp: MCP server for LLM integration - soundgen-gui: egui editor - soundgen-runtime: NES DAC + SoundBank
10 KiB
10 KiB
Soundgen — 8-bit синтезатор на Rust + LLM-интеграция
Статус: Фазы 1-4 завершены
| Параметр | Значение |
|---|---|
| Язык | Rust |
| Игра | Rust + Vulkan (custom engine) |
| Генераторы | Свои, с нуля |
| GUI | egui (фаза 3) |
| MCP | Да, через rmcp (официальный Rust MCP SDK) |
| Звуки | SFX, UI sounds, Ambient |
| Генерация | Build time → WAV-ассеты |
| Лицензия | MIT |
Архитектура Cargo workspace
soundgen/
├── Cargo.toml # [workspace], shared deps
├── LICENSE # MIT
├── README.md
│
├── crates/
│ ├── soundgen-core/ # чистый движок синтеза, без I/O
│ │ └── src/
│ │ ├── lib.rs # реэкспорты
│ │ ├── generator.rs # trait Generator, Voice, Param
│ │ ├── voice/
│ │ │ ├── pulse.rs # PulseChannel (duty 12.5/25/50/75%)
│ │ │ ├── triangle.rs # TriangleChannel (32-step)
│ │ │ ├── noise.rs # NoiseChannel (LFSR white/periodic)
│ │ │ ├── dpcm.rs # (фаза 2)
│ │ │ ├── wavetable.rs # (фаза 2, GB wave-style)
│ │ │ └── fm.rs # (фаза 2, 4-op FM)
│ │ ├── effect/
│ │ │ ├── envelope.rs # ADSR
│ │ │ ├── sweep.rs # freq sweep (linear/exponential)
│ │ │ ├── vibrato.rs # LFO (фаза 2)
│ │ │ └── filter.rs # biquad lowpass/highpass (свой)
│ │ ├── automation.rs # FrequencyAutomation, Arpeggiator
│ │ └── mixer.rs # Mixer: N голосов → стерео
│ │
│ ├── soundgen-fmt/ # декларативный формат + пресеты
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── spec.rs # SoundSpec (serde JSON)
│ │ └── preset.rs # PresetRegistry, built-in presets
│ │
│ ├── soundgen-io/ # I/O слой
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── wav.rs # hound: WAV writer (16/24-bit)
│ │ └── realtime.rs # cpal (фаза 3)
│ │
│ ├── soundgen-seq/ # секвенсер (фаза 2)
│ │ └── src/
│ │ ├── pattern.rs # Pattern, Row, Note
│ │ ├── song.rs # Song, Track
│ │ └── sequencer.rs # Sequencer
│ │
│ ├── soundgen-cli/ # CLI binary
│ │ └── src/
│ │ ├── main.rs
│ │ └── commands/
│ │ ├── gen.rs # gen --preset jump --out ...
│ │ ├── render.rs # render song.json --out ...
│ │ └── list.rs # list-presets
│ │
│ ├── soundgen-mcp/ # MCP server для LLM (фаза 2)
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── server.rs # rmcp ServerHandler impl
│ │ └── tools.rs # generate_sfx, list_presets, render
│ │
│ └── soundgen-gui/ # egui GUI (фаза 3)
│ └── src/
│ ├── main.rs
│ ├── keyboard.rs # виртуальная клавиатура
│ ├── channel_panel.rs # регуляторы каналов
│ └── preset_browser.rs # браузер пресетов
│
├── presets/ # встроенная библиотека (JSON)
│ ├── sfx/
│ │ ├── jump.json
│ │ ├── explosion.json
│ │ ├── coin.json
│ │ ├── laser.json
│ │ ├── hit.json
│ │ └── powerup.json
│ ├── ui/
│ │ ├── click.json
│ │ ├── hover.json
│ │ ├── confirm.json
│ │ └── error.json
│ └── ambient/ # (фаза 2)
│ ├── wind.json
│ ├── rain.json
│ └── drone.json
│
├── examples/
│ ├── play_melody.rs # фаза 1: pulse+triangle+noise → WAV
│ ├── generate_sfx.rs # фаза 1: SFX из кода
│ └── render_song.rs # фаза 2: song.json → WAV
│
└── tests/
└── integration.rs # рендер WAV, проверка RMS/длительности
Декларативный формат (JSON) — LLM-friendly
Пример presets/sfx/jump.json:
{
"name": "jump",
"duration": 0.3,
"sample_rate": 44100,
"channels": [
{
"type": "pulse",
"duty": 50,
"frequency": { "start": 200, "end": 800, "curve": "exponential" },
"envelope": { "attack": 0.01, "decay": 0.15, "sustain": 0.0, "release": 0.14 },
"volume": 0.7
}
]
}
Пример presets/sfx/explosion.json:
{
"name": "explosion",
"duration": 0.8,
"channels": [
{
"type": "noise",
"mode": "white",
"filter": { "type": "lowpass", "cutoff": { "start": 2000, "end": 200, "curve": "exponential" } },
"envelope": { "attack": 0.005, "decay": 0.7, "sustain": 0.0, "release": 0.095 },
"volume": 0.9
}
]
}
LLM генерирует такой JSON → CLI/MCP рендерит → WAV-ассет готов.
MCP server — tools для LLM
Сервер на rmcp (stdio transport), expose 3 tool'а:
| Tool | Параметры | Возвращает |
|---|---|---|
list_presets |
category?: "sfx"|"ui"|"ambient" |
JSON-список пресетов с описаниями |
generate_sfx |
preset: string, params?: object, out_path: string |
Путь к WAV + метаданные (длительность, размер) |
render_sound |
spec: object (полный SoundSpec JSON), out_path: string |
Путь к WAV + метаданные |
Workflow LLM при разработке игры:
- LLM вызывает
list_presets→ видит доступные звуки - LLM вызывает
generate_sfx { preset: "jump", out_path: "assets/sfx/jump.wav" }→ WAV создан - Для кастомного звука: LLM пишет JSON-spec и вызывает
render_sound { spec: {...}, out_path: "assets/sfx/laser.wav" } - LLM пишет Rust-код игры, загружающий WAV через
hound/rodio
Зависимости
# workspace
[workspace.dependencies]
hound = "0.5" # WAV I/O
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# soundgen-io (фаза 3)
cpal = "0.15"
# soundgen-mcp (фаза 2)
rmcp = "1.7"
tokio = { version = "1", features = ["full"] }
# soundgen-cli
clap = { version = "4", features = ["derive"] }
# soundgen-gui (фаза 3)
eframe = "0.27"
egui = "0.27"
Фазы разработки
Фаза 1 — Core + CLI + Пресеты (MVP)
Цель: работающая библиотека, CLI, и набор готовых пресетов для SFX/UI.
- soundgen-core:
Generator/Voice/Paramтрейты,PulseChannel,TriangleChannel,NoiseChannel,Envelope(ADSR),Sweep(linear/exponential),FrequencyAutomation,Mixer, простые biquad filters (lowpass/highpass — свой код) - soundgen-fmt:
SoundSpec(serde),PresetRegistry(загрузка JSON изpresets/) - soundgen-io:
wav::write(path, samples, sr, bit_depth)черезhound - soundgen-cli:
gen --preset <name> [--param k=v]... --out <path>,gen --from <spec.json> --out <path>,list-presets [--category sfx|ui|ambient] - Пресеты: jump, explosion, coin, laser, hit, powerup (SFX); click, hover, confirm, error (UI)
- Examples:
play_melody,generate_sfx - Тесты: unit на duty cycle/частоту/envelope; интеграционный — рендер WAV, проверка длительности и RMS
Фаза 2 — Extended synthesis + Sequencer + MCP
Цель: расширенный синтез, секвенсер для мелодий, MCP-сервер для LLM.
- soundgen-core:
DpcmChannel,WavetableChannel,FmChannel,Vibrato(LFO) - soundgen-seq:
Pattern,Song,Sequencer(tempo, rows, note triggers) - soundgen-mcp: rmcp-сервер, tools:
list_presets,generate_sfx,render_sound - Ambient пресеты: wind (filtered noise + slow LFO), rain (noise + highpass), drone (low freq sustained)
- CLI:
render song.json --out music.wav - Example:
render_song
Фаза 3 — GUI (egui)
Цель: интерактивный редактор для человека.
- egui app: виртуальная клавиатура (мышью/клавишами), панель каналов (duty, freq, envelope), браузер пресетов, pattern editor
- cpal realtime playback (ring buffer)
- Сохранение/загрузка проектов (JSON)
Фаза 4 — Advanced (опционально)
- NES-authentic: нелинейный DAC, DPCM corruption, hardware-accurate mixing
- VST плагин через
nih-plug - Runtime library для прямой интеграции в Rust+Vulkan игру
Ключевые принципы
- Чистый core без I/O — рендеринг в
Vec<f32>в тестах без звуковой карты - Sample-accurate tick —
Voice::tick() -> f32,Mixerсобирает буфер - Без allocations в hot path — генераторы работают с
&mut self, безVecв audio thread - JSON-first для LLM — каждый звук описывается JSON, LLM генерирует JSON естественно
- Пресеты как data, не code — JSON-файлы в
presets/, расширяемые без перекомпиляции