Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .github/workflows/ci-v3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: CI v3

# v3(TimecodeBridge3)の Windows 検証。v3.0.0 の Windows 版は起動直後に落ちていた(app.manifest が無く WebView を埋め込めない)が、
# タグを打つまで Windows で一度も起動しない流れだったため気づけなかった。PR と feature/v3 への push で、
# ビルド・テスト・発行物の起動 smoke・インストーラーで入れたものの起動 smoke まで通す。
# (GitHub の Windows ランナーには音声デバイスが無いので LTC の受信は確かめない。LTC は手元で smoke-windows.ps1 -LoopbackDevice)
on:
push:
branches: [feature/v3]
pull_request:
branches: [feature/v3]
workflow_dispatch:

jobs:
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: src/TimecodeBridge.Web/package-lock.json
- uses: ilammy/msvc-dev-cmd@v1

# dist の差分検査は release-v3 の macOS ジョブで行う(Windows は改行コードの自動変換で偽の差分が出る)
- name: Build Web UI
working-directory: src/TimecodeBridge.Web
shell: bash
run: |
npm ci
npm run typecheck
npm test
npm run build

- name: Build libltc.dll
shell: cmd
run: native\libltc\build-windows.cmd native\libltc\out

- name: Test (Ltc / Host)
shell: bash
run: |
dotnet test tests/TimecodeBridge.Ltc.Tests
dotnet test tests/TimecodeBridge.Host.Tests

- name: Publish (win-x64)
shell: bash
run: |
set -euo pipefail
dotnet publish src/TimecodeBridge.Host/TimecodeBridge.Host.csproj \
-c Release --self-contained -r win-x64 -o publish
test -f publish/libltc.dll
test -f publish/web/index.html
cp THIRD_PARTY_NOTICES.md publish/

- name: Ensure WebView2 runtime
shell: pwsh
run: |
$id = '{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}'
$pv = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\$id", "HKCU:\Software\Microsoft\EdgeUpdate\Clients\$id" |
ForEach-Object { (Get-ItemProperty $_ -ErrorAction SilentlyContinue).pv } | Where-Object { $_ -and $_ -ne '0.0.0.0' } | Select-Object -First 1
if ($pv) { "WebView2 runtime $pv"; exit 0 }
Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -OutFile "$env:RUNNER_TEMP\MicrosoftEdgeWebview2Setup.exe"
Start-Process "$env:RUNNER_TEMP\MicrosoftEdgeWebview2Setup.exe" -ArgumentList '/silent', '/install' -Wait

- name: Smoke (publish)
shell: pwsh
run: pwsh tools/tcb3/smoke-windows.ps1 -Exe publish\TimecodeBridge3.exe -RunDir "$env:RUNNER_TEMP\smoke-publish"

- name: Build installer
shell: pwsh
run: |
Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -OutFile installer/MicrosoftEdgeWebview2Setup.exe
iscc /DAppVersion=0.0.0 installer\TimecodeBridge3.iss

# 利用者と同じくインストーラーで入れ(ユーザー単位・サイレント)、入ったものを起動して確かめる
- name: Install and smoke (installer)
shell: pwsh
run: |
$dir = Join-Path $env:RUNNER_TEMP 'tcb3-installed'
$log = Join-Path $env:RUNNER_TEMP 'install.log'
$setup = (Get-Item installer-output\TimecodeBridge3-Setup-*.exe).FullName
$p = Start-Process $setup -ArgumentList '/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART', "/DIR=$dir", "/LOG=$log" -Wait -PassThru
if ($p.ExitCode -ne 0) { Get-Content $log -Tail 40; throw "installer exit $($p.ExitCode)" }
pwsh tools/tcb3/smoke-windows.ps1 -Exe (Join-Path $dir 'TimecodeBridge3.exe') -RunDir "$env:RUNNER_TEMP\smoke-installed"

- uses: actions/upload-artifact@v4
if: always()
with:
name: windows-smoke
path: |
${{ runner.temp }}/smoke-publish/
${{ runner.temp }}/smoke-installed/
${{ runner.temp }}/install.log
if-no-files-found: ignore
19 changes: 19 additions & 0 deletions .github/workflows/release-v3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ jobs:
test -f publish/libltc.dll
test -f publish/web/index.html
cp THIRD_PARTY_NOTICES.md publish/

# 起動しないビルドを出さない(v3.0.0 の Windows 版は起動直後に落ちていた)。詳しい確認は ci-v3.yml
- name: Ensure WebView2 runtime
shell: pwsh
run: |
$id = '{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}'
$pv = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\$id", "HKCU:\Software\Microsoft\EdgeUpdate\Clients\$id" |
ForEach-Object { (Get-ItemProperty $_ -ErrorAction SilentlyContinue).pv } | Where-Object { $_ -and $_ -ne '0.0.0.0' } | Select-Object -First 1
if ($pv) { "WebView2 runtime $pv"; exit 0 }
Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -OutFile "$env:RUNNER_TEMP\MicrosoftEdgeWebview2Setup.exe"
Start-Process "$env:RUNNER_TEMP\MicrosoftEdgeWebview2Setup.exe" -ArgumentList '/silent', '/install' -Wait

- name: Smoke (publish)
shell: pwsh
run: pwsh tools/tcb3/smoke-windows.ps1 -Exe publish\TimecodeBridge3.exe -RunDir "$env:RUNNER_TEMP\smoke-publish"

- name: Zip (win-x64)
shell: bash
run: |
cd publish && 7z a "../TimecodeBridge3-${{ github.ref_name }}-win-x64.zip" .

# WebView2 Evergreen ブートストラッパーを取得し、未導入 PC で実行するインストーラーを作る
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ macOS 15 以降では、ファイルを右クリックして「開く」を選

## ライセンス

