Skip to content

ucdaw: drive Studio Pro over UCNET (CLI + MCP) - #39

Merged
steveclarke merged 63 commits into
masterfrom
feat/ucdaw
Oct 12, 2026
Merged

steveclarke merged 63 commits into
masterfrom
feat/ucdaw

Conversation

@steveclarke

Copy link
Copy Markdown
Owner

Summary

Adds ucdaw, a CLI and MCP server that drives Fender Studio Pro 8 over UCNET (the protocol the Studio Pro Remote app uses), and ships it in the same release and Homebrew formula as ucmix.

  • .goreleaser.yml: second build cmd/ucdaw in the same archives; the formula installs both binaries (brew install steveclarke/tap/ucmix). fakeboard stays out. goreleaser check passes apart from the existing brews deprecation notice; goreleaser release --snapshot --clean --skip=publish succeeded and the archives and formula contain ucdaw. Nothing published or tagged.
  • README: "Getting started with ucdaw" for non-developers; CONTRIBUTING.md (build, just test, no real captures).

Proven live (Studio Pro 8.0.2)

Details and output in DECISIONS.md.

  • Discovery, session, live song model from Studio Pro's own updates; every change read back before ucdaw answers.
  • Transport, click, tempo, new song, audio and instrument tracks, insert plug-ins with presets, favourites.
  • Arrangement edits (add, repeat, move, rename, delete, play from a section), faders in dB on Studio Pro's measured curve.
  • Stem import, analyze (loudness), input trim and gain staging.
  • The full scene from a fresh Claude over MCP (guitar, pad, keys, bass, sections), run twice.
  • ucdaw serve answers in about 40 ms.

Untested

  • Reconnect after Studio Pro restarts. The code path is the same Connect the CLI uses and serve retries with backoff, but Studio Pro was never quit during testing.
  • Audio edits (fades, splits, quantize) are sent and checked on screen but cannot be read back: Studio Pro does not report audio events to remotes.
  • Live tests ran only against Studio Pro 8.0.2 on macOS.

Test plan

  • just test (845 tests), golangci-lint run clean
  • goreleaser snapshot build
  • CI green

Batched press+value with an 80 ms hold, byte-exact JM bodies, snapshot wait,
parameter set and lab commands. Play/Stop proven live; metronome open.
ucdaw song new [--tempo BPM] [--click on|off] and MCP new_song run
File > New Session, press the New window's OK button by its label, wait
for document/title to change, then set tempo and click and read back.
Any other dialog is cancelled and reported.

DismissDialog now presses the button labelled Cancel: the New window
lists OK first, so pressing button 0 there would start a song.
…ng faders

- analyze / analyze_audio: average RMS over active audio, peak, BS.1770 LUFS,
  silence, clipping and the trim to a -18 dBFS target; streams WAV/AIFF/AIFC
- trim / trim: channel input gain in dB, read back
- gainstage / gain_stage: every audio track's trim to the target, faders untouched
- track to file from ucdaw's import log, or the song's waveform cache plus Spotlight
- fader, trim and param set take negative levels and every global flag
- mixing workflow in the MCP instructions and skills/ucdaw/mixing.md
The go-sdk runs tool calls concurrently and, without ucdaw serve, nothing
serialized them, so selection-based edits could interleave and act on the
wrong track. One process-wide lock now wraps every request except Stop,
using the same Request.Exclusive rule as ucdaw serve.
An unlabeled first button was dropped, shifting the second into slot 0,
so pressing it by index sent the wrong dialogResult. Slots now stay in
place; only trailing empty slots are dropped.
DismissDialog pressed button 0 when there was no Cancel and reported it
canceled. It now presses only Cancel, No, Don't... or Do Not... (matched
as whole words; Don't Save is excluded because it loses work), or the
only button of a one-button alert. Otherwise it presses nothing and every
caller reports the dialog left open with its buttons named.

Import picked the last label containing a positive word, so it could
answer Don't Convert. It now skips any label that turns the offer down
and takes the first positive one.
A timed play converted seconds or bars to time.Duration before checking
MaxPlay; on amd64 1e300 or +Inf overflows to a negative Duration that
passes the check and plays untimed. The length is now checked as a float
first (NaN, negatives and -Inf rejected the same way), and the import
landing wait is capped the same way.
A timed play slept for its length and always pressed Stop, so a musician
who stopped and restarted playback meanwhile had it stopped under them.
It now waits on transport/start with the deadline, returns as soon as
playback stops or restarts elsewhere, and presses Stop only if Studio Pro
is still playing its own run at the deadline. A client hang-up still
stops playback.
Delete, rename and add confirmed only the section count (or one name),
so a Studio Pro that removed or renamed the wrong section was reported
as success. Every arranger edit now waits for the exact list it expects,
names and starts, and reports what Studio Pro shows if it differs. Move
checks the pasted copy (name at the destination, the rest shifted) before
deleting the original, so a bad paste never costs the original section.
Skill, CLI help and MCP tool descriptions said ucdaw cancels every dialog
and a timed play always stops itself; both are now conditional. dismiss
also says when a dialog closed before ucdaw answered it.
On "Save changes?" a No button discards the song, and labels alone cannot
tell which button keeps the work. A dialog whose title or text mentions
saving, discarding, deleting, removing, overwriting or closing is now left
open, whatever its buttons, with the dialog and buttons named; import
does not answer a conversion question that mentions overwriting.
… arranger check

Studio Pro makes no arranger section in a song with no tracks and reports
nothing, so add waited and timed out. It now refuses up front with the
fix. The whole-list arranger checks passed live on a new song for add,
rename, duplicate, move both ways, delete and repeat.
@steveclarke
steveclarke merged commit 6b7287e into master Oct 12, 2026
5 checks passed
@steveclarke
steveclarke deleted the feat/ucdaw branch October 12, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant