A file-based bridge API that extends Synthesizer V Studio's Lua scripting interface, enabling bidirectional communication between SV and external programs through a pseudo-bus (local JSON files).
Project Scope: This API is a wrapper for the Synthesizer V Lua scripting interface. It does not modify the Synthesizer V binary.
"SV" in this project refers to Synthesizer V, a product of Dreamtonics Co., Ltd. This project is an independent tool and is not affiliated with, sponsored by, or endorsed by Dreamtonics.
SV_Harmony_API provides a JSON Loop IO Bridge that runs inside Synthesizer V Studio as a Lua script. It continuously exports the live project state to a JSON file and monitors a second JSON file for incoming changes from external programs. This pseudo-bus architecture allows any external tool -- written in Python, C#, Node.js, or any language -- to read, manipulate, and write back project data (notes, parameters, tracks, tempo, etc.) while SV is running.
The system is split into two scripts:
| Script | Purpose |
|---|---|
Harmony Bridge (HarmonyBridge.lua) |
Runtime: starts the bridge loop on click. No UI dialogs. |
Harmony Settings (HarmonySettings.lua) |
Configuration UI: update interval, work mode, end detection silence, working directory, session cleanup. Saves to Harmony_Config.json. |
Synthesizer V's Lua scripting sandbox does not expose sockets, named pipes, or any network/IPC primitives. The only available I/O is io.open() for local files and SV:setTimeout() for scheduling. SV_Harmony_API leverages these two primitives to build a poll-based, dual-file IPC channel using the local filesystem as the communication medium.
+----------------------------+ +----------------------------+
| Synthesizer V Studio | | External Program |
| | | (Python, C#, etc.) |
| +----------------------+ | | +----------------------+ |
| | Harmony Bridge | | | | Reads/writes JSON | |
| | (HarmonyBridge.lua) | | | | | |
| +------+----------+----+ | | +----+-----------+-----+ |
| | ^ | | ^ | |
+---------+----------|-------+ +-------|-----------|-------+
| | | |
v | | v
{uuid}_out.json | | {uuid}_in.json
(SV --> External) | | (External --> SV)
+--------------------------+
Harmony/ working directory
(default: ~/Documents/Dreamtonics/Synthesizer V Studio/Harmony/)
Session-based file naming: Each loop session generates a unique UUID. Bridge files are named {uuid}_out.json and {uuid}_in.json in the Harmony working directory. Session metadata is tracked in Harmony_Session.json.
Two bridge files prevent read/write collisions:
| File | Direction | Writer | Reader |
|---|---|---|---|
{uuid}_out.json |
SV --> External | SV (every tick) | External program |
{uuid}_in.json |
External --> SV | External program | SV (every tick) |
{uuid}_cmd_in.json |
External --> SV | External program | SV (cmd poll tick) |
{uuid}_cmd_out.json |
SV --> External | SV (after exec) | External program |
Harmony_Lock.json |
Toggle signal | Bridge (on start) | Bridge (on click) |
The bridge uses asynchronous phased export: each export cycle is split into multiple phases (metadata → one track per tick → JSON encoding → file write), spreading work across several timer ticks to avoid blocking the SV main thread. In Full mode, an import is performed after each export cycle completes.
Toggle mechanism: Harmony_Lock.json records the active session ID. Clicking Harmony Bridge a second time detects this file and deletes it, which the running loop interprets as a stop signal at the next tick.
- Bidirectional sync -- export project state and import external modifications in real-time
- Async phased export -- export is split across multiple timer ticks (meta → track → encode → write) to avoid blocking the SV main thread
- Segment-based parameter fetching -- parameter curves are fetched in segments, supporting arbitrarily long songs without a fixed time limit
- Configurable end detection -- export range ends after a configurable silence gap (15s/30s/60s/120s with no notes), eliminating the old ~10-minute hard limit
- Pretty-printed JSON -- output uses indented formatting for git-friendliness and human readability
- Resilient import -- tolerates transient
_in.jsonfile absence (e.g., during atomic file replacement by external tools) for up to 60 seconds before reporting an error - Work modes -- Full (alternating export/import), Export Only, or Import Only (configurable in Settings)
- Session cleanup -- stale sessions auto-detected and removable via Settings checkbox
- SVP-compatible JSON format -- output matches the official
.svpfile structure - Full project coverage -- notes, 8 parameter curves (pitchDelta, vibratoEnv, loudness, tension, breathiness, voicing, gender, toneShift), tempo, time signatures, mixer settings, render config
- Zero dependencies -- includes a built-in pure-Lua JSON encoder/decoder
- Session management -- UUID-based sessions with auto-expiry, tracked in
Harmony_Session.json - Field-level diff import -- only modifies notes/parameters that actually changed
- Change detection -- only applies imports when file content actually changes
- CMD execution channel (opt-in, disabled by default) -- external programs can request arbitrary shell commands to be run inside SV Studio and retrieve stdout; independent poll interval, hard limits on command/output size, full error reporting
- Configurable -- update interval, work mode, end detection silence, working directory, and CMD settings via the Settings script
- Localization -- UI supports English and Simplified Chinese
A local stdio MCP server exposes the bridge to any MCP-capable agent. It binds no model and runs no agent loop — those belong to whatever client connects.
| Tool | Description |
|---|---|
harmony_read |
Return the latest project snapshot exported by HarmonyBridge |
harmony_cmd |
Execute one Lua chunk inside SV Studio via the CMD channel |
harmony_capabilities |
Report running sessions, enabled channels, and which writes this bridge supports |
This bridge covers the scripting API layer: same-version reads and writes against
the live project. It cannot render audio or save the project — the SV scripting API
has neither, and bounce is a frozen-state flag rather than an export. Carrying a
render across SV versions and driving an export are separate layers.
npm install
npm run buildRegister the built entry point with your MCP client as a local stdio server:
node <repo>/dist/src/cli.js
The server resolves the Harmony working directory from HARMONY_DIR, falling back to
%USERPROFILE%\Documents\Dreamtonics\Synthesizer V Studio\Harmony. Set HARMONY_DIR
when Node and SV Studio do not resolve the same path.
Note: HarmonyBridge must be running in SV Studio for either tool to return data, and
harmony_cmdadditionally requires the CMD channel to be enabled in Harmony Settings.
External programs that are not MCP clients can keep talking to the bridge files directly — see JSON Data Format and docs/CmdExecution.md.
- Synthesizer V Studio v1.0.1+ (some features like
getMixer()require v2.1.1+) - Operating System: Windows (path handling supports both
/and\) - No external Lua installation or libraries required
- MCP entry: Node.js 20.10+
Run install.bat. It will:
- Auto-detect (or prompt for) your SV Studio scripts folder and copy both Lua scripts.
- Scan for installed AI clients — Claude Code, GitHub Copilot, Cursor, Open Interpreter, OpenAI Codex CLI, Continue.dev — and ask whether to install the Harmony skill into each one's config.
After running: in SV Studio go to Scripts > Rescan.
Copy both scripts into your SV Studio scripts directory (find it via Scripts > Open Scripts Folder):
HarmonyBridge.lua
HarmonySettings.lua
To give your AI assistant context about the bridge, copy skill\HarmonyBridge-skill\SKILL.md into your AI client's instruction/rules config (see the table below). Clients that support skill folders can load skill\HarmonyBridge-skill\ directly, which also brings in the bundled SV scripting API reference.
| AI Client | Where to add the skill |
|---|---|
| Claude Code | ~/.claude/skills/sv-harmony/ (copy the whole folder — this is what install.bat does) |
| Cursor | ~/.cursor/rules/sv-harmony.mdc |
| OpenAI Codex CLI | ~/.codex/instructions.md |
| GitHub Copilot | Repo: .github/copilot-instructions.md · Global: VS Code settings github.copilot.chat.codeGeneration.instructions |
| Open Interpreter | Append to ~/.openinterpreter under custom_instructions: |
| Continue.dev | ~/.continue/rules/sv-harmony.md, then reference in config.json |
-
Save your project (
Ctrl+S) before running the bridge. The script reads the.svpfile on disk to extract voice library (database) andsystemPitchDeltadata that are not accessible through the scripting API. -
(Optional) Configure settings: From the Scripts menu, select Harmony Settings to set the update interval, work mode, end detection silence, and working directory. Settings are saved to
Harmony_Config.json.Work modes:
Mode Behavior Use case Full (default) Async phased export, then import after each export cycle completes Normal bidirectional workflow Export Only Async phased export every cycle, no import Read-only external tools (monitoring, analysis) Import Only Import every tick, no export One-way external control End Detection Silence:
Setting Behavior 15s Export range stops 15 seconds after last note 30s (default) Export range stops 30 seconds after last note 60s Export range stops 60 seconds after last note 120s Export range stops 120 seconds after last note Note: Export Only / Import Only should only be used if the external script requires it or you know what you are doing. The default Full mode is recommended for most use cases.
-
Start the bridge: From the Scripts menu, select Harmony Bridge. The loop starts immediately (no dialog). The Harmony working directory will be created automatically if needed.
-
Stop the bridge: Click Harmony Bridge again. The script detects the running instance via a lock file (
Harmony_Lock.json) and sends a stop signal. The running loop stops at the next tick and cleans up automatically. Only one bridge instance can run per SV editor at a time. -
For external program integration, write your tool to:
- Read
Harmony_Session.jsonto discover the active session UUID and file paths - Read
{uuid}_out.jsonto get the current SV project state - Write
{uuid}_in.jsonto push changes back into SV
- Read
WARNING: Switching .svp projects while a session is running
You must stop the bridge before opening or switching to a different
.svpproject. The session is bound to the project that was active when it started. If you switch projects without stopping first, the bridge will continue exporting/importing against the wrong project context. The resulting behavior is undefined -- you have been warned.
Over time, stale sessions and orphan bridge files can accumulate in the Harmony working directory. To clean them up, open Harmony Settings and check the Clean Sessions checkbox before clicking OK.
Cleanup rules:
- Sessions with
state == "stopped"are removed immediately, along with their bridge files. - Sessions with
state == "running"that have not updated their heartbeat in >60 seconds are considered dead and removed, along with their bridge files. - After session cleanup, all
*_out.json/*_in.jsonfiles in the working directory are scanned. Any files whose UUID does not belong to a surviving session are deleted as orphans.
Bridge files are created in the Harmony working directory:
~/Documents/Dreamtonics/Synthesizer V Studio/Harmony/
This can be overridden in Harmony Settings. The directory is created automatically on first run.
The bridge produces JSON structurally identical to the official .svp format. Time values use blicks (1 quarter note = 705,600,000 blicks).
{
"version": 153,
"time": {
"meter": [{ "index": 0, "numerator": 4, "denominator": 4 }],
"tempo": [{ "position": 0, "bpm": 120.0 }]
},
"tracks": [{
"name": "Track 1",
"mixer": { "gainDecibel": 0.0, "pan": 0.0, "mute": false, "solo": false },
"mainGroup": {
"notes": [{
"onset": 0,
"duration": 705600000,
"pitch": 60,
"lyrics": "la",
"phonemes": ""
}],
"parameters": {
"pitchDelta": { "mode": "cubic", "points": [] },
"vibratoEnv": { "mode": "cubic", "points": [] },
"loudness": { "mode": "cubic", "points": [] },
"tension": { "mode": "cubic", "points": [] },
"breathiness": { "mode": "cubic", "points": [] },
"voicing": { "mode": "cubic", "points": [] },
"gender": { "mode": "cubic", "points": [] },
"toneShift": { "mode": "cubic", "points": [] }
}
}
}],
"renderConfig": { "sampleRate": 44100, "bitDepth": 16 }
}- Latency: Configurable polling interval (default 1s); in Full mode, one complete export-then-import cycle spans multiple ticks due to phased export
- No file locking: An external program could theoretically read a partially-written file
- Voice library: Database info is read from the saved
.svpfile, not from the live editor. Changing the voice library requires saving the project first - Project switching: You must stop the session before switching
.svpprojects. Behavior is undefined otherwise
HarmonyBridge.lua # Runtime bridge (starts loop on click, no UI)
HarmonySettings.lua # Settings UI (interval, work mode, working dir, session cleanup)
install.bat # One-click installer: copies scripts + installs AI skill to detected clients
uninstall.bat # Removes installed scripts, skill entries, and optionally session data
LICENSE.txt # ALE 1.1 + GPL v3.0 dual license
src/
cli.ts # MCP stdio entry point
config.ts # Harmony working directory resolution
session.ts # Harmony_Session.json reading and session selection
harmony-ipc.ts # Snapshot read and CMD request/poll
server.ts # Two-tool MCP surface: harmony_read, harmony_cmd
skill/
HarmonyBridge-skill/
SKILL.md # AI assistant skill: MCP tools, file protocol, data schema, examples
references/sv-api.md # Synthesizer V scripting API reference
docs/
CmdExecution.md # CMD execution channel: protocol, error handling, Python example, API ref
This project is dual-licensed under the Anti-Labor Exploitation License 1.1 and GNU General Public License v3.0. The permissions granted under GPL v3.0 are conditional upon full compliance with ALE 1.1. See LICENSE.txt for details.