# dsh-vst3-studio 安装指南 本插件通过官方 `dsh plugin` 机制安装。功能与用法见 [`README.md`](./README.md)。 | 插件 | 组合包名 | 功能 | | --- | --- | --- | | dsh-vst3-studio | `dsh-vst3-studio` | 让 AI 操作本机 VST3 插件捏音色、把 MIDI 渲染成音频、串效果链、做客观分析 | 打包产物:`releases/dsh-vst3-studio-0.1.6.tgz`(在 `vst3/` 目录下) ## 1. 前置条件 - 有 `dsh` 命令(发行版安装);从源码 checkout 运行时把下文 `dsh` 换成 `pnpm dsh`。 - 机器上有 **pnpm**(`dsh plugin` 把包管理转发给 pnpm)。 - npm/pnpm 能访问 registry(本机已配腾讯镜像)。 - **不需要** Rust / C++ / Visual Studio / VST3 SDK:`nvst3-host` 自带各平台预编译二进制。 ## 2. 安装 ```sh dsh plugin --profile web add ./releases/dsh-vst3-studio-0.1.6.tgz ``` 会发生什么: 1. 首次使用自动初始化该 profile(`@deepseek-ai/dsh-base` 等内置 bundle 从 dsh 安装目录解析,无需网络); 2. pnpm 把 tgz 装进 `$DSH_HOME/profiles/web/node_modules`,并安装依赖 `nvst3-host`; 3. `dsh` 检测到包声明了 `dsh.bundle`,自动把它追加进 profile 的 `dsh.profile.bundles`。 卸载: ```sh dsh plugin --profile web remove dsh-vst3-studio ``` ### 如果 `nvst3-host` 没装好 `nvst3-host` 的 `binding.gyp` 会让 npm 尝试跑 `node-gyp rebuild`,在受限环境(如沙箱)里会因管道 stdio 被拒而报 `spawn EPERM`。预编译二进制本来就随包发布,跳过生命周期脚本即可: ```sh cd $DSH_HOME/profiles/web npm install nvst3-host --ignore-scripts ``` ## 3. 验证安装 ```sh dsh --profile web --dump-config | Select-String 'dsh-vst3-studio' ``` 应能看到 `# == dsh-vst3-studio` 这一层。然后**重启 dsh(web GUI)**,会话里会出现 11 个工具: ``` vst3_env vst3_scan vst3_inspect vst3_params vst3_set_params vst3_patch vst3_midi vst3_presets vst3_render vst3_variants vst3_analyze ``` 第一件事:让模型调 `vst3_env`,它会报告原生宿主版本(应为 `VST 3.8.0`)、宿主子进程状态与配置目录。再调 `vst3_scan` 应能列出本机插件。 ## 4. 配置 组合包自带默认配置。**改配置不要改安装包里的文件**,在 profile 自己的补丁里按相同 `id` 写一整行覆盖(行会整体替换,`config` 不深合并——要列全想设的键): `$DSH_HOME/profiles/web/cordis.patch.yml`(已有内容就**追加**): ```yaml - id: dsh-vst3-studio name: dsh-vst3-studio config: allowDirs: ['C:/Program Files/Common Files/VST3'] # 安全:只允许加载这些目录下的插件 assetDir: 'D:/audio/vst3-assets' renderDir: 'D:/audio/renders' scanDirs: [] sampleRate: 48000 maxBlockSize: 512 requestTimeoutMs: 120000 renderTimeoutMs: 600000 maxRenderSec: 900 bitDepth: 16 maxCrashes: 5 analyzeByDefault: true logFile: 'D:/audio/host.log' # 预设索引 presetDirs: [] serumPresetPath: '' includeSerumPacks: true maxPackBytes: 536870912 maxIndexEntries: 5000 nexusContentPath: '' # Nexus 库路径;空=自动(注册表 HKLM\SOFTWARE\reFX\Nexus\ContentPath → scanDirs 浅层搜索) exportDir: '' # 导出根目录;空=项目文件夹下的 vst3-exports ``` 完整键表与说明见 [`README.md`](./README.md) 的「配置项」。 > **安全提醒**:加载 VST3 等于在本机以你的用户权限执行第三方原生二进制。默认 `allowDirs` 为空(不限制路径)以换取通用性;如果你只固定用几个插件,强烈建议按上面的例子收紧。 ## 5. 其它安装途径 **A. 开发期免安装加载(`--patch` overlay,改动立即生效)** `my-overlay.yml`: ```yaml - insert: - id: dev-vst3-studio name: 'D:/APP/dsh/vst3/dist/index.js' ``` ```sh dsh --profile web --patch my-overlay.yml ``` 适合开发调试,不写进任何 home,不污染安装。 **B. 手工改 profile 补丁**(不想用 pnpm 时) 把插件目录(含其 `node_modules`)放到能被解析的位置后,往 `$DSH_HOME/profiles/web/cordis.patch.yml` 追加以包名或绝对路径为 `name` 的行。注意 `dsh plugin add` 会自动管理依赖与 bundles 列表,手工方式两者都要自己做。 ## 6. 重新打包(改了源码之后) ```sh cd vst3 npm run build npm pack --pack-destination releases ``` 产物落到 `vst3/releases/*.tgz`,再按第 2 节 `add`(或先 `remove` 旧版再 `add`)。 ## 常见问题 ### 导出目录跑到了 `D:\Program Files\DSH Desktop` 这种地方 桌面版(Electron)里 `DSH_SESSION_JSONL` 只注入给 shell 工具,**没有**注入插件进程, 所以只靠会话环境变量反推工作区的启发式在桌面版里必然失败,导出目录会退回 "dsh 进程工作目录"——也就是 dsh 的安装目录,既不该写、也常常写不进去。 0.1.2 起改为逐级回退,且每一级都**实测可写**才采用: 1. 配置里的 `exportDir`; 2. `DSH_SESSION_JSONL` / `DSH_SESSION_DIR` 推出的工作区; 3. **直接扫 `/sessions/`,取最近写入的会话目录**,其目录名(如 `--D-APP-dsh--`) 解码出来就是当前工作区(会话在持续写入,所以它的 mtime 必然最新); 4. dsh 进程工作目录; 5. 兜底到 `/vst3-studio/vst3-exports`。 `vst3_env` 的「导出目录」一行会同时给出**来源说明**,一眼能看出是哪一级命中的。 想固定位置就直接配 `exportDir`,或在 `vst3_patch {action:"exportBundle", output:"..."}` 里显式给路径。 ### 参数明明"设置成功"了,声音却完全没变 先怀疑**单位口径**。实测 Serum 2 上有两种静默改值: | 写法 | 实际结果 | | --- | --- | | `{"name":"Main Vol","value":50,"mode":"plain"}` | 被解析成 **100%**(钳到最大) | | `{"name":"B Enable","value":"On"}` | 被解析成 **Off** | 两者 `setParameter` 都返回成功。0.1.2 起会自动回读比对,命中就报 `⚠ 疑似被插件改写`。 正确写法:带 `%` 的写 `"55%"`,带时间写 `"1.2s"`,带频率写 `"1200Hz"`,带电平写 `"-9dB"`, 布尔量用 plain `1`/`0`。 其次要怀疑**这个参数根本没接在信号路径上**:Serum 2 的 `Filter 1` 要配合 `Routing Matrix` 的 `X>Filter Balance` 才进链路(默认 `-100` 才是"全送进滤波器", `+100` 反而是直通旁路)。判断办法只有一个——**比对渲染出的音频**(哈希或频谱重心), 不要只看参数回读。 ### 所有工具都报「宿主子进程结束(退出码 0)」,而且 `host.log` 一行都没有 **这是 dsh 桌面版(Electron)特有的坑,0.1.1 已修。** 如果你在旧版本上遇到,症状非常典型: - 连 `vst3_env`(最轻量的命令)都失败,报「连续两次失败…宿主子进程结束(退出码 0)」; - `host.log` 的修改时间停在上一次成功的时候 —— **新一轮子进程连启动日志都没写**; - 手动 `node <插件目录>/dist/host/worker.js --port 1 --token x --log t.log` 却完全正常。 原因是**宿主子进程用哪个可执行文件跑**。dsh 桌面版是 Electron 应用,它的 `process.execPath` 指向 `DSH Desktop.exe`,而: | 拿什么跑 worker.js | 结果 | | --- | --- | | `DSH Desktop.exe`(不加环境变量) | Electron 把 `.js` 当 app 目录去找,撞上已在运行实例的单实例锁 → **立刻退出码 0,一行日志都不写** | | `DSH Desktop.exe` + `ELECTRON_RUN_AS_NODE=1` | 能跑普通脚本,但 **`require('nvst3-host')` 会把进程直接打崩**(退出码 `0xFFFF7003`,崩在 N-API 加载处,JS 的 `try/catch` 都拦不住) | | 真正的 `node.exe` | ✅ 一切正常 | 所以 0.1.1 起,监督器会**优先找一个真正的 node**:`PATH` → `%ProgramFiles%\nodejs` 等常见安装位置 → nvm-windows / fnm / volta;找不到才退到 Electron 兜底(并在说明里明确警告它加载不了原生模块)。 第一个候选「没握手就退出」时会自动换下一个。 自查与修法: ```powershell # 看 vst3_env 里的「宿主运行时」这一行,它直接告诉你用的是哪个可执行文件 # 输出示例:D:\Program Files\nodejs\node.exe(系统 node;…);备用候选 1 个 ``` 如果本机确实没装 node,装一个即可;也可以显式指定: ```yaml # profile 的 cordis.patch.yml - id: vst3-studio # 换成安装层里实际的 id config: nodePath: 'C:\Program Files\nodejs\node.exe' ``` 或临时用环境变量 `DSH_VST3_NODE` 覆盖(优先级低于 `nodePath`)。 ### `dsh plugin add` 报 `ERR_PNPM_IGNORED_BUILDS: nvst3-host@0.3.1` pnpm ≥10(本机是 11.8.0)默认拦截依赖的生命周期脚本;`nvst3-host` 带 `binding.gyp`,所以它的 `install` 脚本被拦下。而 dsh **只在 pnpm 退出码为 0 时才把插件登记进 `bundles`**(见 `@deepseek-ai/dsh` 的 `plugin-*.js`:`if (exitCode === 0) reconcilePlugins(...)`),于是安装看起来失败了。 正确做法是**在 profile 里明确拒掉这个构建**(不是放行): ```yaml # $DSH_HOME/profiles/web/pnpm-workspace.yaml allowBuilds: nvst3-host: false ``` 为什么是 `false` 而不是 `true`: - `nvst3-host/index.js` 在 **require 时**用 `node-gyp-build` 定位预编译二进制 (`prebuilds/win32-x64/nvst3-host.node`),**装完就能用,根本不需要运行安装脚本**; - 它的 `install` 脚本只是 `node-gyp-build` 这个**定位器**;一旦放行,它会因为找不到匹配的预编译而回退调用 `node-gyp rebuild`,而 pnpm 11 自带的 node-gyp 在该发行版里路径不存在,必然失败。 改完重跑 `dsh plugin add`,再确认 `bundles` 已登记: ```powershell (Get-Content $env:USERPROFILE\.dsh\profiles\web\package.json -Raw | ConvertFrom-Json).dsh.profile.bundles ``` 也可以直接验证插件能从 profile 加载(不必重启 dsh): ```powershell cd $env:USERPROFILE\.dsh\profiles\web node -e "import('dsh-vst3-studio').then(m=>console.log('加载成功', typeof m.apply))" ``` ### 安装时报 `ENOENT ... dsh-browser-agent-0.1.0.tgz`(或别的旧路径) profile 的 `package.json` 里存着指向 tgz 的 **`file:` 绝对路径**。如果你挪动过那些 tgz(例如把 `releases/` 换了位置),这条路径就失效了;而 pnpm 安装时会解析 profile 的**全部**依赖—— **一条旧路径失效就会让后续任何安装都失败**(包括装完全无关的插件),报错还会指向那个无关的包名, 很容易误判。 修法:把 `~/.dsh/profiles/web/package.json` 里那条 `file:` 路径改成 tgz 的新位置,或先 `dsh plugin --profile web remove <包名>` 移除它再装。 ### profile 目录在哪 `$DSH_HOME/profiles/web/`(`$DSH_HOME` 默认 `~/.dsh`)。关键文件: `package.json`(依赖 + `dsh.profile.bundles` 登记表)、`pnpm-workspace.yaml`(pnpm 配置,含 `allowBuilds`)、 `cordis.patch.yml`(你对该 profile 的补丁层)。 ### 其它 - **`dsh plugin` 报找不到 pnpm**:装 pnpm(`npm i -g pnpm`)后重试。 - **改了配置不生效**:补丁行按 `id` 覆盖、`config` 整体替换;确认覆盖行的 id 与安装层一致,且重启了 dsh。 - **GUI 正在运行**:安装/改层后需重启 dsh,工具列表才会刷新。 - **首次渲染很慢**:第一次会拉起宿主子进程并加载插件,之后同一会话内复用(扫描结果也缓存 5 分钟)。 - **插件把宿主搞崩了**:这是设计内的。崩溃只终止宿主子进程,dsh 不受影响,下一次调用自动重启(并自动重试一次);崩溃次数会出现在 `vst3_env` 里,现场细节在 `logFile`。60 秒内崩溃超过 `maxCrashes` 次会停止自动重启并提示换插件。 - **找不到某个插件**:用 `vst3_scan` 的 `dirs` 显式指定它的目录;注意必须是 `.vst3` 模块(Windows 上是目录 bundle),不是插件包内的 dll。 - **Nexus 预设搜不到**:确认 `nexusContentPath`(留空则自动从注册表读),或用 `vst3_presets { action: "addSource", dir: "\\Presets" }` 手动加。