audacity4-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- audacity4_mcp-0.1.0/.github/dependabot.yml +11 -0
- audacity4_mcp-0.1.0/.github/workflows/ci.yml +52 -0
- audacity4_mcp-0.1.0/.github/workflows/publish.yml +59 -0
- audacity4_mcp-0.1.0/.gitignore +6 -0
- audacity4_mcp-0.1.0/AUDACITY4_RESEARCH.md +460 -0
- audacity4_mcp-0.1.0/CHANGELOG.md +47 -0
- audacity4_mcp-0.1.0/CONTRIBUTING.md +86 -0
- audacity4_mcp-0.1.0/LICENSE +190 -0
- audacity4_mcp-0.1.0/PKG-INFO +132 -0
- audacity4_mcp-0.1.0/README.md +103 -0
- audacity4_mcp-0.1.0/SECURITY.md +26 -0
- audacity4_mcp-0.1.0/docs/INSTALLATION.md +93 -0
- audacity4_mcp-0.1.0/docs/TOOLS.md +204 -0
- audacity4_mcp-0.1.0/pyproject.toml +66 -0
- audacity4_mcp-0.1.0/server4/__init__.py +0 -0
- audacity4_mcp-0.1.0/server4/bridge_client.py +106 -0
- audacity4_mcp-0.1.0/server4/main.py +17 -0
- audacity4_mcp-0.1.0/server4/tool_registry.py +12 -0
- audacity4_mcp-0.1.0/server4/tools/__init__.py +0 -0
- audacity4_mcp-0.1.0/server4/tools/analysis_tools.py +342 -0
- audacity4_mcp-0.1.0/server4/tools/cleanup_tools.py +648 -0
- audacity4_mcp-0.1.0/server4/tools/edit_tools.py +94 -0
- audacity4_mcp-0.1.0/server4/tools/effects_tools.py +588 -0
- audacity4_mcp-0.1.0/server4/tools/generate_tools.py +160 -0
- audacity4_mcp-0.1.0/server4/tools/label_tools.py +217 -0
- audacity4_mcp-0.1.0/server4/tools/project_tools.py +184 -0
- audacity4_mcp-0.1.0/server4/tools/realtime_effects_tools.py +143 -0
- audacity4_mcp-0.1.0/server4/tools/selection_tools.py +158 -0
- audacity4_mcp-0.1.0/server4/tools/track_tools.py +125 -0
- audacity4_mcp-0.1.0/server4/tools/transcription_tools.py +576 -0
- audacity4_mcp-0.1.0/server4/tools/transport_tools.py +62 -0
- audacity4_mcp-0.1.0/tests/__init__.py +0 -0
- audacity4_mcp-0.1.0/tests/test_analysis_tools.py +40 -0
- audacity4_mcp-0.1.0/tests/test_bridge_client.py +160 -0
- audacity4_mcp-0.1.0/tests/test_cleanup_tools.py +179 -0
- audacity4_mcp-0.1.0/tests/test_edit_tools.py +52 -0
- audacity4_mcp-0.1.0/tests/test_effects_tools.py +332 -0
- audacity4_mcp-0.1.0/tests/test_generate_tools.py +105 -0
- audacity4_mcp-0.1.0/tests/test_project_tools.py +208 -0
- audacity4_mcp-0.1.0/tests/test_realtime_effects_tools.py +196 -0
- audacity4_mcp-0.1.0/tests/test_selection_tools.py +235 -0
- audacity4_mcp-0.1.0/tests/test_tools.py +30 -0
- audacity4_mcp-0.1.0/tests/test_track_tools.py +165 -0
- audacity4_mcp-0.1.0/tests/test_transcription_tools.py +175 -0
- audacity4_mcp-0.1.0/tests/test_transport_tools.py +131 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
"on":
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
# Static analysis only - version/OS independent, so this runs once
|
|
12
|
+
# instead of being duplicated across the full test matrix below.
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7
|
|
16
|
+
- uses: actions/setup-python@v7
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- name: Run ruff
|
|
21
|
+
run: ruff check .
|
|
22
|
+
|
|
23
|
+
test:
|
|
24
|
+
runs-on: ${{ matrix.os }}
|
|
25
|
+
# Hard backstop: a hung test would otherwise run until GitHub's default
|
|
26
|
+
# 360-minute job timeout. 10 minutes is generous for a suite that
|
|
27
|
+
# normally finishes in seconds.
|
|
28
|
+
timeout-minutes: 10
|
|
29
|
+
strategy:
|
|
30
|
+
fail-fast: false
|
|
31
|
+
matrix:
|
|
32
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
33
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
34
|
+
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v7
|
|
37
|
+
|
|
38
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
39
|
+
uses: actions/setup-python@v7
|
|
40
|
+
with:
|
|
41
|
+
python-version: ${{ matrix.python-version }}
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: pip install -e ".[dev]"
|
|
45
|
+
|
|
46
|
+
- name: Run tests
|
|
47
|
+
run: pytest tests/ -x -q
|
|
48
|
+
|
|
49
|
+
# Note: these unit tests run against a mocked bridge, not a real
|
|
50
|
+
# Audacity4-Dev instance - they verify the Python wrapper layer only.
|
|
51
|
+
# There is no CI coverage yet for the C++ mcp module or live
|
|
52
|
+
# end-to-end behavior against a running Audacity 4 fork.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Fires automatically on every version tag push (git tag vX.Y.Z && git push
|
|
4
|
+
# --tags), or manually via workflow_dispatch - no manual `twine upload` step,
|
|
5
|
+
# and no PyPI token stored anywhere in this repo. Uses PyPI's Trusted
|
|
6
|
+
# Publisher (OIDC) mechanism instead: PyPI is configured (once, on pypi.org)
|
|
7
|
+
# to trust this exact workflow in this exact repo, so GitHub can prove its
|
|
8
|
+
# identity to PyPI without a shared secret to store, rotate, or leak.
|
|
9
|
+
"on":
|
|
10
|
+
push:
|
|
11
|
+
tags:
|
|
12
|
+
- "v*"
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
test:
|
|
17
|
+
# Gate: publishing requires the tagged commit itself to pass tests, not
|
|
18
|
+
# just whatever main's CI run said earlier - a tag can point anywhere.
|
|
19
|
+
runs-on: ${{ matrix.os }}
|
|
20
|
+
timeout-minutes: 10
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
25
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v7
|
|
28
|
+
- uses: actions/setup-python@v7
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
- run: pip install -e ".[dev]"
|
|
32
|
+
- run: pytest tests/ -x -q
|
|
33
|
+
|
|
34
|
+
build:
|
|
35
|
+
needs: test
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v7
|
|
39
|
+
- uses: actions/setup-python@v7
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.12"
|
|
42
|
+
- run: python -m pip install --upgrade build
|
|
43
|
+
- run: python -m build
|
|
44
|
+
- uses: actions/upload-artifact@v7
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
|
|
49
|
+
publish:
|
|
50
|
+
needs: build
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
permissions:
|
|
53
|
+
id-token: write # required for Trusted Publishing - do not remove
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/download-artifact@v8
|
|
56
|
+
with:
|
|
57
|
+
name: dist
|
|
58
|
+
path: dist/
|
|
59
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
# Audacity 4 — Reverse Engineering Research
|
|
2
|
+
# Conducted March 2026 (Alpha Build)
|
|
3
|
+
# PRIVATE — Do not publish
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
Audacity 4 is a complete rewrite on the MuseScore/Muse framework (Qt6/QML).
|
|
7
|
+
The old wxWidgets codebase is gone. mod-script-pipe is gone.
|
|
8
|
+
New architecture uses a JavaScript scripting engine with dispatcher actions.
|
|
9
|
+
|
|
10
|
+
## Source Code
|
|
11
|
+
- Main repo: https://github.com/audacity/audacity.git
|
|
12
|
+
- Muse framework (submodule): https://github.com/musescore/framework_tmp.git
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Dispatcher Action System
|
|
17
|
+
|
|
18
|
+
Central command system. All operations go through `dispatcher()->dispatch()`.
|
|
19
|
+
|
|
20
|
+
### Action URI Pattern
|
|
21
|
+
```
|
|
22
|
+
action://<module>/<verb>?param=value
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Complete Action Map (200+ actions)
|
|
26
|
+
|
|
27
|
+
#### Playback (25+ actions)
|
|
28
|
+
- `action://playback/play` — Play
|
|
29
|
+
- `action://playback/pause` — Pause
|
|
30
|
+
- `action://playback/stop` — Stop
|
|
31
|
+
- `action://playback/rewind-start` — Rewind to start
|
|
32
|
+
- `action://playback/rewind-end` — Rewind to end
|
|
33
|
+
- `action://playback/seek` — Seek to position
|
|
34
|
+
- `action://playback/level` — Set playback level
|
|
35
|
+
- `toggle-loop-region` — Loop playback
|
|
36
|
+
- `metronome` — Toggle metronome
|
|
37
|
+
- `playback-time` — Set playback time
|
|
38
|
+
- `playback-bpm` — Set tempo
|
|
39
|
+
- `playback-time-signature` — Set time signature
|
|
40
|
+
- `action://playback/change-api` — Change audio host
|
|
41
|
+
- `action://playback/change-playback-device` — Change playback device
|
|
42
|
+
- `action://playback/change-recording-device` — Change recording device
|
|
43
|
+
- `action://playback/change-input-channels` — Change input channels
|
|
44
|
+
- `rescan-devices` — Rescan audio devices
|
|
45
|
+
- `clear-loop-region` — Clear loop region
|
|
46
|
+
- `set-loop-region-to-selection` — Set loop to selection
|
|
47
|
+
- `set-selection-to-loop` — Set selection to loop
|
|
48
|
+
|
|
49
|
+
#### Record (6 actions)
|
|
50
|
+
- `action://record/start` — Record
|
|
51
|
+
- `action://record/pause` — Pause recording
|
|
52
|
+
- `action://record/stop` — Stop recording
|
|
53
|
+
- `action://record/level` — Set record level
|
|
54
|
+
- `action://record/toggle-mic-metering` — Show mic metering
|
|
55
|
+
- `action://record/toggle-input-monitoring` — Input monitoring
|
|
56
|
+
|
|
57
|
+
#### Track Edit (60+ actions)
|
|
58
|
+
##### Clipboard
|
|
59
|
+
- `action://trackedit/copy` — Copy
|
|
60
|
+
- `action://trackedit/cut` — Cut
|
|
61
|
+
- `action://trackedit/paste-default` — Paste
|
|
62
|
+
- `action://trackedit/paste-insert` — Paste (pushes clips)
|
|
63
|
+
- `action://trackedit/paste-overlap` — Paste (overlaps)
|
|
64
|
+
- `action://trackedit/paste-insert-all-tracks-ripple` — Paste (preserves sync)
|
|
65
|
+
- `action://trackedit/delete` — Delete
|
|
66
|
+
- `action://trackedit/undo` — Undo
|
|
67
|
+
- `action://trackedit/redo` — Redo
|
|
68
|
+
|
|
69
|
+
##### Clip Operations
|
|
70
|
+
- `split` — Split
|
|
71
|
+
- `join` — Join selected clips
|
|
72
|
+
- `disjoin` — Split at silences
|
|
73
|
+
- `duplicate` — Duplicate
|
|
74
|
+
- `merge-selected-on-tracks` — Merge selected clips
|
|
75
|
+
- `clip-export` — Export clip
|
|
76
|
+
- `clip-pitch-speed-open` — Open pitch/speed dialog
|
|
77
|
+
- `clip-render-pitch-speed` — Render pitch/speed
|
|
78
|
+
- `trim-audio-outside-selection` — Trim
|
|
79
|
+
- `silence-audio-selection` — Silence
|
|
80
|
+
- `group-clips` / `ungroup-clips` — Group/ungroup
|
|
81
|
+
- `stretch-clip-to-match-tempo` — Stretch with tempo
|
|
82
|
+
|
|
83
|
+
##### Ripple Editing
|
|
84
|
+
- `cut-per-clip-ripple` / `cut-per-track-ripple` / `cut-all-tracks-ripple`
|
|
85
|
+
- `delete-per-track-ripple` / `delete-all-tracks-ripple`
|
|
86
|
+
|
|
87
|
+
##### Track Management
|
|
88
|
+
- `track-rename` — Rename track
|
|
89
|
+
- `track-duplicate` — Duplicate track
|
|
90
|
+
- `track-delete` — Delete track
|
|
91
|
+
- `track-move-up` / `track-move-down` / `track-move-top` / `track-move-bottom`
|
|
92
|
+
- `track-change-rate-custom` — Change sample rate
|
|
93
|
+
- `track-make-stereo` — Make stereo
|
|
94
|
+
- `track-swap-channels` — Swap L/R
|
|
95
|
+
- `track-split-stereo-to-lr` / `track-split-stereo-to-center`
|
|
96
|
+
- `track-resample` — Resample
|
|
97
|
+
- `new-mono-track` / `new-stereo-track` / `new-label-track`
|
|
98
|
+
|
|
99
|
+
##### Track View
|
|
100
|
+
- `action://trackedit/track-view-waveform` — Waveform view
|
|
101
|
+
- `action://trackedit/track-view-spectrogram` — Spectrogram view
|
|
102
|
+
- `action://trackedit/track-view-multi` — Multi view
|
|
103
|
+
- `action://trackedit/global-view-spectrogram` — Toggle spectral
|
|
104
|
+
- `action://trackedit/clip/change-color-auto` — Auto clip color
|
|
105
|
+
- `action://trackedit/track/change-format?format=N` — Change format
|
|
106
|
+
- `action://trackedit/track/change-rate?rate=N` — Change rate
|
|
107
|
+
|
|
108
|
+
##### Labels
|
|
109
|
+
- `label-add` / `label-delete` / `label-cut` / `label-copy`
|
|
110
|
+
|
|
111
|
+
##### Track View Navigation
|
|
112
|
+
- `track-view-item-move-left/right/up/down`
|
|
113
|
+
- `track-view-item-extend-left/right`
|
|
114
|
+
- `track-view-item-reduce-left/right`
|
|
115
|
+
- `track-view-next-panel/prev-panel/next-item/prev-item`
|
|
116
|
+
- `track-view-next-track/prev-track/first-track/last-track`
|
|
117
|
+
- `track-view-toggle-selection/range-selection`
|
|
118
|
+
- `track-view-item-context-menu`
|
|
119
|
+
|
|
120
|
+
#### Project (80+ actions)
|
|
121
|
+
##### File
|
|
122
|
+
- `file-new` / `file-open` / `file-save` / `file-save-as` / `file-save-backup`
|
|
123
|
+
- `file-close` / `clear-recent`
|
|
124
|
+
- `project-import` — Import
|
|
125
|
+
- `export-audio` — Export audio
|
|
126
|
+
- `export-labels` — Export labels
|
|
127
|
+
- `export-midi` — Export MIDI
|
|
128
|
+
|
|
129
|
+
##### Edit
|
|
130
|
+
- `duplicate` / `insert` / `rename-item` / `trim-clip`
|
|
131
|
+
- `split-into-new-track` / `silence-audio`
|
|
132
|
+
- Label operations: `cut-labels`, `copy-labels`, `delete-labels`, `split-labels`, `join-labels`, `silence-labels`, `disjoin-labels`
|
|
133
|
+
- `manage-labels` / `manage-metadata`
|
|
134
|
+
|
|
135
|
+
##### Selection
|
|
136
|
+
- `select-all` / `select-all-tracks` / `clear-selection`
|
|
137
|
+
- `select-left-of-playback-position` / `select-right-of-playback-position`
|
|
138
|
+
- `select-track-start-to-cursor` / `select-cursor-to-track-end`
|
|
139
|
+
- `select-previous-clip` / `select-next-clip`
|
|
140
|
+
- `toggle-spectral-selection` / `zero-cross`
|
|
141
|
+
|
|
142
|
+
##### View
|
|
143
|
+
- `zoom-in` / `zoom-out` / `zoom-to-selection` / `zoom-toggle` / `zoom-reset`
|
|
144
|
+
- `fit-project-to-window` / `fit-view-to-project`
|
|
145
|
+
- `collapse-all-tracks` / `expand-all-tracks`
|
|
146
|
+
- `toggle-effects` / `toggle-metadata-editor` / `toggle-history`
|
|
147
|
+
|
|
148
|
+
##### Record Menu
|
|
149
|
+
- `record-on-current-track` / `record-on-new-track`
|
|
150
|
+
- `set-up-timed-recording` / `punch-and-roll-record`
|
|
151
|
+
- `toggle-sound-activated-recording` / `set-sound-activation-level`
|
|
152
|
+
|
|
153
|
+
##### Track Menu
|
|
154
|
+
- `duplicate-track` / `remove-tracks` / `mixdown-to`
|
|
155
|
+
- Alignment: `align-end-to-end`, `align-together`, `align-start-to-zero`, `align-start-to-playhead`, etc.
|
|
156
|
+
- `sort-by-time` / `sort-by-name` / `keep-tracks-synchronised`
|
|
157
|
+
|
|
158
|
+
##### Effects/Generate/Analyze Menu
|
|
159
|
+
- `effect-plugin-manager` / `generate-plugin-manager` / `analyze-plugin-manager`
|
|
160
|
+
- `add-realtime-effects`
|
|
161
|
+
- `favourite-effect-1/2/3`
|
|
162
|
+
- `contrast-analyzer` / `plot-spectrum`
|
|
163
|
+
|
|
164
|
+
##### Tools
|
|
165
|
+
- `manage-macros` / `apply-macros-palette`
|
|
166
|
+
- `nyquist-prompt` / `nyquist-plugin-installer`
|
|
167
|
+
- `sample-data-export` / `sample-data-import` / `raw-data-import`
|
|
168
|
+
- `reset-configuration`
|
|
169
|
+
|
|
170
|
+
#### Effects (8 static + dynamic per-effect)
|
|
171
|
+
- `repeat-last-effect` — Repeat last effect
|
|
172
|
+
- `realtimeeffect-remove` — Remove realtime effect
|
|
173
|
+
- `action://effects/presets/apply` — Apply preset
|
|
174
|
+
- `action://effects/presets/save` — Save preset
|
|
175
|
+
- `action://effects/presets/delete` — Delete preset
|
|
176
|
+
- `action://effects/presets/import` / `export` — Import/export preset
|
|
177
|
+
- `action://effects/toggle_vendor_ui` — Toggle vendor UI
|
|
178
|
+
- `action://effects/open?effectId=<id>` — Open effect (dynamic)
|
|
179
|
+
- `action://effects/realtime-add?effectId=<id>` — Add realtime effect (dynamic)
|
|
180
|
+
- `action://effects/realtime-replace?effectId=<id>` — Replace realtime effect (dynamic)
|
|
181
|
+
|
|
182
|
+
#### App Shell (25+ actions)
|
|
183
|
+
- `quit` / `restart` / `fullscreen`
|
|
184
|
+
- `preference-dialog` / `audio-settings`
|
|
185
|
+
- Layout toggles: `toggle-transport`, `toggle-tracks`, `toggle-instruments`, `inspector`, etc.
|
|
186
|
+
- Global aliases: `action://copy` → `action://trackedit/copy`, etc.
|
|
187
|
+
|
|
188
|
+
#### Project Scene (20+ actions)
|
|
189
|
+
- Tools: `clip-gain`, `split-tool`, `snap`
|
|
190
|
+
- View: `minutes-seconds-ruler`, `beats-measures-ruler`, `toggle-vertical-rulers`
|
|
191
|
+
- `show-master-track` / `toggle-rms-in-waveform` / `toggle-clipping-in-waveform`
|
|
192
|
+
- `clip-properties` / `clip-rename` / `clip-pitch-speed`
|
|
193
|
+
- `play-position-decrease` / `play-position-increase`
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 2. Two Script Engines
|
|
198
|
+
|
|
199
|
+
### Autobot Scripts (internal testing)
|
|
200
|
+
Location: `C:\Program Files\Audacity 4\autobotscripts\`
|
|
201
|
+
Global object: `api` (ScriptApi)
|
|
202
|
+
|
|
203
|
+
Available APIs:
|
|
204
|
+
- `api.dispatcher` — dispatch actions (FULL ACCESS)
|
|
205
|
+
- `api.keyboard` — simulate keyboard input
|
|
206
|
+
- `api.navigation` — navigate UI
|
|
207
|
+
- `api.shortcuts` — trigger shortcuts
|
|
208
|
+
- `api.accessibility` — UI element tree
|
|
209
|
+
- `api.process` — process control
|
|
210
|
+
- `api.filesystem` — file access
|
|
211
|
+
- `api.interactive` — dialogs
|
|
212
|
+
- `api.log` — logging
|
|
213
|
+
- `api.autobot` — test runner (sleep, setInterval, etc.)
|
|
214
|
+
- `api.context` — script context
|
|
215
|
+
|
|
216
|
+
Usage:
|
|
217
|
+
```javascript
|
|
218
|
+
api.dispatcher.dispatch("file-new");
|
|
219
|
+
api.dispatcher.dispatch("zoom-x-percent", [100]);
|
|
220
|
+
api.keyboard.key("Ctrl+S");
|
|
221
|
+
api.autobot.sleep(1000);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Extensions (user plugins)
|
|
225
|
+
Location: `C:\Users\<user>\AppData\Local\Audacity\Audacity4\extensions\`
|
|
226
|
+
Global object: `api` (ExtApi)
|
|
227
|
+
|
|
228
|
+
Available APIs:
|
|
229
|
+
- `api.log` — logging
|
|
230
|
+
- `api.interactive` — dialogs
|
|
231
|
+
- `api.theme` — theme info
|
|
232
|
+
- `api.websocket` — WebSocket client
|
|
233
|
+
- `api.websocketserver` — WebSocket server
|
|
234
|
+
|
|
235
|
+
BLOCKED APIs (commented out in source for security):
|
|
236
|
+
- ~~api.dispatcher~~ — "Providing these APIs requires approval"
|
|
237
|
+
- ~~api.keyboard~~
|
|
238
|
+
- ~~api.navigation~~
|
|
239
|
+
- ~~api.shortcuts~~
|
|
240
|
+
- ~~api.accessibility~~
|
|
241
|
+
- ~~api.process~~
|
|
242
|
+
- ~~api.filesystem~~
|
|
243
|
+
|
|
244
|
+
### Key Difference
|
|
245
|
+
Autobot = full control, no networking
|
|
246
|
+
Extensions = networking (WebSocket), no control
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 3. Extension System
|
|
251
|
+
|
|
252
|
+
### Manifest Format (manifest.json)
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"uri": "muse://extensions/my-extension",
|
|
256
|
+
"type": "macros",
|
|
257
|
+
"title": "My Extension",
|
|
258
|
+
"description": "What it does",
|
|
259
|
+
"version": "1.0.0",
|
|
260
|
+
"apiversion": 2,
|
|
261
|
+
"actions": [
|
|
262
|
+
{
|
|
263
|
+
"code": "main",
|
|
264
|
+
"path": "main.js",
|
|
265
|
+
"type": "macros",
|
|
266
|
+
"title": "Run",
|
|
267
|
+
"func": "main",
|
|
268
|
+
"show_on_appmenu": true
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Types
|
|
275
|
+
- `"macros"` — JS only, no UI
|
|
276
|
+
- `"form"` — QML with UI
|
|
277
|
+
- `"composite"` — both
|
|
278
|
+
|
|
279
|
+
### Install Paths
|
|
280
|
+
- Bundled: `<install_dir>/extensions/`
|
|
281
|
+
- User: `C:\Users\<user>\AppData\Local\Audacity\Audacity4\extensions\`
|
|
282
|
+
- Packaged as `.mext` (zip with manifest.json)
|
|
283
|
+
|
|
284
|
+
### Module System
|
|
285
|
+
CommonJS-style `require()` / `exports` / `module` available.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 4. VST3 Support (Full Backend — UI Not Wired Yet in Alpha)
|
|
290
|
+
|
|
291
|
+
### Effect ID Format
|
|
292
|
+
```
|
|
293
|
+
Effect_Audacity_Audacity_<SymbolName>_Built-in Effect: <SymbolName>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### VST3 Plugin ID Format
|
|
297
|
+
```
|
|
298
|
+
Effect_<Family>_<Vendor>_<Symbol>_<Path>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Scan Paths
|
|
302
|
+
- Windows: `%PROGRAMFILES%\Common Files\VST3\`
|
|
303
|
+
- macOS: `~/Library/Audio/Plug-ins/VST3/`, `/Library/Audio/Plug-ins/VST3/`
|
|
304
|
+
- Linux: `~/.vst3/`, `/usr/lib/vst3/`, `/usr/local/lib/vst3/`
|
|
305
|
+
|
|
306
|
+
### Programmatic Parameter Control
|
|
307
|
+
```cpp
|
|
308
|
+
// Read all parameters
|
|
309
|
+
ParameterInfoList parameters(EffectInstanceId instanceId);
|
|
310
|
+
|
|
311
|
+
// ParameterInfo contains:
|
|
312
|
+
// - id, name, units ("dB", "Hz", "%")
|
|
313
|
+
// - type (Toggle, Dropdown, Slider, Numeric, ReadOnly)
|
|
314
|
+
// - minValue, maxValue, defaultValue, currentValue
|
|
315
|
+
// - currentValueString ("440 Hz", "-3.5 dB")
|
|
316
|
+
// - stepCount, enumValues, isLogarithmic, canAutomate
|
|
317
|
+
|
|
318
|
+
// Set parameter
|
|
319
|
+
bool setParameterValue(EffectInstanceId, parameterId, double value);
|
|
320
|
+
|
|
321
|
+
// Apply effect without UI dialog
|
|
322
|
+
DoEffect(pluginID, project, EffectManager::kConfigured);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Realtime Effects Chain
|
|
326
|
+
```cpp
|
|
327
|
+
// Add VST to track (trackId = -2 for master bus)
|
|
328
|
+
addRealtimeEffect(trackId, effectId);
|
|
329
|
+
removeRealtimeEffect(trackId, state);
|
|
330
|
+
replaceRealtimeEffect(trackId, effectListIndex, newEffectId);
|
|
331
|
+
moveRealtimeEffect(state, newIndex);
|
|
332
|
+
setIsActive(state, active);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Preset System
|
|
336
|
+
```cpp
|
|
337
|
+
// Factory presets
|
|
338
|
+
PresetIdList factoryPresets(effectId);
|
|
339
|
+
// User presets
|
|
340
|
+
PresetIdList userPresets(effectId);
|
|
341
|
+
// Apply/save/import/export
|
|
342
|
+
applyPreset(instanceId, presetId);
|
|
343
|
+
saveCurrentAsPreset(instanceId, presetName);
|
|
344
|
+
importPreset(instanceId, filePath);
|
|
345
|
+
exportPreset(instanceId, filePath);
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Builtin Effect Symbols
|
|
349
|
+
Amplify, Bass and Treble, Change Pitch, Change Speed, Change Tempo,
|
|
350
|
+
Chirp, Click removal, Compressor, Distortion, DTMF Tones, Echo,
|
|
351
|
+
Equalization, Fade In, Fade Out, Find Clipping, Graphic EQ, Invert,
|
|
352
|
+
Limiter, Noise, Noise Reduction, Normalize, Normalize Loudness,
|
|
353
|
+
Paulstretch, Phaser, Repair, Repeat, Reverse, Reverb, Silence,
|
|
354
|
+
Sliding Stretch, Stereo To Mono, Tone, Truncate silence, Wahwah,
|
|
355
|
+
Auto Duck
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## 5. WebSocket API (If Compiled)
|
|
360
|
+
|
|
361
|
+
Default OFF: `MUSE_MODULE_NETWORK_WEBSOCKET=OFF` in CMake.
|
|
362
|
+
|
|
363
|
+
### Server API (available to extensions)
|
|
364
|
+
```javascript
|
|
365
|
+
var server = api.websocketserver;
|
|
366
|
+
server.listen(8765, function(clientId) {
|
|
367
|
+
server.onMessage(clientId, function(message) {
|
|
368
|
+
var data = JSON.parse(message);
|
|
369
|
+
server.send(clientId, JSON.stringify({ result: "ok" }));
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Client API
|
|
375
|
+
```javascript
|
|
376
|
+
var ws = api.websocket;
|
|
377
|
+
ws.open(8084, function(socketId) {
|
|
378
|
+
ws.onMessage(socketId, function(message) { ... });
|
|
379
|
+
ws.send(socketId, JSON.stringify({ ... }));
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
- Text messages only (no binary)
|
|
384
|
+
- No protocol defined — raw strings, parse your own JSON
|
|
385
|
+
- Server name: `"muse_extension"`
|
|
386
|
+
- Client IDs start at 2001
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## 6. IPC Mechanisms Found
|
|
391
|
+
|
|
392
|
+
| Mechanism | Purpose | External Access |
|
|
393
|
+
|-----------|---------|:---:|
|
|
394
|
+
| QLocalServer/Socket | Multi-window coordination | No |
|
|
395
|
+
| QTcpServer (OAuth) | Cloud sign-in redirect capture | No |
|
|
396
|
+
| WebSocket (extension API) | Plugin networking | Yes (if compiled) |
|
|
397
|
+
| mod-script-pipe | GONE in v4 | N/A |
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## 7. Bridge Architecture (Planned)
|
|
402
|
+
|
|
403
|
+
### Target: Extension with WebSocket + Dispatcher
|
|
404
|
+
Requires two changes to build from source:
|
|
405
|
+
1. `MUSE_MODULE_NETWORK_WEBSOCKET=ON` in CMake
|
|
406
|
+
2. Uncomment `api.dispatcher` in `muse_framework/framework/extensions/api/extapi.h`
|
|
407
|
+
|
|
408
|
+
```
|
|
409
|
+
┌─────────────────────┐ WebSocket ┌──────────────────┐
|
|
410
|
+
│ AudacityMCP Server │ ◄────────────────► │ Audacity 4 │
|
|
411
|
+
│ (Python/FastMCP) │ localhost:8765 │ Extension │
|
|
412
|
+
│ 99+ tools │ │ (bridge.js) │
|
|
413
|
+
└─────────────────────┘ │ ↓ │
|
|
414
|
+
│ dispatcher() │
|
|
415
|
+
│ → 200+ actions │
|
|
416
|
+
│ → VST3 control │
|
|
417
|
+
└──────────────────┘
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Source Files to Modify
|
|
421
|
+
- `muse_framework/framework/extensions/api/extapi.h` — uncomment dispatcher property
|
|
422
|
+
- `CMakeLists.txt` or build config — set `MUSE_MODULE_NETWORK_WEBSOCKET=ON`
|
|
423
|
+
- Create extension: `manifest.json` + `bridge.js`
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## 8. Key Source File Locations
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
audacity/
|
|
431
|
+
├── src/
|
|
432
|
+
│ ├── appshell/internal/applicationuiactions.cpp — app actions
|
|
433
|
+
│ ├── playback/internal/playbackuiactions.cpp — transport
|
|
434
|
+
│ ├── record/internal/recorduiactions.cpp — recording
|
|
435
|
+
│ ├── trackedit/internal/trackedituiactions.cpp — editing (biggest)
|
|
436
|
+
│ ├── project/internal/projectuiactions.cpp — file/menu
|
|
437
|
+
│ ├── projectscene/internal/projectsceneuiactions.cpp — view/tools
|
|
438
|
+
│ ├── effects/
|
|
439
|
+
│ │ ├── effects_base/internal/effectsuiactions.cpp — effect actions
|
|
440
|
+
│ │ ├── effects_base/ieffectparametersprovider.h — param API
|
|
441
|
+
│ │ ├── builtin_collection/ — builtin effects
|
|
442
|
+
│ │ └── vst/internal/vstparameterextractorservice.* — VST param bridge
|
|
443
|
+
│ └── au3cloud/ — cloud/OAuth
|
|
444
|
+
├── au3/
|
|
445
|
+
│ ├── libraries/au3-vst3/ — VST3 host engine
|
|
446
|
+
│ └── libraries/au3-builtin-effects/ — legacy effects
|
|
447
|
+
└── muse_framework/
|
|
448
|
+
└── framework/
|
|
449
|
+
├── autobot/internal/api/ — autobot JS API
|
|
450
|
+
├── extensions/ — plugin system
|
|
451
|
+
│ ├── api/extapi.h — extension API (MODIFY THIS)
|
|
452
|
+
│ └── internal/extensionsloader.cpp — manifest parser
|
|
453
|
+
├── network/api/
|
|
454
|
+
│ ├── websocketserverapi.* — WS server
|
|
455
|
+
│ └── websocketapi.* — WS client
|
|
456
|
+
├── actions/
|
|
457
|
+
│ ├── iactionsdispatcher.h — dispatcher interface
|
|
458
|
+
│ └── actiontypes.h — ActionData, ActionQuery
|
|
459
|
+
└── vst/internal/ — VST host framework
|
|
460
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Audacity4MCP will be documented in this file.
|
|
4
|
+
|
|
5
|
+
This is early alpha under active daily development.
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-09-05
|
|
8
|
+
|
|
9
|
+
### Realtime/VST3 Effects: New Surface, Three Real Bugs Found Along the Way
|
|
10
|
+
|
|
11
|
+
Built the whole non-destructive effects path this session: `add_realtime_effect`, `list_realtime_effects`, `remove_realtime_effect`, `set_realtime_effect_active`, `list_effect_parameters`, `set_effect_parameter`, `list_effect_presets`, `apply_effect_preset`. This is now the priority effects surface — most users want to tweak a plugin's settings live (reverb decay, EQ curve, compressor ratio), not permanently bake an effect in.
|
|
12
|
+
|
|
13
|
+
Confirming this actually worked against a real VST3 (Valhalla VintageVerb, then FabFilter Pro-Q 3 / Pro-C 2) surfaced three separate, real bugs:
|
|
14
|
+
|
|
15
|
+
- **Realtime effect instances were never registered with `IEffectInstancesRegister`.** Only the UI's own settings-panel dialog does this registration today (`RealtimeEffectViewerDialogModel::reload()`) — headless MCP calls got "Effect instance not found" for every parameter read/write. Fixed by replicating that exact registration pattern (idempotent, checked on first use) in the C++ controller.
|
|
16
|
+
- **`setParameterValue()` silently failed to stick on VST3 plugins.** Calls reported success and even echoed a plausible-looking value, but an independent fresh re-read showed nothing had changed. Root cause: VST3 plugins require `beginParameterGesture()`/`setParameterValue()`/`endParameterGesture()` bracketing to distinguish real automation from a spurious write — a bare call silently no-ops. Fixed by wrapping every write in the gesture calls; verified via a second, independent parameter read after the fact, not just trusting the immediate response.
|
|
17
|
+
- **A Unity-build ambiguous-symbol compile error** (`C2872: 'TranslatableString'`) when linking `au3wrap` into the mcp module — a legacy AU3 header pulled in transitively declares its own non-`muse::` `TranslatableString`, colliding with `using namespace muse;` in the Unity-merged command registrar. Fixed with `SKIP_UNITY_BUILD_INCLUSION ON` on the affected file, matching an existing pattern already used elsewhere in the fork.
|
|
18
|
+
|
|
19
|
+
### Fixed: Bridge Read Buffer Silently Broke on Large Parameter Dumps
|
|
20
|
+
|
|
21
|
+
`bridge_client.py`'s `asyncio.open_connection()` used the default 64KB `StreamReader` line limit. FabFilter Pro-Q 3 (a 24-band EQ) reports 492 real automatable parameters in one response — comfortably over that limit — and the call raised `LimitOverrunError`. Fixed by passing `limit=16*1024*1024` explicitly.
|
|
22
|
+
|
|
23
|
+
### Fixed: `transport_play_region` Ignored the Region It Just Selected
|
|
24
|
+
|
|
25
|
+
Originally composed `select-time` + `play-stop` (a toggle). Live testing proved `play-stop` just resumes wherever playback last was, ignoring the just-set selection entirely. Root cause: `play-stop` and "play this specific selection" are genuinely different actions in Audacity 4 (`PlaybackController::playSelectionAction()`, `action://playback/play-selection`). Added the missing `play-selection` command and switched the tool to use it — verified live (a 60s-offset region reported `playPosition: 62.08` after ~2s of playback, matching offset + elapsed correctly).
|
|
26
|
+
|
|
27
|
+
### Known Limitation, Not Fixed Here: VST3 Discrete/List Parameters Don't Persist
|
|
28
|
+
|
|
29
|
+
Continuous VST3 parameters (frequency, gain, Q, threshold, ratio, attack/release, mix) work correctly through `set_effect_parameter` — verified via independent re-reads. Discrete/list-type parameters (e.g. FabFilter Pro-Q 3's per-band "Shape" selector) do not, even with correct value encoding (raw index and normalized fraction both tested). Root-caused to `VST3Wrapper::FlushParameters` — Audacity's own documented workaround for "plugins that read parameter values directly from the DSP model" — being a no-op for any realtime effect instance, since those stay `mActive == true` for their entire life (confirmed with actual audio playback running during the test, ruling out a "just needs a process() call" explanation). The fix, if pursued, lives in Audacity 4's own VST3 host code, not this server. See [README's Known Gaps](README.md#known-gaps).
|
|
30
|
+
|
|
31
|
+
### Verified Existing Effects Against the Real Plugin Registry, Not Source Presence
|
|
32
|
+
|
|
33
|
+
Several v3 effects were initially wrapped based on source files existing in the fork's tree (Echo, Phaser, Wahwah, Distortion, Repeat, ChangeTempo, ChangeSpeed, Equalization, AutoDuck) — all failed live with "Effect not found." Root cause: source presence in `au3/src/effects/*.cpp` does not mean an effect is actually compiled into this fork's build. Ground truth is the real runtime-generated `known_audio_plugins.json`. Removed all 11 wrappers rather than ship tools that can never succeed; same technique later confirmed `StereoToMono`, `project_edit_metadata`, `analyze_contrast`, `analyze_plot_spectrum`, and `analyze_find_clipping` as genuinely absent too.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- `project_get_info`, `track_get_info`, `select_clip`, `transport_get_play_position`, `list_effects` and the full realtime-effects surface above on the C++ side, plus matching Python wrappers.
|
|
38
|
+
- Analysis tools: `analyze_beat_finder`, `analyze_label_sounds`, `analyze_sample_data_export`.
|
|
39
|
+
- Generators: `generate_silence`, `generate_rhythm_track` (full real parameter set, not a v3 port — tempo/swing/click-type/pitch all confirmed against v4's actual Rhythm Track effect).
|
|
40
|
+
- Full label-region composite ops: `label_cut_regions`, `label_delete_regions`, `label_silence_regions`, `label_split_regions`, `label_join_regions`, plus `label_add_at`, `label_add_batch`, `label_get_all`, `label_find`, `label_regular_intervals`, `label_delete_audio_at`.
|
|
41
|
+
- Full edit/selection/track surfaces ported and verified against v4's real interfaces (not v3's parameter names, which don't carry over — v4 renamed and restructured extensively).
|
|
42
|
+
|
|
43
|
+
### Initial Commits
|
|
44
|
+
|
|
45
|
+
- `6cec293` — Initial commit: Audacity 4 MCP server with audio cleanup pipelines (podcast, audiobook, interview, vocal, live, music mastering, lo-fi).
|
|
46
|
+
- `c2e99a7` — Removed dead pre-discovery scaffolding, fixed a stale tool-count assertion.
|
|
47
|
+
- `ef22bf5` — Python wrappers for the first 7 playback/project MCP commands built on the C++ side.
|