本体は [LICENSE](LICENSE) のとおり。LTC の復号・生成に使う libltc は LGPL-2.1 で、動的リンクのまま同梱しています。同梱物の一覧は [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
本体は [LICENSE](LICENSE) のとおり。LTC の復号に使う libltc は LGPL-3.0-or-later で、動的リンクのまま同梱しています。同梱物の一覧は [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
38 changes: 35 additions & 3 deletions docs/v3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ dotnet build src/TimecodeBridge.Host/TimecodeBridge.Host.csproj

`dotnet build` は `native/libltc/out/libltc.dylib` と `src/TimecodeBridge.Web/dist` を実行ファイルの隣(`libltc.dylib`, `web/`)へコピーします。どちらかが無いとビルド時に警告が出て、起動時に見つからない旨のエラーになります。

## 初回セットアップ(Windows)

Visual Studio 2022(C++ によるデスクトップ開発)、.NET 8 以降の SDK、Node.js 22 以降が要ります。libltc は Developer Command Prompt(vcvars64)で `cl` を使ってビルドします。

```powershell
cmd /c '"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" && native\libltc\build-windows.cmd native\libltc\out'
cd src\TimecodeBridge.Web; npm ci; npm run build; cd ..\..
dotnet build src\TimecodeBridge.Host\TimecodeBridge.Host.csproj # → src\TimecodeBridge.Host\bin\Debug\net8.0\TimecodeBridge3.exe
```

- 日本語 Windows では libltc のビルドで C4819 の警告が出ますが、`ltc.h` のコメント内の文字(`ß` `±`)なので無害です。
- Windows で `npm run build` すると `dist/` に差分が出ることがありますが、改行コード(CRLF/LF)だけです。コミットしないでください(`git checkout -- src/TimecodeBridge.Web/dist`)。
- `src/TimecodeBridge.Host/app.manifest` は消さないでください。対応 OS の宣言が無いと、Avalonia が WebView 用の子ウィンドウを作れず起動直後に落ちます(v3.0.0 の Windows 版で発生)。
- WebView2 のユーザーデータは `%LOCALAPPDATA%\TimecodeBridge3\WebView2`(`TIMECODEBRIDGE_DATA_DIR` があればその下の `WebView2`)に置きます。既定の「実行ファイルの隣」は Program Files に入れると書けず、起動直後に `E_ACCESSDENIED` で落ちます。

## 起動

```sh
Expand All @@ -22,13 +37,13 @@ dotnet build src/TimecodeBridge.Host/TimecodeBridge.Host.csproj

| 変数 | 内容 |
|---|---|
| `TIMECODEBRIDGE_SELFTEST_OUTPUT=<出力デバイス名の一部>` | 同一プロセス内で LTC(30fps, 01:00:00:00 から)を生成してその出力へ流す |
| `TIMECODEBRIDGE_SELFTEST_OUTPUT=<出力デバイス名の一部>` | 同一プロセス内で LTC(30fps, 01:00:00:00 から)を生成してその出力へ流す(macOS のみ。Windows は下記の smoke-windows.ps1 で 2 つ目の Host に生成させる) |
| `TIMECODEBRIDGE_AUTOSTART_INPUT=<入力デバイス名の一部>` | 接続直後にそのデバイスで LTC 受信を始める |
| `TIMECODEBRIDGE_BRIDGE_TRACE=1` / `2` | Web との送受信・受信状態を標準出力へ(2 は毎フレームの時計も) |
| `TIMECODEBRIDGE_WEB_DIST=<dist ディレクトリ>` | 同梱の web/ ではなくそのディレクトリの index.html を開く(Web 開発中に便利) |
| `TIMECODEBRIDGE_LIBLTC=<dylib のフルパス>` | 同梱の libltc ではなくそのファイルを読み込む |
| `TIMECODEBRIDGE_AUTOMATION_PORT=<port>` | 127.0.0.1:<port> で自動操作用の HTTP を待ち受ける(下記「人手なしの実機確認」) |
| `TIMECODEBRIDGE_DATA_DIR=<dir>` | 設定(最近使ったプロジェクト)の保存先を変える。tcb3ctl は `$TCB3_RUN_DIR/data` を渡し、試験用インスタンスが利用者の設定を書き換えないようにする |
| `TIMECODEBRIDGE_DATA_DIR=<dir>` | 設定(最近使ったプロジェクト)の保存先を変える。tcb3ctl は `$TCB3_RUN_DIR/data` を渡し、試験用インスタンスが利用者の設定を書き換えないようにする。Windows では WebView2 のユーザーデータもこの下の `WebView2` に置く |

Pro Tools Audio Bridge のような仮想ループバックは、再生と取り込みが別プロセスだとタイムコードが乱れます。ハードウェアなしで確かめるときは `TIMECODEBRIDGE_SELFTEST_OUTPUT` を使ってください。

Expand Down Expand Up @@ -90,6 +105,21 @@ tools/tcb3/tcb3ctl reload && tools/tcb3/tcb3ctl shot /tmp/tcb3ctl/after.png # H

Codex を herdr のペインで動かす場合(`herdr agent start <name> --kind codex --pane <id> -- -s workspace-write -a never -c sandbox_workspace_write.network_access=true`)も、この `tcb3ctl reload` / `shot` をそのまま使えます。`network_access=true` が無いとサンドボックスから 127.0.0.1 の自動操作口に届きません。Codex は撮った PNG を自分の画像表示ツールで開いて確認できます(実機で確認済み)。Codex のサンドボックスでは headless Chrome が起動できない(プロファイル先やヘルパープロセスの制約で SIGABRT)ので、見た目の確認は実機一本にしてください。ループバックのデバイス名は `TCB3_SELFTEST_DEVICE`、作業ファイルの置き場は `TCB3_RUN_DIR`(既定 `/tmp/tcb3ctl`)で変えられます。`osc_listen.py` は単体でも使え、届いた OSC を 1 行 1 メッセージの JSON で出します。

## 人手なしの実機確認(Windows)

tcb3ctl / smoke.sh は macOS 専用です(`pgrep`・`ps eww`・`jq` を使い、`/screenshot` も Windows では 501)。Windows では `tools/tcb3/smoke-windows.ps1`(pwsh 7、jq・python 不要)で通し確認をします。自動操作口(`/health` `/state` `/command` `/eval` など)は Windows でもそのまま使えます。

```powershell
pwsh tools/tcb3/smoke-windows.ps1 # Debug ビルドを起動 → Web ready → OSC 発火と受信 → 送信ログと画面 → 撮影
pwsh tools/tcb3/smoke-windows.ps1 -Exe publish\TimecodeBridge3.exe # 発行物(CI と同じ)
pwsh tools/tcb3/smoke-windows.ps1 -LoopbackDevice "CABLE In 16ch" # 2 つ目の Host が LTC を生成してその出力へ流し、1 つ目がループバックで受けてキュー発火まで確認
```

- `SMOKE PASS` / `SMOKE FAIL` で終わり、終了コードも 0 / 1。作業ファイル・ログ・撮影(`smoke.png`)は `-RunDir`(既定 `%TEMP%\tcb3-smoke`)に出ます。`-Keep` で Host を残します。
- Windows では出力デバイスが入力一覧に「(Loopback)」付きで並び、WASAPI のループバック取り込みで受信できます(再生と取り込みが別プロセスでも乱れない)。`-LoopbackDevice` には VB-Audio Virtual Cable のような聞こえない出力を指定してください(スピーカーを指定すると LTC が鳴ります)。
- 撮影は `PrintWindow`(PW_RENDERFULLCONTENT)で行うので、前面化しなくても WebView の中身が写ります。
- GitHub の Windows ランナーには音声デバイスが無いので、CI(`.github/workflows/ci-v3.yml`)は `-LoopbackDevice` なしで、発行物とインストーラーで入れたものの両方を確認します。

## Web UI の変更

Web は Codex が担当しています。`dist/` は git 管理で、CI が再ビルドして差分が無いことを検査するため、変更後は必ず `npm run build` の結果をコミットしてください。見た目の確認は、手元の macOS では上の tcb3ctl(実機)を使ってください。Codex のサンドボックス外で素早く確認するだけなら headless Chrome でも描画できます(WebKit だけの見え方、たとえば number input のスピナーは Chrome では出ません)。
Expand All @@ -102,4 +132,6 @@ Web は Codex が担当しています。`dist/` は git 管理で、CI が再

## リリース

`v3.*` のタグで `.github/workflows/release-v3.yml` が動き、macOS(Apple Silicon)の `TimecodeBridge3.app`(zip)と Windows の zip・インストーラー(WebView2 ランタイムを未導入なら導入)を作ります。libltc は LGPL-3.0 のため動的リンクで同梱し、`THIRD_PARTY_NOTICES.md` と `libltc-COPYING.txt` を含めます。
`v3.*` のタグで `.github/workflows/release-v3.yml` が動き、macOS(Apple Silicon)の `TimecodeBridge3.app`(zip)と Windows の zip・インストーラー(WebView2 ランタイムを未導入なら導入)を作ります。Windows は zip にする前に発行物を smoke-windows.ps1 で起動して確かめ、起動しないビルドは出しません。libltc は LGPL-3.0 のため動的リンクで同梱し、`THIRD_PARTY_NOTICES.md` と `libltc-COPYING.txt` を含めます。

PR と `feature/v3` への push では `.github/workflows/ci-v3.yml` が Windows でビルド・テスト(Ltc / Host)・発行物の smoke・インストーラーを作ってサイレントインストールしたものの smoke を行います。
2 changes: 1 addition & 1 deletion docs/v3/bridge-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ M0合否目安(推測): clock+wave、1000 cues表示を10分継続し、入
|`project.new/open/save/saveAs`|`{path?,suggestedName?}`|`{cancelled,path?}` / `invalidProject`,`ioError`。open/save/saveAs は `path` を渡すとネイティブダイアログを出さずにそのファイルを読む/書く(自動操作向け。フォルダが無ければ `ioError`)|
|`mode.set`|`{mode}`|`{ltcStarted}` / `validation`。ltc へ切り替えたとき、選択済みの入力デバイスがあれば Host が自動で受信を再開する(未選択なら停止のまま)|
|`ltc.start/stop/reconnect`|`{deviceId?}`|`deviceNotFound`,`audioError`,`nativeError`|
|`audio.refreshDevices`|`{direction}`|patch / `audioError`|
|`audio.refreshDevices`|`{direction}`|patch / `audioError`。Host は裏のスレッドでデバイスを列挙し直し、終わってから一覧の patch と result を返す(Windows で 0.5〜1 秒。その間も時計や他の command は止まらず、一覧は古いまま)。Web は result が返るまでスキャン中を表示する。一覧はこの command まで使い回す|
|`receive.selectDevice`|`{deviceId}`|`deviceId` が null/空なら「未選択」に戻す(受信を止めて選択を消す)。それ以外は `ltc.reconnect` と同じ / `deviceNotFound`,`audioError`|
|`receive.setOffset`|`{value}`|`{normalized}` / `validation`|
|`receive.setTriggerWindow`|`{frames}`|`{frames}` / `validation`|
Expand Down
Loading
Loading