From b6daa813045895aff725f19f6e33cc8864f23f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Fri, 20 Mar 2026 13:03:32 +0100 Subject: [PATCH] Feat: big movement for ASIO --- .cargo/config.toml | 5 - .gitea/workflows/assemble-macos.yml | 135 ------------ .gitea/workflows/build-cross.yml | 49 ----- .gitea/workflows/build-linux.yml | 131 ------------ .gitea/workflows/build-macos.yml | 127 ----------- .gitea/workflows/build-plugins-linux.yml | 56 ----- .gitea/workflows/build-plugins-macos.yml | 66 ------ .gitea/workflows/build-plugins-rpi.yml | 57 ----- .gitea/workflows/build-plugins-windows.yml | 59 ------ .gitea/workflows/build-plugins.yml | 17 -- .gitea/workflows/build-windows.yml | 134 ------------ .gitea/workflows/ci.yml | 23 -- .gitea/workflows/release.yml | 111 ---------- BUILDING.md | 55 ++--- CHANGELOG.md | 6 + Cargo.lock | 36 ++-- Cargo.toml | 7 +- Cross.toml | 3 - README.md | 6 +- build.rs | 23 +- nsis/cagire.nsi | 114 ---------- nsis/header.bmp | Bin 25818 -> 0 bytes nsis/sidebar.bmp | Bin 154542 -> 0 bytes plugins/cagire-plugins/Cargo.toml | 2 +- scripts/build.py | 100 ++++----- scripts/cross/x86_64-windows.Dockerfile | 19 -- scripts/platforms.toml | 2 +- src/engine/audio.rs | 231 ++++++++++++--------- 28 files changed, 236 insertions(+), 1338 deletions(-) delete mode 100644 .gitea/workflows/assemble-macos.yml delete mode 100644 .gitea/workflows/build-cross.yml delete mode 100644 .gitea/workflows/build-linux.yml delete mode 100644 .gitea/workflows/build-macos.yml delete mode 100644 .gitea/workflows/build-plugins-linux.yml delete mode 100644 .gitea/workflows/build-plugins-macos.yml delete mode 100644 .gitea/workflows/build-plugins-rpi.yml delete mode 100644 .gitea/workflows/build-plugins-windows.yml delete mode 100644 .gitea/workflows/build-plugins.yml delete mode 100644 .gitea/workflows/build-windows.yml delete mode 100644 .gitea/workflows/ci.yml delete mode 100644 .gitea/workflows/release.yml delete mode 100644 nsis/cagire.nsi delete mode 100644 nsis/header.bmp delete mode 100644 nsis/sidebar.bmp delete mode 100644 scripts/cross/x86_64-windows.Dockerfile diff --git a/.cargo/config.toml b/.cargo/config.toml index 93c06d5..8c8a538 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,8 +3,3 @@ MACOSX_DEPLOYMENT_TARGET = "12.0" [alias] xtask = "run --package xtask --release --" - -[target.x86_64-pc-windows-gnu] -rustflags = [ - "-C", "link-args=-Wl,-Bstatic -lstdc++ -lgcc -lgcc_eh -lpthread -Wl,-Bdynamic -lmingwex -lmsvcrt -lws2_32 -liphlpapi -lwinmm -lole32 -loleaut32 -luuid -lkernel32", -] diff --git a/.gitea/workflows/assemble-macos.yml b/.gitea/workflows/assemble-macos.yml deleted file mode 100644 index cc82820..0000000 --- a/.gitea/workflows/assemble-macos.yml +++ /dev/null @@ -1,135 +0,0 @@ -name: Assemble macOS Universal - -on: - workflow_call: - -jobs: - assemble: - runs-on: macos-14 - timeout-minutes: 10 - - steps: - - name: Download macOS artifacts - uses: actions/download-artifact@v4 - with: - pattern: cagire-macos-* - path: artifacts - - - name: Create universal CLI binary - run: | - lipo -create \ - artifacts/cagire-macos-x86_64/cagire \ - artifacts/cagire-macos-aarch64/cagire \ - -output cagire - chmod +x cagire - lipo -info cagire - - - name: Create universal app bundle - run: | - cd artifacts/cagire-macos-aarch64-desktop - unzip Cagire.app.zip - cd ../cagire-macos-x86_64-desktop - unzip Cagire.app.zip - cd ../.. - cp -R artifacts/cagire-macos-aarch64-desktop/Cagire.app Cagire.app - lipo -create \ - artifacts/cagire-macos-x86_64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \ - artifacts/cagire-macos-aarch64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \ - -output Cagire.app/Contents/MacOS/cagire-desktop - lipo -info Cagire.app/Contents/MacOS/cagire-desktop - zip -r Cagire.app.zip Cagire.app - - - name: Create universal CLAP plugin - run: | - mkdir -p cagire-plugins.clap/Contents/MacOS - cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/Info.plist \ - cagire-plugins.clap/Contents/ 2>/dev/null || true - cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/PkgInfo \ - cagire-plugins.clap/Contents/ 2>/dev/null || true - lipo -create \ - artifacts/cagire-macos-x86_64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \ - artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \ - -output cagire-plugins.clap/Contents/MacOS/cagire-plugins - lipo -info cagire-plugins.clap/Contents/MacOS/cagire-plugins - - - name: Create universal VST3 plugin - run: | - mkdir -p cagire-plugins.vst3/Contents/MacOS - cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Info.plist \ - cagire-plugins.vst3/Contents/ 2>/dev/null || true - cp artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/PkgInfo \ - cagire-plugins.vst3/Contents/ 2>/dev/null || true - cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Resources \ - cagire-plugins.vst3/Contents/ 2>/dev/null || true - lipo -create \ - artifacts/cagire-macos-x86_64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \ - artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \ - -output cagire-plugins.vst3/Contents/MacOS/cagire-plugins - lipo -info cagire-plugins.vst3/Contents/MacOS/cagire-plugins - - - uses: actions/checkout@v4.2.2 - with: - sparse-checkout: | - assets/DMG-README.txt - scripts/make-dmg.sh - clean: false - - - name: Create DMG - run: | - chmod +x scripts/make-dmg.sh - scripts/make-dmg.sh Cagire.app . - - - name: Build .pkg installer - run: | - VERSION="${GITEA_REF_NAME#v}" - mkdir -p pkg-root/Applications pkg-root/usr/local/bin - cp -R Cagire.app pkg-root/Applications/ - cp cagire pkg-root/usr/local/bin/ - pkgbuild --analyze --root pkg-root component.plist - plutil -replace BundleIsRelocatable -bool NO component.plist - pkgbuild --root pkg-root --identifier com.sova.cagire \ - --version "$VERSION" --install-location / \ - --component-plist component.plist \ - "Cagire-${VERSION}-universal.pkg" - - - name: Upload universal CLI - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal - path: cagire - - - name: Upload universal app bundle - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-desktop - path: Cagire.app.zip - - - name: Prepare universal plugin staging - run: | - mkdir -p staging/clap staging/vst3 - cp -R cagire-plugins.clap staging/clap/ - cp -R cagire-plugins.vst3 staging/vst3/ - - - name: Upload universal CLAP plugin - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-clap - path: staging/clap/ - - - name: Upload universal VST3 plugin - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-vst3 - path: staging/vst3/ - - - name: Upload DMG - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-dmg - path: Cagire-*.dmg - - - name: Upload .pkg installer - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-pkg - path: Cagire-*-universal.pkg diff --git a/.gitea/workflows/build-cross.yml b/.gitea/workflows/build-cross.yml deleted file mode 100644 index 9e23ed0..0000000 --- a/.gitea/workflows/build-cross.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Build Cross (Linux ARM64) - -on: - workflow_call: - workflow_dispatch: - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: aarch64-unknown-linux-gnu - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: aarch64-unknown-linux-gnu - - - name: Install cross - run: cargo install cross --git https://github.com/cross-rs/cross - - - name: Build - run: cross build --release --target aarch64-unknown-linux-gnu - - - name: Build desktop - run: cross build --release --features desktop --bin cagire-desktop --target aarch64-unknown-linux-gnu - - - name: Upload CLI artifact - uses: actions/upload-artifact@v4 - with: - name: cagire-linux-aarch64 - path: target/aarch64-unknown-linux-gnu/release/cagire - - - name: Upload desktop artifact - uses: actions/upload-artifact@v4 - with: - name: cagire-linux-aarch64-desktop - path: target/aarch64-unknown-linux-gnu/release/cagire-desktop diff --git a/.gitea/workflows/build-linux.yml b/.gitea/workflows/build-linux.yml deleted file mode 100644 index d9ecd78..0000000 --- a/.gitea/workflows/build-linux.yml +++ /dev/null @@ -1,131 +0,0 @@ -name: Build Linux - -on: - workflow_call: - inputs: - run-tests: - type: boolean - default: false - run-clippy: - type: boolean - default: false - build-packages: - type: boolean - default: false - workflow_dispatch: - inputs: - run-tests: - type: boolean - default: true - run-clippy: - type: boolean - default: true - build-packages: - type: boolean - default: false - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: x86_64-unknown-linux-gnu - components: clippy - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: x86_64-unknown-linux-gnu - - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y build-essential cmake pkg-config libasound2-dev libclang-dev libjack-dev \ - libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev libgl1-mesa-dev \ - libx11-dev libx11-xcb-dev libxcursor-dev libxrandr-dev libxi-dev libwayland-dev - - - name: Build - run: cargo build --release --target x86_64-unknown-linux-gnu - - - name: Build desktop - run: cargo build --release --features desktop --bin cagire-desktop --target x86_64-unknown-linux-gnu - - - name: Test - if: inputs.run-tests - run: cargo test --target x86_64-unknown-linux-gnu - - - name: Clippy - if: inputs.run-clippy - run: cargo clippy --target x86_64-unknown-linux-gnu -- -D warnings - - - name: Install cargo-bundle - if: inputs.build-packages - run: cargo install cargo-bundle - - - name: Bundle desktop app - if: inputs.build-packages - run: cargo bundle --release --features desktop --bin cagire-desktop --target x86_64-unknown-linux-gnu - - - name: Build AppImages - if: inputs.build-packages - run: | - mkdir -p target/releases - scripts/make-appimage.sh target/x86_64-unknown-linux-gnu/release/cagire x86_64 target/releases - scripts/make-appimage.sh target/x86_64-unknown-linux-gnu/release/cagire-desktop x86_64 target/releases - - - name: Bundle CLAP plugin - if: inputs.build-packages - run: cargo xtask bundle cagire-plugins --release --target x86_64-unknown-linux-gnu - - - name: Upload CLI artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-linux-x86_64 - path: target/x86_64-unknown-linux-gnu/release/cagire - - - name: Upload desktop artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-linux-x86_64-desktop - path: target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb - - - name: Upload AppImage artifacts - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-linux-x86_64-appimage - path: target/releases/*.AppImage - - - name: Prepare plugin artifacts - if: inputs.build-packages - run: | - mkdir -p staging/clap staging/vst3 - cp -R target/bundled/cagire-plugins.clap staging/clap/ - cp -R target/bundled/cagire-plugins.vst3 staging/vst3/ - - - name: Upload CLAP artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-linux-x86_64-clap - path: staging/clap/ - - - name: Upload VST3 artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-linux-x86_64-vst3 - path: staging/vst3/ diff --git a/.gitea/workflows/build-macos.yml b/.gitea/workflows/build-macos.yml deleted file mode 100644 index df5ada2..0000000 --- a/.gitea/workflows/build-macos.yml +++ /dev/null @@ -1,127 +0,0 @@ -name: Build macOS - -on: - workflow_call: - inputs: - run-tests: - type: boolean - default: false - run-clippy: - type: boolean - default: false - build-packages: - type: boolean - default: false - matrix: - type: string - default: '[{"os":"macos-14","target":"aarch64-apple-darwin","artifact":"cagire-macos-aarch64"}]' - workflow_dispatch: - inputs: - run-tests: - type: boolean - default: true - run-clippy: - type: boolean - default: true - build-packages: - type: boolean - default: false - matrix: - type: string - default: '[{"os":"macos-14","target":"aarch64-apple-darwin","artifact":"cagire-macos-aarch64"}]' - -env: - CARGO_TERM_COLOR: always - MACOSX_DEPLOYMENT_TARGET: "12.0" - -jobs: - build: - strategy: - fail-fast: false - matrix: - include: ${{ fromJSON(inputs.matrix) }} - - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.target }} - components: clippy - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - - - name: Install dependencies - run: brew list cmake &>/dev/null || brew install cmake - - - name: Build - run: cargo build --release --target ${{ matrix.target }} - - - name: Build desktop - run: cargo build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }} - - - name: Test - if: inputs.run-tests - run: cargo test --target ${{ matrix.target }} - - - name: Clippy - if: inputs.run-clippy - run: cargo clippy --target ${{ matrix.target }} -- -D warnings - - - name: Bundle desktop app - if: inputs.build-packages - run: scripts/make-app-bundle.sh ${{ matrix.target }} - - - name: Bundle CLAP plugin - if: inputs.build-packages - run: cargo xtask bundle cagire-plugins --release --target ${{ matrix.target }} - - - name: Zip macOS app bundle - if: inputs.build-packages - run: | - cd target/${{ matrix.target }}/release/bundle/osx - zip -r Cagire.app.zip Cagire.app - - - name: Upload CLI artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }} - path: target/${{ matrix.target }}/release/cagire - - - name: Upload desktop artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-desktop - path: target/${{ matrix.target }}/release/bundle/osx/Cagire.app.zip - - - name: Prepare plugin artifacts - if: inputs.build-packages - run: | - mkdir -p staging/clap staging/vst3 - cp -R target/bundled/cagire-plugins.clap staging/clap/ - cp -R target/bundled/cagire-plugins.vst3 staging/vst3/ - - - name: Upload CLAP artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-clap - path: staging/clap/ - - - name: Upload VST3 artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-vst3 - path: staging/vst3/ diff --git a/.gitea/workflows/build-plugins-linux.yml b/.gitea/workflows/build-plugins-linux.yml deleted file mode 100644 index 6502a00..0000000 --- a/.gitea/workflows/build-plugins-linux.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Build Plugins Linux - -on: - workflow_call: - workflow_dispatch: - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: x86_64-unknown-linux-gnu - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: x86_64-unknown-linux-gnu-plugins - - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y build-essential cmake pkg-config libasound2-dev libclang-dev libjack-dev \ - libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev libgl1-mesa-dev \ - libx11-dev libx11-xcb-dev libxcursor-dev libxrandr-dev libxi-dev libwayland-dev - - - name: Build plugins - run: cargo xtask bundle cagire-plugins --release --target x86_64-unknown-linux-gnu - - - name: Prepare plugin artifacts - run: | - mkdir -p staging/clap staging/vst3 - cp -R target/bundled/cagire-plugins.clap staging/clap/ - cp -R target/bundled/cagire-plugins.vst3 staging/vst3/ - - - name: Upload CLAP artifact - uses: actions/upload-artifact@v4 - with: - name: plugins-linux-x86_64-clap - path: staging/clap/ - - - name: Upload VST3 artifact - uses: actions/upload-artifact@v4 - with: - name: plugins-linux-x86_64-vst3 - path: staging/vst3/ diff --git a/.gitea/workflows/build-plugins-macos.yml b/.gitea/workflows/build-plugins-macos.yml deleted file mode 100644 index 749e0a9..0000000 --- a/.gitea/workflows/build-plugins-macos.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Build Plugins macOS - -on: - workflow_call: - inputs: - matrix: - type: string - default: '[{"os":"macos-14","target":"aarch64-apple-darwin","artifact":"plugins-macos-aarch64"},{"os":"macos-15-intel","target":"x86_64-apple-darwin","artifact":"plugins-macos-x86_64"}]' - workflow_dispatch: - inputs: - matrix: - type: string - default: '[{"os":"macos-14","target":"aarch64-apple-darwin","artifact":"plugins-macos-aarch64"}]' - -env: - CARGO_TERM_COLOR: always - MACOSX_DEPLOYMENT_TARGET: "12.0" - -jobs: - build: - strategy: - fail-fast: false - matrix: - include: ${{ fromJSON(inputs.matrix) }} - - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.target }} - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }}-plugins - - - name: Install dependencies - run: brew list cmake &>/dev/null || brew install cmake - - - name: Build plugins - run: cargo xtask bundle cagire-plugins --release --target ${{ matrix.target }} - - - name: Prepare plugin artifacts - run: | - mkdir -p staging/clap staging/vst3 - cp -R target/bundled/cagire-plugins.clap staging/clap/ - cp -R target/bundled/cagire-plugins.vst3 staging/vst3/ - - - name: Upload CLAP artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-clap - path: staging/clap/ - - - name: Upload VST3 artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-vst3 - path: staging/vst3/ diff --git a/.gitea/workflows/build-plugins-rpi.yml b/.gitea/workflows/build-plugins-rpi.yml deleted file mode 100644 index a43c0d1..0000000 --- a/.gitea/workflows/build-plugins-rpi.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Build Plugins RPi - -on: - workflow_call: - workflow_dispatch: - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: aarch64-unknown-linux-gnu - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: aarch64-unknown-linux-gnu-plugins - - - name: Install cross - run: cargo install cross --git https://github.com/cross-rs/cross - - - name: Build plugins - run: cross build --release -p cagire-plugins --target aarch64-unknown-linux-gnu - - - name: Prepare plugin artifacts - run: | - mkdir -p target/bundled - cp target/aarch64-unknown-linux-gnu/release/libcagire_plugins.so target/bundled/cagire-plugins.clap - mkdir -p "target/bundled/cagire-plugins.vst3/Contents/aarch64-linux" - cp target/aarch64-unknown-linux-gnu/release/libcagire_plugins.so "target/bundled/cagire-plugins.vst3/Contents/aarch64-linux/cagire-plugins.so" - - mkdir -p staging/clap staging/vst3 - cp -R target/bundled/cagire-plugins.clap staging/clap/ - cp -R target/bundled/cagire-plugins.vst3 staging/vst3/ - - - name: Upload CLAP artifact - uses: actions/upload-artifact@v4 - with: - name: plugins-linux-aarch64-clap - path: staging/clap/ - - - name: Upload VST3 artifact - uses: actions/upload-artifact@v4 - with: - name: plugins-linux-aarch64-vst3 - path: staging/vst3/ diff --git a/.gitea/workflows/build-plugins-windows.yml b/.gitea/workflows/build-plugins-windows.yml deleted file mode 100644 index 71d3891..0000000 --- a/.gitea/workflows/build-plugins-windows.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Build Plugins Windows - -on: - workflow_call: - workflow_dispatch: - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: windows-latest - timeout-minutes: 60 - - defaults: - run: - shell: bash - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: x86_64-pc-windows-msvc - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: x86_64-pc-windows-msvc-plugins - - - name: Install dependencies - shell: pwsh - run: | - choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' - echo "C:\Program Files\CMake\bin" >> $env:GITHUB_PATH - - - name: Build plugins - run: cargo xtask bundle cagire-plugins --release --target x86_64-pc-windows-msvc - - - name: Prepare plugin artifacts - run: | - mkdir -p staging/clap staging/vst3 - cp -R target/bundled/cagire-plugins.clap staging/clap/ - cp -R target/bundled/cagire-plugins.vst3 staging/vst3/ - - - name: Upload CLAP artifact - uses: actions/upload-artifact@v4 - with: - name: plugins-windows-x86_64-clap - path: staging/clap/ - - - name: Upload VST3 artifact - uses: actions/upload-artifact@v4 - with: - name: plugins-windows-x86_64-vst3 - path: staging/vst3/ diff --git a/.gitea/workflows/build-plugins.yml b/.gitea/workflows/build-plugins.yml deleted file mode 100644 index 878213d..0000000 --- a/.gitea/workflows/build-plugins.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Build Plugins - -on: - workflow_dispatch: - -jobs: - linux: - uses: ./.gitea/workflows/build-plugins-linux.yml - - macos: - uses: ./.gitea/workflows/build-plugins-macos.yml - - windows: - uses: ./.gitea/workflows/build-plugins-windows.yml - - rpi: - uses: ./.gitea/workflows/build-plugins-rpi.yml diff --git a/.gitea/workflows/build-windows.yml b/.gitea/workflows/build-windows.yml deleted file mode 100644 index 6c89ba5..0000000 --- a/.gitea/workflows/build-windows.yml +++ /dev/null @@ -1,134 +0,0 @@ -name: Build Windows - -on: - workflow_call: - inputs: - run-tests: - type: boolean - default: false - run-clippy: - type: boolean - default: false - build-packages: - type: boolean - default: false - workflow_dispatch: - inputs: - run-tests: - type: boolean - default: true - run-clippy: - type: boolean - default: true - build-packages: - type: boolean - default: true - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: windows-latest - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v4.2.2 - with: - submodules: recursive - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: x86_64-pc-windows-msvc - components: clippy - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - with: - key: x86_64-pc-windows-msvc - - - name: Install dependencies - run: | - choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' - echo "C:\Program Files\CMake\bin" >> $env:GITHUB_PATH - - - name: Build - run: cargo build --release --features asio --target x86_64-pc-windows-msvc - - - name: Build desktop - run: cargo build --release --features desktop,asio --bin cagire-desktop --target x86_64-pc-windows-msvc - - - name: Test - if: inputs.run-tests - run: cargo test --features asio --target x86_64-pc-windows-msvc - - - name: Clippy - if: inputs.run-clippy - run: cargo clippy --features asio --target x86_64-pc-windows-msvc -- -D warnings - - - name: Bundle CLAP plugin - if: inputs.build-packages - run: cargo xtask bundle cagire-plugins --release --features asio --target x86_64-pc-windows-msvc - - - name: Install NSIS - if: inputs.build-packages - run: choco install nsis - - - name: Build NSIS installer - if: inputs.build-packages - shell: pwsh - run: | - $version = (Select-String -Path Cargo.toml -Pattern '^version\s*=\s*"(.+)"' | Select-Object -First 1).Matches.Groups[1].Value - $root = (Get-Location).Path - $target = "x86_64-pc-windows-msvc" - & "C:\Program Files (x86)\NSIS\makensis.exe" ` - "-DVERSION=$version" ` - "-DCLI_EXE=$root\target\$target\release\cagire.exe" ` - "-DDESKTOP_EXE=$root\target\$target\release\cagire-desktop.exe" ` - "-DICON=$root\assets\Cagire.ico" ` - "-DOUTDIR=$root\target" ` - nsis/cagire.nsi - - - name: Upload CLI artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-windows-x86_64 - path: target/x86_64-pc-windows-msvc/release/cagire.exe - - - name: Upload desktop artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-windows-x86_64-desktop - path: target/x86_64-pc-windows-msvc/release/cagire-desktop.exe - - - name: Upload installer artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-windows-x86_64-installer - path: target/cagire-*-setup.exe - - - name: Prepare plugin artifacts - if: inputs.build-packages - shell: bash - run: | - mkdir -p staging/clap staging/vst3 - cp -R target/bundled/cagire-plugins.clap staging/clap/ - cp -R target/bundled/cagire-plugins.vst3 staging/vst3/ - - - name: Upload CLAP artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-windows-x86_64-clap - path: staging/clap/ - - - name: Upload VST3 artifact - if: inputs.build-packages - uses: actions/upload-artifact@v4 - with: - name: cagire-windows-x86_64-vst3 - path: staging/vst3/ diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml deleted file mode 100644 index f7d7ae7..0000000 --- a/.gitea/workflows/ci.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: CI - -on: - workflow_dispatch: - -jobs: - linux: - uses: ./.gitea/workflows/build-linux.yml - with: - run-tests: true - run-clippy: true - - macos: - uses: ./.gitea/workflows/build-macos.yml - with: - run-tests: true - run-clippy: true - - windows: - uses: ./.gitea/workflows/build-windows.yml - with: - run-tests: true - run-clippy: true diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml deleted file mode 100644 index fa17a8b..0000000 --- a/.gitea/workflows/release.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: Release - -on: - workflow_dispatch: - -jobs: - linux: - uses: ./.gitea/workflows/build-linux.yml - with: - build-packages: true - - macos: - uses: ./.gitea/workflows/build-macos.yml - with: - build-packages: true - matrix: >- - [ - {"os":"macos-14","target":"aarch64-apple-darwin","artifact":"cagire-macos-aarch64"}, - {"os":"macos-15-intel","target":"x86_64-apple-darwin","artifact":"cagire-macos-x86_64"} - ] - - windows: - uses: ./.gitea/workflows/build-windows.yml - with: - build-packages: true - - cross: - uses: ./.gitea/workflows/build-cross.yml - - assemble-macos: - needs: macos - uses: ./.gitea/workflows/assemble-macos.yml - - release: - needs: [linux, macos, windows, cross, assemble-macos] - runs-on: ubuntu-latest - timeout-minutes: 10 - - steps: - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: Prepare release files - run: | - mkdir -p release - for dir in artifacts/*/; do - name=$(basename "$dir") - if [[ "$name" == "cagire-macos-universal-dmg" ]]; then - cp "$dir"/*.dmg release/ - elif [[ "$name" == "cagire-macos-universal-pkg" ]]; then - cp "$dir"/*.pkg release/ - elif [[ "$name" == "cagire-macos-universal-desktop" ]]; then - cp "$dir/Cagire.app.zip" "release/cagire-macos-universal-desktop.app.zip" - elif [[ "$name" == "cagire-macos-universal" ]]; then - cp "$dir/cagire" "release/cagire-macos-universal" - elif [[ "$name" == "cagire-macos-universal-clap" ]]; then - cd "$dir" && zip -r "../../release/cagire-macos-universal-clap.zip" cagire-plugins.clap && cd ../.. - elif [[ "$name" == "cagire-macos-universal-vst3" ]]; then - cd "$dir" && zip -r "../../release/cagire-macos-universal-vst3.zip" cagire-plugins.vst3 && cd ../.. - elif [[ "$name" == *-clap ]]; then - base="${name%-clap}" - cd "$dir" && zip -r "../../release/${base}-clap.zip" cagire-plugins.clap && cd ../.. - elif [[ "$name" == *-vst3 ]]; then - base="${name%-vst3}" - cd "$dir" && zip -r "../../release/${base}-vst3.zip" cagire-plugins.vst3 && cd ../.. - elif [[ "$name" == *-installer ]]; then - cp "$dir"/*-setup.exe release/ - elif [[ "$name" == *-appimage ]]; then - cp "$dir"/*.AppImage release/ - elif [[ "$name" == *-desktop ]]; then - base="${name%-desktop}" - if ls "$dir"/*.deb 1>/dev/null 2>&1; then - cp "$dir"/*.deb "release/${base}-desktop.deb" - elif [ -f "$dir/Cagire.app.zip" ]; then - cp "$dir/Cagire.app.zip" "release/${base}-desktop.app.zip" - elif [ -f "$dir/cagire-desktop.exe" ]; then - cp "$dir/cagire-desktop.exe" "release/${base}-desktop.exe" - fi - else - if [ -f "$dir/cagire.exe" ]; then - cp "$dir/cagire.exe" "release/${name}.exe" - elif [ -f "$dir/cagire" ]; then - cp "$dir/cagire" "release/${name}" - fi - fi - done - - - name: Create Gitea release - env: - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - run: | - TAG="${GITEA_REF_NAME:-manual-$(date +%Y%m%d-%H%M%S)}" - API_URL="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases" - - RELEASE_ID=$(curl -s -X POST "$API_URL" \ - -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"tag_name\": \"$TAG\", \"name\": \"$TAG\", \"draft\": true}" \ - | jq -r '.id') - - for file in release/*; do - filename=$(basename "$file") - curl -s -X POST "$API_URL/$RELEASE_ID/assets?name=$filename" \ - -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/octet-stream" \ - --data-binary "@$file" - done - - echo "Release $TAG created as draft with $(ls release | wc -l) assets" diff --git a/BUILDING.md b/BUILDING.md index 930d0d1..5d79cda 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -110,57 +110,49 @@ cargo run --release --features desktop --bin cagire-desktop ## Cross-Compilation -[cross](https://github.com/cross-rs/cross) uses Docker to build for other platforms without installing their toolchains locally. It works on any OS that runs Docker. - ### Targets | Target | Method | Binaries | |--------|--------|----------| | aarch64-apple-darwin | Native (macOS ARM only) | `cagire`, `cagire-desktop` | | x86_64-apple-darwin | Native (macOS only) | `cagire`, `cagire-desktop` | -| x86_64-unknown-linux-gnu | `cross build` | `cagire`, `cagire-desktop` | -| aarch64-unknown-linux-gnu (RPi 64-bit) | `cross build` | `cagire`, `cagire-desktop` | -| x86_64-pc-windows-gnu | `cross build` | `cagire`, `cagire-desktop` | +| x86_64-unknown-linux-gnu | `cross build` (Docker) | `cagire`, `cagire-desktop` | +| aarch64-unknown-linux-gnu (RPi 64-bit) | `cross build` (Docker) | `cagire`, `cagire-desktop` | +| x86_64-pc-windows-msvc | `cargo xwin build` (native) | `cagire`, `cagire-desktop` | -macOS targets can only be built on macOS — Apple does not support cross-compilation to macOS from other platforms. Linux and Windows targets can be cross-compiled from any OS. The aarch64-unknown-linux-gnu target covers Raspberry Pi (64-bit OS). - -### Windows ABI - -CI produces `x86_64-pc-windows-msvc` binaries (native Windows build, better compatibility). Local cross-compilation from non-Windows hosts produces `x86_64-pc-windows-gnu` binaries (MinGW via Docker). Both work; MSVC is preferred for releases. +macOS targets can only be built on macOS. Linux targets are cross-compiled via Docker (`cross`). Windows targets are cross-compiled natively via `cargo-xwin` (downloads Windows SDK + MSVC CRT headers, no Docker needed). ### Prerequisites -1. **Docker**: https://docs.docker.com/get-docker/ -2. **cross**: `cargo install cross --git https://github.com/cross-rs/cross` +1. **Docker** + **cross** (Linux targets only): `cargo install cross --git https://github.com/cross-rs/cross` +2. **cargo-xwin** (Windows target): `cargo install cargo-xwin` and `rustup target add x86_64-pc-windows-msvc` 3. On macOS, add the Intel target: `rustup target add x86_64-apple-darwin` -Docker must be running before invoking `cross` or `scripts/build-all.sh`. - ### Building Individual Targets ```bash -# Linux x86_64 +# Linux x86_64 (Docker) cross build --release --target x86_64-unknown-linux-gnu cross build --release --features desktop --bin cagire-desktop --target x86_64-unknown-linux-gnu -# Linux aarch64 +# Linux aarch64 (Docker) cross build --release --target aarch64-unknown-linux-gnu cross build --release --features desktop --bin cagire-desktop --target aarch64-unknown-linux-gnu -# Windows x86_64 -cross build --release --target x86_64-pc-windows-gnu -cross build --release --features desktop --bin cagire-desktop --target x86_64-pc-windows-gnu +# Windows x86_64 (native, no Docker) +cargo xwin build --release --target x86_64-pc-windows-msvc +cargo xwin build --release --features desktop --bin cagire-desktop --target x86_64-pc-windows-msvc ``` -### Building All Targets (macOS only) +### Building All Targets ```bash # Interactive (prompts for platform/target selection): -scripts/build-all.sh +uv run scripts/build.py # Non-interactive: -scripts/build-all.sh --platforms macos-arm64,linux-x86_64 --targets cli,desktop --yes -scripts/build-all.sh --all --yes +uv run scripts/build.py --platforms macos-arm64,linux-x86_64 --targets cli,desktop +uv run scripts/build.py --all ``` Builds selected targets, producing binaries in `releases/`. @@ -170,18 +162,11 @@ Target aliases: `cli`, `desktop`, `plugins`. ### Linux AppImage Packaging -Linux releases ship as AppImages — self-contained executables that bundle all shared library dependencies (ALSA, JACK, X11, OpenGL). No runtime dependencies required. - -After building a Linux target, produce an AppImage with: - -```bash -scripts/make-appimage.sh target/x86_64-unknown-linux-gnu/release/cagire x86_64 releases -``` - -`scripts/build-all.sh` does this automatically for every Linux target selected. The CI pipeline produces AppImages for the x86_64 Linux build. Cross-arch AppImage building (e.g. aarch64 on x86_64) is not supported — run on a matching host or in CI. +Linux releases ship as AppImages — self-contained executables that bundle all shared library dependencies (ALSA, JACK, X11, OpenGL). No runtime dependencies required. `build.py` handles AppImage creation automatically for Linux targets. ### Notes -- Custom Dockerfiles in `cross/` install the native libraries Cagire depends on (ALSA, JACK, X11, cmake, libclang, etc.). `Cross.toml` maps each target to its Dockerfile. -- The first build per target downloads Docker base images and installs packages. Subsequent builds use cached layers. -- Cross-architecture Docker builds (e.g. aarch64 on x86_64 or vice versa) run under QEMU emulation and are significantly slower. +- Custom Dockerfiles in `scripts/cross/` install the native libraries for Linux cross-compilation (ALSA, JACK, X11, cmake, libclang, etc.). `Cross.toml` maps each Linux target to its Dockerfile. +- The first Linux cross-build per target downloads Docker base images and installs packages. Subsequent builds use cached layers. +- Cross-architecture Docker builds (e.g. aarch64 on x86_64) run under QEMU emulation and are significantly slower. +- Windows cross-compilation via `cargo-xwin` runs natively on the host (no Docker) and uses real Windows SDK headers, ensuring correct ABI and struct layouts. diff --git a/CHANGELOG.md b/CHANGELOG.md index b9216b4..9e971d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [0.1.5] + +### Added + +- Support i32/i16 sample formats at cpal boundary for ASIO compatibility + ## [0.1.4] ### Breaking diff --git a/Cargo.lock b/Cargo.lock index 19c3b12..9ff16f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -894,7 +894,7 @@ dependencies = [ "tachyonfx", "thread-priority", "tui-big-text", - "winres", + "winresource", ] [[package]] @@ -1825,6 +1825,7 @@ dependencies = [ [[package]] name = "doux" version = "0.0.18" +source = "git+https://github.com/sova-org/doux?tag=v0.0.18#4a5a065ba525657cf7ff1362f0b7e2f4f4f2b46c" dependencies = [ "arc-swap", "clap", @@ -5595,15 +5596,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.7.8" @@ -5631,6 +5623,21 @@ dependencies = [ "winnow 0.7.15", ] +[[package]] +name = "toml" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399b1124a3c9e16766831c6bba21e50192572cdd98706ea114f9502509686ffc" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 1.0.0+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -7085,12 +7092,13 @@ dependencies = [ ] [[package]] -name = "winres" -version = "0.1.12" +name = "winresource" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +checksum = "0986a8b1d586b7d3e4fe3d9ea39fb451ae22869dcea4aa109d287a374d866087" dependencies = [ - "toml 0.5.11", + "toml 1.0.6+spec-1.1.0", + "version_check", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 75f51a9..5df3d97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ cagire-forth = { path = "crates/forth" } cagire-markdown = { path = "crates/markdown" } cagire-project = { path = "crates/project" } cagire-ratatui = { path = "crates/ratatui" } -doux = { git = "https://github.com/sova-org/doux", tag = "v0.0.18", features = ["native", "soundfont"] } +doux = { git = "https://github.com/sova-org/doux", tag = "v0.0.19", features = ["native", "soundfont"] } rusty_link = "0.4" ratatui = "0.30" crossterm = "0.29" @@ -87,7 +87,7 @@ image = { version = "0.25", default-features = false, features = ["png"], option cpal = { version = "0.17", optional = true, features = ["jack"] } [build-dependencies] -winres = "0.1" +winresource = "0.1" [profile.release] opt-level = 3 @@ -105,9 +105,6 @@ egui-baseview = { path = "plugins/egui-baseview" } [patch."https://github.com/RustAudio/baseview.git"] baseview = { path = "plugins/baseview" } -[patch.'https://github.com/sova-org/doux'] -doux = { path = "/Users/bubo/doux" } - [package.metadata.bundle.bin.cagire-desktop] name = "Cagire" identifier = "com.sova.cagire" diff --git a/Cross.toml b/Cross.toml index d169034..3fef6bb 100644 --- a/Cross.toml +++ b/Cross.toml @@ -3,6 +3,3 @@ dockerfile = "./scripts/cross/aarch64-linux.Dockerfile" [target.x86_64-unknown-linux-gnu] dockerfile = "./scripts/cross/x86_64-linux.Dockerfile" - -[target.x86_64-pc-windows-gnu] -dockerfile = "./scripts/cross/x86_64-windows.Dockerfile" diff --git a/README.md b/README.md index e4b4097..49c1913 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ A generative pattern using randomness, scales, and effects: ```forth sine sound 2 fm 0.5 fmh 0 7 rand minor 50 + note -.1 .8 rrand cutoff -1 4 irand 10 * delay .5 delayfb +.1 .8 rand lpf +1 4 rand 10 * delay .5 delayfeedback . ``` @@ -66,7 +66,7 @@ To build from source instead, see [BUILDING.md](BUILDING.md). ### Documentation -Cagire includes interactive documentation with runnable code examples. Press **F1** in the application to open it. +Cagire includes interactive documentation with runnable code examples. Press **F4** in the application to open it. - [Website](https://cagire.raphaelforment.fr) - [BUILDING.md](BUILDING.md) — build instructions and CLI flags diff --git a/build.rs b/build.rs index 5f3b008..5cb3232 100644 --- a/build.rs +++ b/build.rs @@ -4,8 +4,6 @@ fn main() { let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); if target_os == "windows" { - // C++ runtime (stdc++, gcc, gcc_eh, pthread) linked statically via .cargo/config.toml - // using -Wl,-Bstatic. Only Windows system DLLs go here. println!("cargo:rustc-link-lib=ws2_32"); println!("cargo:rustc-link-lib=iphlpapi"); println!("cargo:rustc-link-lib=winmm"); @@ -16,23 +14,12 @@ fn main() { if target_os == "windows" { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let icon = format!("{manifest_dir}/assets/Cagire.ico"); - let mut res = winres::WindowsResource::new(); - // Cross-compiling from Unix: use prefixed MinGW tools - if cfg!(unix) { - res.set_windres_path("x86_64-w64-mingw32-windres"); - res.set_ar_path("x86_64-w64-mingw32-ar"); - res.set_toolkit_path("/"); - } - res.set_icon(&icon) + winresource::WindowsResource::new() + .set_icon(&icon) .set("ProductName", "Cagire") .set("FileDescription", "Forth-based music sequencer") - .set("LegalCopyright", "Copyright (c) 2025 Raphaël Forment"); - res.compile().expect("Failed to compile Windows resources"); - // GNU ld discards unreferenced sections from static archives, - // so link the resource object directly to ensure .rsrc is kept. - if cfg!(unix) { - let out_dir = std::env::var("OUT_DIR").unwrap(); - println!("cargo:rustc-link-arg-bins={out_dir}/resource.o"); - } + .set("LegalCopyright", "Copyright (c) 2025 Raphaël Forment") + .compile() + .expect("Failed to compile Windows resources"); } } diff --git a/nsis/cagire.nsi b/nsis/cagire.nsi deleted file mode 100644 index daa8822..0000000 --- a/nsis/cagire.nsi +++ /dev/null @@ -1,114 +0,0 @@ -; Cagire NSIS Installer Script -; Receives defines from command line: -; -DVERSION=x.y.z -; -DCLI_EXE=/path/to/cagire.exe -; -DDESKTOP_EXE=/path/to/cagire-desktop.exe -; -DICON=/path/to/Cagire.ico -; -DOUTDIR=/path/to/releases - -!include "MUI2.nsh" -!include "WordFunc.nsh" - -Name "Cagire ${VERSION}" -OutFile "${OUTDIR}\cagire-${VERSION}-windows-x86_64-setup.exe" -InstallDir "$PROGRAMFILES64\Cagire" -InstallDirRegKey HKLM "Software\Cagire" "InstallDir" -RequestExecutionLevel admin -Unicode True - -!define MUI_ICON "${ICON}" -!define MUI_UNICON "${ICON}" -!define MUI_ABORTWARNING - -!define MUI_HEADERIMAGE -!define MUI_HEADERIMAGE_BITMAP "header.bmp" -!define MUI_WELCOMEFINISHPAGE_BITMAP "sidebar.bmp" -!define MUI_UNWELCOMEFINISHPAGE_BITMAP "sidebar.bmp" - -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH - -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -!insertmacro MUI_LANGUAGE "English" - -Section "Cagire (required)" SecCore - SectionIn RO - SetOutPath "$INSTDIR" - !ifdef CLI_EXE - File "/oname=cagire.exe" "${CLI_EXE}" - !endif - !ifdef DESKTOP_EXE - File "/oname=cagire-desktop.exe" "${DESKTOP_EXE}" - !endif - - WriteUninstaller "$INSTDIR\uninstall.exe" - WriteRegStr HKLM "Software\Cagire" "InstallDir" "$INSTDIR" - - ; Add/Remove Programs entry - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "DisplayName" "Cagire" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "DisplayVersion" "${VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "Publisher" "Raphael Forment" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "UninstallString" '"$INSTDIR\uninstall.exe"' - !ifdef DESKTOP_EXE - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "DisplayIcon" '"$INSTDIR\cagire-desktop.exe"' - !else - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "DisplayIcon" '"$INSTDIR\cagire.exe"' - !endif - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "URLInfoAbout" "https://git.raphaelforment.fr/BuboBubo/cagire" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "HelpLink" "https://cagire.raphaelforment.fr" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" "NoRepair" 1 -SectionEnd - -Section "Add to PATH" SecPath - ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" - StrCpy $0 "$0;$INSTDIR" - WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$0" - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 -SectionEnd - -!ifdef DESKTOP_EXE -Section "Start Menu Shortcut" SecStartMenu - CreateDirectory "$SMPROGRAMS\Cagire" - CreateShortCut "$SMPROGRAMS\Cagire\Cagire.lnk" "$INSTDIR\cagire-desktop.exe" "" "$INSTDIR\cagire-desktop.exe" 0 - CreateShortCut "$SMPROGRAMS\Cagire\Uninstall.lnk" "$INSTDIR\uninstall.exe" -SectionEnd -!endif - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${SecCore} "Installs Cagire CLI and Desktop binaries." - !insertmacro MUI_DESCRIPTION_TEXT ${SecPath} "Add the install location to the PATH system environment variable." - !ifdef DESKTOP_EXE - !insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} "Add a Cagire shortcut to the Start Menu." - !endif -!insertmacro MUI_FUNCTION_DESCRIPTION_END - -Section "Uninstall" - !ifdef CLI_EXE - Delete "$INSTDIR\cagire.exe" - !endif - !ifdef DESKTOP_EXE - Delete "$INSTDIR\cagire-desktop.exe" - !endif - Delete "$INSTDIR\uninstall.exe" - RMDir "$INSTDIR" - - Delete "$SMPROGRAMS\Cagire\Cagire.lnk" - Delete "$SMPROGRAMS\Cagire\Uninstall.lnk" - RMDir "$SMPROGRAMS\Cagire" - - ; Remove from PATH - ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" - ; Remove ";$INSTDIR" from the path string - ${WordReplace} $0 ";$INSTDIR" "" "+" $0 - WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "Path" "$0" - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cagire" - DeleteRegKey HKLM "Software\Cagire" -SectionEnd diff --git a/nsis/header.bmp b/nsis/header.bmp deleted file mode 100644 index 62985a8ab487a195815bb8ff00ba29e4fa65869c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25818 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 diff --git a/nsis/sidebar.bmp b/nsis/sidebar.bmp deleted file mode 100644 index 0e3b735877a41d8212340ed77f060dff525707a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154542 zcmeI52Yg(`z3=nhyGbavG458ex~wkSvaBvyT~@PtFSaaMR<&fy#s&9=1@67~BFWMg z?aB>8=#Wb&flG3^1VSJo1PFv;3?%ox@0^jAMK<7o0*~C`Gv3eaoH=vm{C@v7|Ctpr zXhapb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a z0fm4hapb$_9Cy) z5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4ha zpb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4< zKp~(IPzWdl6aoqXg@8ifUkrg;ZW(g>?W4zxaU3#a*q|Z9hmNqfaqzNt^d39b$x`gb zd5&}Tv$1g*HOhYY@Ug>(+YBB&?8iU;XkDVCo>*nL-;zjXx z@pf|@Z)fW=ZE{%BUK6S3hDE0bMMO^s@^$qI^qfG&!QOSelV{AtAm?%Jp3a^* zVbQ5m!nq|cJSNJ2$^>`6tk9{`gCpYuLa5LvOJ+z^{G^b$Nx_Vn7akoSmNX?YEx0Hl zX!^7%q3OP1S#A^K$GP~A4@mNulH%Yx(Lbp?sBocoM4ne@mRCro`=kW7iE*y}F}C*O z$2t3Z24^^V2J@!e;vSGVJ}||`*3Hhz&(SB+bwZr8cQ}2x>Nq~oZ9=T0d*B#bx1apv zrs1RP?HqlEjo(5GS3_ys$Wi0m1CqQ#v&Dl#v&T=K=HN16_((g@zV+52x7{{k z#0XnENAFQ%o%l)_I&`E&d-P}r;I(z0U_U)4|=zBRh0zh|eT?rUyqx_)eys$Jy98$%?157dHlY_{*Nu87ekFZaHaqX6@@qx*X_DD%KcU9eFB%oraCU?vUL3OelranXTz#k7 zICu}eZ3K2~;Z>51`u9`+&*@s-T0BV?lw+-P98yAvUT(wdi&@RV_nBM z_((kMT_@3Jw2h0cy}Pgv9znKllgCd<8$UUjufs>$V_GEagJUSBeEw% z`3PfO10>hHR zll($6yn@r=sE_VUG+JsdY(g22v$1otwR7i<&{oN{&{J*+%XamR8f)Wx^UZ?>55C>T z*2R5dyrdf;88zDBmRpDZ^rl;X`qP_lx_R(z*kM~&1{YS**7fFF1`irE6sySiXe)hS z4Lq?MLf^x(8AsZXA;WBL#VU>-hmPAj`2x6u>m($Qub6boKyfWpX^f+-t#e{nMAp<8 zj4GZqCO8gcJcHADceESX!}|aQJ!O9fw@JvPaO;{2!2Wx<`PI*AET3MO872%YUUgbv znA14q!P&*ZJvlJEAR-pNCb;{0IC=0@JSaF4Yo8e+{BK5Z6kkzQ{JVIHCe%9s043MlODTwqD~_2qC$F@rqOLf0T2@F@dQhY={#f;}I4^hq zaV`@CzhT*ECDV5Gi-Jvif)HDz%LV^SJ3d{?fF|ctxC#Pv1B5X)E^xs^0RdlT=in)C zaSKSYbM_x&>x#u5JzoqwH@Pbo=lTworV_ErV~m=@!}tifc?|khid+ppB8Fk{%q95gtD^EZJwm zRLn94oS6dx_SwfP5c7!Dois5DKwSLj5aQ$&;u#eZk~VdAUP)R+T$s-!h{ojNWF!0n z=`0H&7F?&tB&Wru6087MhB)LX5uvwWp}c7qk=pTdSS-LJ9#*bb7Oj0 zDG6yMDY7e$0pqKtEy$W;$v4d5k17;WzL2*v_PRUI?V%g%iYJqiC95KlK2 zPd#jmgL@$H9#ood{FjDxq6?^LaWCsN0(1`QeUZ~yia=qBzZ=Ar+{ zk#@+*Py1Zn`JNL%PQ3z^Xl*!(e$ejZcOun$^bhW-wb z-RQ5)Q&`%OBkgaxX%LYxmj;S!7l-j-zLNn5uE7><0wsv1Kw0dh5CTm;qhtV z@i=06DJwiSJv`o0GUF3+664WUu$5dBGBGl2Mox)rsjSb9PQpHOZ%J%&X&mK&Vv^{9 zjM2y|P-p2UF%0#Y6dw@k9ne&VJE@hmLmkrJb+B)WabB^3^ja zP1sw{5F~_KT)e{(NNh5}xiIGbF{lGvJGxKi7NWb}u-3*|a!r&)1&=R6(aF4uC@G;e?sBUC6h>yH932$dTwYxkpK7@=uQyJMg$M*= z(s+Ml45?sMPUOZq3)_MnfPDxeJmB3aqsKTBy<5+LIw1i(A}Ry}j9-$HH8ZcQU}~a# z79BDW*NMT%gB)jy=Y%N#K*om`EUnvwIB0@F_eqHk9>KSda_|Vt@Qp2ILG4a^pGk*z zA~!T0-f85n&%@L)j&?2+#(4yz)C5#q;$8xBXtHziVF7;Yt+#2h^k`Jue*6@K2k%c$ zd^f=!m#{Xs-8NiXW#7gpjac#_LxvOAq4gMl8V8DN2%=y!-5ou!z@IbH$1G}2hils{ zEocxlp?A}RqcFMj=aV8w<|@U~*}8(>LFi-;f5J1207Aty;00x85LQo8870@$S!yw+ z9N99CY@rcmgS;mZ4N4nMhy2LcsEI+g_ysMtXB_Nk4(Mj6#DEawgc;^W#-`0m3(HR>cEa;Y z(9r9t6GTiRzw&8g?{4qxPmn1rc38GwT&YiVA+gg4TlXQu#^RA}g*pqx*OuO-M6&!7 z(}QOwct<9aSF!D+!mz!v zg|Hb9%WR=${U(Zv^?mxQGQD8S}mnJtS*Fa#mzrwr@;| z;42`BL&`WDL88ep&M+XgBGGK z71r!T>=+^+S08#>o>-S(wzzg)NnA2qXNOJoaP^wt>7N}Y7W+kU$#=|Yu1L#~otdFk zVHqAn6l!PZh7r)XCby8`5u8q}PDQqS{u!3#6`nyZ1=h%}U~Gx!;gN;2W}@8*#t5Ee zs*|W2|4V3xFMwHTnfc^KQMB|daX5CKw;MG0cJk^xlzc2AJ>YRTut@#2C@C$nOq(2v zA~cp%CP&75yLh1v(G!Ga<|>&AR306XJ&_hdGR!0GvIC!xMbw1)TLz>B8$yUh42DXQ zM+JFUW+*CH59p(Vwvi#^fhomJ3SoZ);kN{7l5xILkS=CL!8kKQX?$u$YIZ?XJWoV! z5k&%TZl^=A&*YgYSF4j0rut9W`fU95)_Zgx?|*Pjhe$aPgh`Im_DmOMKNr zEN8C}SR-b0pClxNJrwj8ImD9VaC-|xYg$YPEVf*m_X({d0wcCjyu%&6QREoB#;t>H zCvqTpg)t`=H)zmph{{0Oa9{ya=mskbDV7RLq=i)tiIEBDAYl(KRZ`jS7U)A6(G+== z+Ytj6SqzKjT1JCw94qdd+v$mYke8@XSb|~v5diMuUit`02#&*2oP-RDiM^!*@w|&)9LGYc#M${87DCj%4TQ1Sfx~GL}D$qnEPk6vxu!)s`bj&+LiSa|C@XK%n zL1-nDfjA-o>G2s;&Q^+z<&$}WEfxcJK=O^PG)AzXO&v>uaiE150B^;Bm)XgtG zdunsWlwx+udXs6I5+ zGZ7q43Ync%loOk*T@p!GuA+v}jUX`}GN??0+hyS@Uzr;*A)T2gIU+>J+tr)pJQcX$ z6LTcU)pVTExC?oZ!hjCCP6+c$2@8skjR;F6H;6BWL`x=3=<<{l3_cMWja0lNvjZ|} zS!ZE{SvA8ECV~{`2)3k0+L1r8bMS^xyf&SQv~RifHger8r3u0@)V<o(TO53^4n z!gAs?+6Rzp2<1&dL)grqNIV*0Ef@j|!IhRt6Ooe0NcZtB356*_Xzs=EN;#oj_C!ad z^|naJwOr?hiCj&D{}c~bA2galT*kQ*x?_784O+3i7#u#m$NSgKsHx5^Wi+lLgrv<; zQZE;8tO1Qol4+o%AcLNARhv}^<1=mgFf4H?K#r1X3rrPhg|b+s9zvNbBWN7hz^w$dabz?ISrgI#-ET3in0G(m84_9xr=e=MmvP!2*8j@ zqV;s<67LAV1fP6G;JH`!VL(AW#JLBGgsPS`^$O4R$XG$4($AX{(Lt*$u6|P?T?E@U z&Ws?VZYpe+K{{t$P+q1%s$68tvG#*S)&)P#8eF?kv-tzZH69J!gb@nN0vBY!N znyfG27kkAUVaM<$TF)46$G$Nd7JyG;KOfIP&Ni_90guGYzPZc&@|IIU0VUm3FyPv* zsJ0kq@7q6yr;9xoO~+YQTa`cpF!C_B4;yXgaIR0|W6aX56~Yve;2oSF3FnijamzsnHF)f$5USnQhA9eExOm?3@j&yur zesf?!Gc7oAVada?+18{TCoXhfs6UzWSURB8a(yjDqIb(IDBa${3uZaKMG9SW0hyeL z(`3U5lP-6@B=rNuHNKCR`dVs8S)&L*2Oubg+?rq%#Qsz>)i=YA%jWxz-BPVDOyVnQ<6(I}`<5__4iKZg}^p|D?-IpV93Ez!_ zOA3i~=QKi4I!oZ&M>{%rh4n>foN7qN6yuAp|IMkB>ck+p3FQ{)5%@Mjeem2f^;y`h&n_IXpKb?^HYe}&f@Ehs;wWEET4u~8+ z6hcYAP~j^+9cE#TV2rgJgQL7?t61HKVYffuYr{$)0HUXzD|Iv-X8B5y#=oyFzDm;N zR51mTYo2Rs>xyc_Aeqlz9%XQ@eUe=fgAmD+3$<~eY95@SYLNameL9^j-jsA+x zW7!cKDt5%QxKW-<8SCVac^@dQ7p5myCw#qL^S-DRN<@+zJwkne5zA@u*EFK|fNxR5 zuVgcNR$5L&Q3Z(_Ir5ivW;E+dSQU&dL6-=agT>iYDrIRo^(B=h*~O_*iR3(CSy+Iu zXeJ{avGoXCF&FrBs3aYVz3mOl z1;xTUW4bAmMhTEXmbY?q@I)f9c5eAGH zX*X* z>g=KgmGwo@N%W+@C1kRGF3d74=f`-2bQ!exx_YzaZIJ=m>kDRZh?G*DRmedI;wXY` z#-Wewh8$*uhJBmO(=YO0TW4{n|Q8fhvImn1dDmZj#@Wh1E^$IM4#ZT6+|(4bNy%`Rfh~ z>_t-(Wy%`e0ay!tvOiy;K*YfD>37U-v@FVq5@E`E%)+PyWQGm}k@3udT?`nsjK*x) zYn$LRc|rADjENK~mLBA7cm=7~Jcu*V(y+ z`b|je}(q3`B+GiC9^Wbs9dxhGZ$EW6wn{ z#eE9#9(1!>=hV~p!nHNRC;|pEJ}|s0vp{Ym0xt!5z_kGmoh4tyIe=pU-!cg3VUP)N zH9y#&Yr4?^OOhR(G&3zH$UA_?S?-mC<3!MLdHx?U;}P5f9V` z-Q)<`7FYnjfC=yjW=I$h=BO2nW4#du>^4T5du2q*8}Te;n7uP9^x<~YJlr=RJ!C59 z!a0o~mQG>WC^$D_$%)e#6ZNEp0}osklHePOzee}5(ntlLcH=xoX)9}yML|ehCW#!W z_M;4rGw~yW0puEWKq0x1lI(e`oiW++Snyz`X~SQ12tLl?|}005CAyGSrVk-i?u;W&+p zN05J5CdJ(^iclQu&2Bg;G7gs#b@NqfJ;Feu8&l5;i!+VLfH&;K4UuK9W6jA_$r^U8{~qqf#)e03cnu+=QIsn8S2$M;>Uzg)7YnDu}& zk~3;@iV5nj?Ev)*l^35{oms$vBGd=VX|WiyGYcxybGa)mdRq3h%-XzCA*GtCLNP04 zN@QR}ZEmSNJj_Yvs_A(Qg`8MVK;D8%Vv5mUHo@VY=TfMk=~AhwquNtEC(5`TgHH^P z=;C_dnoAf5EC8eygcRAW~Y zrzS0`osSF%%RtW=a~4#Jq58cMUzsz5%T05+LKno1>0NOnHo_g?N3?L1{$er&sO;}J zc~E#RDIIRnd_7)3m;ym}P=q@_M#d)FIx`=UBh`LZz~S(lZ@rCQ_K`^8*f2X^EWWfA z8D~}ryv1*R#aEGK<<|#UK_%I7OLGR6>uW*i*TPGYYeK563GLU%@|8aHBpyaXAr4Hi ze!VwpXNfI6uUi2t5X*~7DA9g3z!^3k%>)?1+Cgw;1~xf&#QqmSHJXS@60LD>xPOqZ z*QC_o-hi+;HkqMN@asMffy8=q7dz=pRpYw%JcHz#M-!nD#W67qIMD^qfqb7x*n8*Y67STeN37?48M5@Pglbglq6fLugY#S@LX(3Z*Ov@mVB3odY9kDMs_dem29lqid9b|AA$C4vR z*j|LH-}JbhtB^q6s5DF%ONM33>5}1T%2}_vZ6U1MxARd!JI42m% zvJ!-I-c0UlaR?2|K;e)B2HeKh9c$p?7ycb{&0F(!pv|j6>-@CjLsdBkD|<`B4RZ}^ z769`j;xOr?E-i4uHRhVtjn*d`C(F95DkEQVO*d-;g6vT&qlv3pv5fYQRu~*1lp=lY zP6X257e zH|uf9viuxJKHNXb#oymyyf^Cq9dpeaIXkc_={?oJ&vJ_*V=YDCV`X^zfh?|Gukh>m zMK$y43ujucLL78cdRzGYZ)BXs2w1ueROQPiCdaqF${cXq7-Xz83JaC^bm|llul7ZK zuuLY0$ea;)3%XG((ntkqv15Jb6(+a5HMu47$2HbO02js(BSt`O-ApPSK!1V?;xS80zY4|y z+3@uWbo30-v|Ijkh+hYbKb%70kP@V`xp~vAw>Sj4jSuIS2m`jK*>5sm@l}|(KJ_e_ z8dn*YfL?3;V@YJquc(z9l-46~3olM06hJKZ$`0^5BPMSDtnAgfX>_ZIjjPLKLEXqN zwOO265Asi{%axSaqv?Ao>j$BmVxiZ^wY(%OytR?nzFOZ!-O{07yX7nPoRo_Td+UKo zlfp74hEDg<{*03Nbud3C2}s0fvlbJ-0sKEd9&PVM`**C@mZ?%fqZenSoT<&PPwEZH zNK;%(w7dmV2C5c2W<3rRmrjjCVEDxQZz;>lkBSFjnUS{ils3fjbpR{GW7wH=jSQ>6}FwDSn)L3#1c`f1g~3$J8bz za+;+gHXb6r&0BLXBS80xoYaNWlMx9_oF(rnuOd-PGE?dE?Vt56r~1#hotKIapB5Gv z9q2g`CnnZV2h8@^3t;fH?y7tPk!C`5h+9@V>JXwGJ^d|A=>{xn#?_A&D zTYPOd*es5U-BF&kz98M&b*{`w+gy?f7v<4$&8gE^#UHN9VNuVCDbCW!@-5|!mH48J z6k-Nqk8e5D*S_Z0c0j>{!qPn0;}*XjN_F;);`GAcLAPVf|24Sg1;Ke~X3E{g8A~&* z{-#QJ%ss^!gamhHrB=l!5DMN^I34QgHY+wB9VcL*%uP|cXx)Dxml*XCO^i&Yp!oRb8dtzYrd?9ni&&M+6|{kBf8dFG<`$CbofG@n^LAxP&zHa(mMiN z-!WZqy*4i$dyZbO$VuZaZowe$nVC&NCztY#-xmgnfA-DFrt-CeAP?3e0cE&UX|eBuK}}nM!n%*Vg`Pxr`ldn(m9OBM zL68mUIG7KSA&GsQMMpzHWAcq|;(YCk3`B?M$gpHWweP@RON|3GQNGe7e)W671sGDS z3Hq{IcozD*r8E=6j(OiylCe5By(K-F)i;XFU1C<+WGoeeI_x>70FzEPiuJD>c<74k zv~8uCXfd`$z78EwWVxo3(?iX<5nsSi$fRZPFPrB-qg^~yqTL5Le;G0%Ea^Mon&<`l zDGQ;mjDNn_JIYtMk$dS0Bgd4e9`IHqbHbI&s4!0{j zua#sX19)&O!^xUF_+?Q4^3Q1Ha8)i^CNY#UZ;j_yzsrsHl;gk-$fI1mEDjX+jg6(k+zKON zcg@IRl>`g$f~r!%2w&IFig_X)5iz@GW+O8&%Yd+acy_LQDa^Pmye32OTo!i>#VwnP zGY(YdluZ4{l6C*+n_A;09$J#YOqdeWH^OX4ykmNbyagVy+bAY;pkR%+mu1lcJ4})Srzj&@Kw&_J z#h$|{ru$q&fp`(t>5YZlJ3nraI~ic=V|`d3R=}u*?C{ikNszIwsK?2kJt+q&b{le$2G4h z-;}o?blg*sT@n?G@Gwcnw|<>}sLpdS4#=L6Ppz<^V9bHy+T3$j_pugZ>rBIrR>RT# z#;!y9t?P7amr@LO)fm>7>E{(4s?6CwBdcp&*{+7%1!>7dO|lTUiY%pO`VjB=Y17DZ z02+|Wca((kbAI7%t>PuYV7Tzbtwk9mKrDbT6azA>h>FvbF{HG}n3)O=m+@f%PYOpY z;nQ+p}PyL^KR zgCmfbZr%$o!+h`~DEmNhtv}suHtf21ah_rIEaRrio{J5}j>9zSPaC`SYs?+94NFQ^ zWDN?$Gj6I_InHKH@db?XKuf?okmML zrV@Pk1jA$1xy!OsF(3oQb=RWWC-ukQdgqn}=+x-!$5 z>h{xBCy&?a&K)(JY11D$Zfa{WZkvIT*Uv3DP?3#2Tqm|2b5SK?X0#7vq>1B`x0sWd zh|=NosiOiIVak%sUU$s96Yg#=%cK#>!7OkInE_`Q1YYPv+4ojt?X0cX*ff7%bxCW% zbZL}ha_V< z5NsCvI27KLIml^TOJctk7LUB9lu64aL)x}So z-S*nEPhB?MZ#cWxbYiw)W0QVmgJDgnenF9bVR84-D)Z^t=9Be?1H1M64(ku@H=7r9 zA8*vHT%cdI;Mn5&1r-?wYjd%9C?i@xbb;*!8Ch^Z>_~z?h8N-pp2=Yvnu-WnB}7;N z*knOXBN|`I=%;xmuQ(Mc;=bF3CtM=_!4BhuMH=n$Fli|P--a@x>AzHk3*_uPUj_c2w zPc5B)V1E6kRrj1ZraQj-*u3fK2iKRFk5w5qlpB_o5Qt)^as5Ptm>npSyvX@i#U&7< zqKOvzzO1q=E0wi?MTKQIxJLf5U2;s`2+?Xv7A8v+&G8Ks*NoG>r_#_eQ-9>Ne&rwYS>j_GS=vqmSADDXtqGVVVSzaDsf&q0c6}qEs`t}Q* zXH0i3U3<@pja_HV`i_e_hH5Sq3!ghn%*LATJ+tJivEqgoI7QgYR)Z)yCp z3O8O?B&^4j&VoL%wHrE3M%^I;J$H$ohSjA48MIRK<^oc!!dHwT zaTMBtUZB4iL*yCuVHWd_-A3kdlyFVVrUgGKY+kcr4U%HCxgwU{T%O&2sMUD(0Ai_M zQg>!y;f~glQ+G9=SUi7mM(UoqdEKou@X_MAY=Uf`VLZMLHcdUN%-!?!ySBH^u3TGI z^!#Ph!|i8uyY?8)m<$~kk=SGVPVL)rVEcycXOHO!RCGIc?_auP*ZdlN>rCT{QXXw! z8M35k`(4Fbs(rhyf8eE$Dl%%z*j468-k=`opJ~o^DxF$DKtdj#PB4DmgkQr@kO%%d9MY z-{Mp^zsTG^+tjn#(0R(#zSz`0-_Uh(^@6&kHDxb9`{XYke4?xE!s#RDP917LeYiu{ zcK+1ij@IROo!WW8aO|X^^X%@;JMLbzVqaCkfmzvjp92*+hnE%|KTvUaZa%A$LshxF z8ig2xugEa7wQz)!l?k{kmTVifjFuo^IXto(qkJbEkFNcj)Gq z5{#KnR_o@KbswE$zOcm5snfTv)HM-#=Cj$8E@Jk`sCOAPz zzVJk$uqC>Ar4)U0@opBjF>%D!H-GROejS@idFebpFUzcba z2a4-%;}(;7dC$dqlWBwT*0&U))H~{O)|3>sAL~4@?eNA$tK06r=Va@h_pB&5GrwS8MOI;i zI8w5uGF!j1;?N=yw3DeI+5r~KIAI%37N<-de#v@aA-N>D#ye}d9bHp_VNv9GD~e5fXPI_X>~6{K1Xzqn*|VR~I!=ILDrjc3mpyE+Y>UEPL*Jw1zzcd@9ctjWm3 zDjJD-I_7k5ok;{mQVwTFl#WKD3)n*}JT4m$(CA+4-7?d#wD!`v`8_M=>hG+*&$R4* z-SW%pTe_Fk>lRk(n~DgZ^hYX>*W|6pP9=;-c!&yM;oz*C&BYmjyydRq{X5I6lM*YY z#x5)>{m&PE^Z4=I?F|L@EN(uqWozfblk;*5>eDmUH??%0)?aGt($6b19cegwdTwoc zGOHon5Q{#UeZ~H;@x0Yh2Jz;O-BmeOdx&}=r<_m~lYI^(&0hO=$vo;!^C{ra}c`u5A+UE9sZ z2G}>Y?=%^!&88aDi7H)lfvzE6zof|AHK%i9`Pn*>80E%2j4-d~Vw1_d-q2ytpTS$| z+m3d2E}y4s%p-gv9Y?;aDlWb#BDx|v_C$5=&ay04$KwB@sF}D;#l!}ToTqDDcgb++ zFK_pkyeyk zSzTJviR!$wwRtD%OIsH&KRmzAu&~I`QLEoIo9qzOoUP02oLBzpb5H;A#TSeVEA)GJ z=}w$J+f>e4Pk0s*<62S$i_tq~WGqX|(=~bMEPk2iVp7m?QmjidQm{ps7mEYJUZKUr zpI8Y?BYk>#pUbL21TaXH%+OkNoC?BYMUaK50j^-xvGBNZlWBFgVHd?@UP)rD+j!3d z4;=lEU!VKggLj&`n)LUq)oom7*uKi#(;#9qEe`MARnc>yw);?p@!&EdVSW2Wtz6LW z+@-&JnQ>dCVP$DsW9iz)1)G+yKe2O%etYflyGm9s%%!ZV&q6~F&TrJ;y1U5U{IqWGLAW-qD?78c6r;_u4pK0Q+>ZT( zdQOV6ewmjtt#wAGe)Ej(?K8W!*6g`^+wP@z9+*E{w|$mz+kAcNI#~?&-1WWe zVzbG-#Bk22@8~gfwe?(RHg26MR^s!7UBx))mlf;QEY!Dm>)X$3j6?b*LuZHiVvBL- zEZu@iR=7_;@$CEWz4`Np)|xLip1(Br($D5yY;QCznrYaz%Ww`$a&LF%<)2-A`27z) zf?~=ipMFNU`pKt{J^WPXo&z0?MTP^jh$qiA%QbbcvH&ToIjk#N5-h`Y%Sws3dM-7Z z&o4H%cj21XHZMBcSjsY!fLzF7#|7R(*M32F@B|e1#w42Rk>kZ^5G%q6!xBA0FZkpUyYLkk*PS8QZiZR|QD=GoPzKXg)X-KUj|1J`IVQ6ozWm$QDbGFo zoBw$3#g9>7O`Z9C=biUne(Cp8!LMHZCZ6j}+QwDB`gI`+XypOPISu!LxGO;oN+>vbCuB&pH;uF7^Hx0=lK;rwN) z_y1>my-|16(AiGR*1c<%$huhMpC#4mMPw;;XM4zO=-Mv4_?uUxxt5=B{o-$4?(Vw$ z#vlJIZ1~lyk007Zg1R_5LHj+vSjOTFNz35u;2qPAH$>CPKoa51Nf0j8uzUB317~I= zrf=kURYU%)xVY8xmKx4o5Dz`uqi^fM*XRx&6FE{#PNr{$z|P12^^NckxAbPGzjwX+zUGrxS{DyI8ynw$RYGorHJzxv02f9#oG|Hn(8eDdjAFTeQGlaK%V zLyxqtU$H(n6$*r2Yl(NZ4_J9YE;f)l>m39Djq5(tqHkZiw>tmK`cmV`*@yR(pE)(x zpkHxk{hXDR)m&PSS`c*9?RCP=1j4R6b&MmIVE?(KZbjP~QY(VHv>MnNQ z|I&-U{ln{Ty#4mOf^@>~Pd@$k$DjSxGrvZ)KmFU^uU!4~op=8FMEmYzEqV3%T8>mZ z)IrFEMFn=OF4|34MIM7wbLY0rFrTV2t|{x@JImZz+e3_TVX0ofXkk_Pk^&Cl38o}d?gblQh$9#Pi1|%xx2RKvgQ*% zUle~s75l!WrNP{@$k5iIKV#CL?KF3{7UNJXD9ckMf*Ynj3B#+hSX856{U2U`)2zSGY~097-_Tv7-#io5AiIJmC7NP=P54A&mW&)B z5IK--?5Hj;C4e+;ouRvE1TFl?BkU%OPlW~t%s1>J|MjHh>> zJ8eF)`}nTA_Z-=E8V9UB>K$VHO4J7buFc)j#axhEnPIL;pDQ#dXhZs<`7^v z>&G>5+P&u=x@3Ovk)J>L#vk8g z_eyvClu6e@&IE!mv)e1OXJ<@1yrcZQsrJI9y6$Z=*>%M>g0p^kiTUj8O)K(erzIY3 z$|H@2#WpM|KGKjkJ1&7O8-B%!qbK4TNUocU^oxrrm}}m#*F;;dTm~54?|{L7EP@4x>M zDYX}W{o*~VHXgd8S>ICL)l%5il;1^iwV|MELs{p!YTep0!|Jl09vpOSkE!`uEz!?>DsJs5ASsOH0h1b2tJ) zA^-3{K$oxgj+bi9JxjU`dyIxXmvsA|?l|(y{Xc)^sb4?y)C>A{)6Uk-2X;4~HywWI z#oxXE{)eA@CQ@gXLZJTUpZ?sVGwJv2Hngt!#i{*IpF8r@*#kXGstv7Wgo366m1s2a zSogkJ9J<)LuITPHgYQ$&rX!Coz~;P9u*OKp~e4mZ1oM3e(~Ps`yX6!|AWh)d}`mv zSFe0@aE*fcdq06zNY>U-~fc=Z$3sa*p~xS8c;$C5zy7;dpa1>qkH7jF<+0zt{)-Q< z{Pokn{rATof3ko1vK4tLUF*fN8oF7`qR!XaXSn8cE9urR&4-|^YfCR~oBQ~YZRWdI zQJy%u`kE*O7qHfh^Bt7>%EwpVe(SwoK7Fd&SfyWAV%%H7rrW){7XGYt@%@{YzVi43ufF&g z>>FCOQ_$8F%X&khVTCwoN5YC|S;#|!2&hb_W}DlqNvd?WRXy>u9dG^arMKUD<*)C* z`SI1Ok3M$b{KY#TdUV6(`&OAucbGcn+6+>e&-4df|NMOHW=t zf2O|oNOM1~Syrzo?cP~|H8Ad|Fsvyvutr;3Mr1A$S(*hlU#xlJ$sKRJ`P>_CKL5s_ zo_qa|Pd)g^TD*+5*{5ZF=_dF7l*PVLi~Uvd@cauM))6>#Q!HFlx%$Z`XdL;|7cO>n z%@sSpvgn&j^z%x@Aqr~~-FFoe&4zog6(U+@O(e?~*T3g4)nB;WD9iavjo6KWGF)n$ zeh3h)J@D}AUp;^3y}!Oem~Bn5b)BFcWq?M(+6uS%qA&qK~fkFVf&tGbI`IYAAR^>=UT&#a^tp{oLVOs6FyoI{R2mU zoW{eC-u1zU?_Bx#LrZ!8y|?e*e5c{=vd@#!Kk(O7f+`Up|M~D^8y|V>ZcBOi(T#-Q z;_Qc__+JhIjCsGJ_KTIAD+Ck*3ITy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a0fm4hapb$_9Cy)5Kssx1QY@a z0fm4hapb$_9Cy) t5Kssx1QY@a0fm4=13.0", "questionary>=2.0"] # /// -"""Cagire release builder — replaces build-all.sh, make-dmg.sh, make-appimage.sh.""" +"""Cagire release builder.""" from __future__ import annotations @@ -150,6 +150,8 @@ def get_version(root: Path) -> str: def builder_for(p: Platform) -> str: + if p.os == "windows" and p.cross: + return "cargo-xwin" return "cross" if p.cross else "cargo" @@ -195,12 +197,31 @@ def run_cmd( # Build functions # --------------------------------------------------------------------------- -def _macos_env(p: Platform) -> dict[str, str] | None: - if p.os == "macos": - return {"MACOSX_DEPLOYMENT_TARGET": "12.0"} +def _find_llvm_prefix() -> str | None: + """Find Homebrew LLVM installation path.""" + try: + result = subprocess.run( + ["brew", "--prefix", "llvm"], capture_output=True, text=True, + ) + if result.returncode == 0: + return result.stdout.strip() + except FileNotFoundError: + pass return None +def _cross_env(p: Platform) -> dict[str, str] | None: + env = {} + if p.os == "macos": + env["MACOSX_DEPLOYMENT_TARGET"] = "12.0" + if p.os == "windows" and p.cross: + env["VCINSTALLDIR"] = "/dummy" + llvm_prefix = _find_llvm_prefix() + if llvm_prefix: + env["LIBCLANG_PATH"] = f"{llvm_prefix}/lib" + return env or None + + def _platform_features(p: Platform) -> list[str]: if p.os == "windows": return ["--features", "asio"] @@ -211,7 +232,7 @@ def build_binary(root: Path, p: Platform, log: list[str], extra_args: list[str] features = _platform_features(p) if platform_features else [] cmd = [builder_for(p), "build", "--release", *target_flags(p), *features, *(extra_args or [])] log.append(f" Building: {' '.join(extra_args or ['default'])}") - run_cmd(cmd, log, env=_macos_env(p), cwd=root) + run_cmd(cmd, log, env=_cross_env(p), cwd=root) def bundle_plugins(root: Path, p: Platform, log: list[str]) -> None: @@ -224,7 +245,7 @@ def bundle_plugins(root: Path, p: Platform, log: list[str]) -> None: def _bundle_plugins_native(root: Path, p: Platform, log: list[str]) -> None: log.append(" Bundling plugins (native xtask)") cmd = ["cargo", "xtask", "bundle", PLUGIN_NAME, "--release", *target_flags(p)] - run_cmd(cmd, log, env=_macos_env(p), cwd=root) + run_cmd(cmd, log, env=_cross_env(p), cwd=root) def _bundle_plugins_cross(root: Path, p: Platform, log: list[str]) -> None: @@ -267,7 +288,7 @@ def bundle_desktop_app(root: Path, p: Platform, log: list[str]) -> None: return log.append(" Bundling desktop .app") cmd = ["cargo", "bundle", "--release", "--features", "desktop", "--bin", "cagire-desktop", *target_flags(p)] - run_cmd(cmd, log, env=_macos_env(p), cwd=root) + run_cmd(cmd, log, env=_cross_env(p), cwd=root) # --------------------------------------------------------------------------- @@ -444,36 +465,6 @@ def make_appimage(root: Path, binary: Path, arch: str, output_dir: Path, log: li return _make_appimage_docker(root, binary, arch, output_dir, log) -# --------------------------------------------------------------------------- -# Packaging: NSIS -# --------------------------------------------------------------------------- - - -def make_nsis(root: Path, rd: Path, version: str, output_dir: Path, config: BuildConfig, log: list[str]) -> str | None: - if not shutil.which("makensis"): - log.append(" makensis not found, skipping NSIS installer") - return None - - log.append(" Building NSIS installer") - abs_root = str(root.resolve()) - cmd = [ - "makensis", - f"-DVERSION={version}", - f"-DICON={abs_root}/assets/Cagire.ico", - f"-DOUTDIR={abs_root}/{OUT}", - ] - if config.cli: - cmd.append(f"-DCLI_EXE={abs_root}/{rd.relative_to(root)}/cagire.exe") - if config.desktop: - cmd.append(f"-DDESKTOP_EXE={abs_root}/{rd.relative_to(root)}/cagire-desktop.exe") - cmd.append(str(root / "nsis" / "cagire.nsi")) - run_cmd(cmd, log) - - installer = f"cagire-{version}-windows-x86_64-setup.exe" - log.append(f" Installer -> {output_dir / installer}") - return str(output_dir / installer) - - # --------------------------------------------------------------------------- # Artifact copying & packaging dispatch # --------------------------------------------------------------------------- @@ -483,7 +474,6 @@ def copy_artifacts(root: Path, p: Platform, config: BuildConfig, log: list[str]) rd = release_dir(root, p) out = root / OUT sx = suffix_for(p) - version = get_version(root) artifacts: list[str] = [] if config.cli: @@ -515,11 +505,6 @@ def copy_artifacts(root: Path, p: Platform, config: BuildConfig, log: list[str]) if dmg: artifacts.append(dmg) - if p.os == "windows": - nsis = make_nsis(root, rd, version, out, config, log) - if nsis: - artifacts.append(nsis) - if p.os == "linux": if config.cli: ai = make_appimage(root, rd / "cagire", p.arch, out, log) @@ -725,9 +710,10 @@ def run_builds( for p in platforms: _update_phase(p.alias, "waiting", 0) - # Split into native (share cargo lock) and cross (independent Docker builds) - native_platforms = [p for p in platforms if not p.cross] - cross_platforms = [p for p in platforms if p.cross] + # Docker-isolated cross builds (Linux only — each in its own container) + docker_cross = [p for p in platforms if p.cross and p.os != "windows"] + # Local builds share cargo lock — run sequentially + local_builds = [p for p in platforms if not p.cross or p.os == "windows"] results: list[PlatformResult] = [] completed: dict[str, PlatformResult] = {} @@ -740,19 +726,19 @@ def run_builds( return _build_display(platforms, config, completed, start_times, log_max_lines) with Live(make_display(), console=console, refresh_per_second=4) as live: - # Native builds run sequentially in one thread (they contend on cargo lock). - # Cross builds run in parallel (each in its own Docker container). - with ThreadPoolExecutor(max_workers=max(len(cross_platforms) + 1, 1)) as pool: + # Local builds run sequentially (they contend on cargo lock). + # Docker cross builds run in parallel (each in its own container). + with ThreadPoolExecutor(max_workers=max(len(docker_cross) + 1, 1)) as pool: futures = {} - if native_platforms: + if local_builds: f = pool.submit( - _build_native_sequential, root, native_platforms, config, + _build_native_sequential, root, local_builds, config, completed, start_times, ) futures[f] = "native" - for p in cross_platforms: + for p in docker_cross: f = pool.submit(build_platform, root, p, config) futures[f] = "cross" @@ -928,20 +914,22 @@ def check_git_clean(root: Path) -> tuple[str, bool]: def check_prerequisites(platforms: list[Platform], config: BuildConfig) -> None: """Verify required tools are available, fail fast if not.""" - need_cross = any(p.cross for p in platforms) + need_xwin = any(p.os == "windows" and p.cross for p in platforms) + need_cross = any(p.cross and p.os != "windows" for p in platforms) need_docker = any(p.cross and p.os == "linux" for p in platforms) need_bundle = config.desktop and any(not p.cross and p.os == "macos" for p in platforms) - need_nsis = any(p.os == "windows" for p in platforms) checks: list[tuple[str, bool]] = [("cargo", True)] + if need_xwin: + checks.append(("cargo-xwin", True)) + checks.append(("clang", True)) + checks.append(("cmake", True)) if need_cross: checks.append(("cross", True)) if need_docker: checks.append(("docker", True)) if need_bundle: checks.append(("cargo-bundle", True)) - if need_nsis: - checks.append(("makensis", False)) console.print("[bold]Prerequisites:[/]") missing_critical: list[str] = [] diff --git a/scripts/cross/x86_64-windows.Dockerfile b/scripts/cross/x86_64-windows.Dockerfile deleted file mode 100644 index 3aa7b5b..0000000 --- a/scripts/cross/x86_64-windows.Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ghcr.io/cross-rs/x86_64-pc-windows-gnu:main - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - cmake \ - clang \ - libclang-dev \ - mingw-w64-tools \ - mingw-w64-x86-64-dev \ - g++-mingw-w64-x86-64 \ - && rm -rf /var/lib/apt/lists/* \ - && ln -sf windows.h /usr/x86_64-w64-mingw32/include/Windows.h \ - && ln -sf winsock2.h /usr/x86_64-w64-mingw32/include/WinSock2.h \ - && ln -sf ws2tcpip.h /usr/x86_64-w64-mingw32/include/WS2tcpip.h \ - && GCCDIR=$(ls -d /usr/lib/gcc/x86_64-w64-mingw32/*-posix 2>/dev/null | head -1) \ - && ln -sf "$GCCDIR/libstdc++.a" /usr/x86_64-w64-mingw32/lib/libstdc++.a \ - && ln -sf "$GCCDIR/libgcc.a" /usr/x86_64-w64-mingw32/lib/libgcc.a \ - && rm -f /usr/x86_64-w64-mingw32/lib/libstdc++.dll.a \ - && rm -f /usr/lib/gcc/x86_64-w64-mingw32/*/libstdc++.dll.a diff --git a/scripts/platforms.toml b/scripts/platforms.toml index 010f560..f97bd36 100644 --- a/scripts/platforms.toml +++ b/scripts/platforms.toml @@ -5,5 +5,5 @@ triples = [ "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", - "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", ] diff --git a/src/engine/audio.rs b/src/engine/audio.rs index 2bb98ac..53da96a 100644 --- a/src/engine/audio.rs +++ b/src/engine/audio.rs @@ -267,6 +267,7 @@ pub fn preload_sample_heads( #[cfg(feature = "cli")] use cpal::traits::{DeviceTrait, StreamTrait}; +use cpal::FromSample; #[cfg(feature = "cli")] use cpal::Stream; #[cfg(feature = "cli")] @@ -421,29 +422,46 @@ pub fn build_stream( input_cfg.channels(), input_cfg.sample_rate() ); + let input_format = input_cfg.sample_format(); let mut input_producer = input_producer; - let stream = dev - .build_input_stream( - &input_cfg.into(), - move |data: &[f32], _| { - input_producer.push_slice(data); - }, - { - let device_lost = Arc::clone(&device_lost); - move |err: cpal::StreamError| { - eprintln!("input stream error: {err}"); - match err { - cpal::StreamError::DeviceNotAvailable - | cpal::StreamError::StreamInvalidated => { - device_lost.store(true, Ordering::Release); - } - _ => {} + + macro_rules! build_input { + ($T:ty) => {{ + let mut scratch: Vec = Vec::new(); + dev.build_input_stream( + &input_cfg.into(), + move |data: &[$T], _| { + scratch.resize(data.len(), 0.0); + for (dst, &src) in scratch.iter_mut().zip(data.iter()) { + *dst = >::from_sample_(src); } - } - }, - None, - ) - .ok()?; + input_producer.push_slice(&scratch); + }, + { + let device_lost = Arc::clone(&device_lost); + move |err: cpal::StreamError| { + eprintln!("input stream error: {err}"); + match err { + cpal::StreamError::DeviceNotAvailable + | cpal::StreamError::StreamInvalidated => { + device_lost.store(true, Ordering::Release); + } + _ => {} + } + } + }, + None, + ) + }}; + } + + let stream = match input_format { + cpal::SampleFormat::F32 => build_input!(f32), + cpal::SampleFormat::I32 => build_input!(i32), + cpal::SampleFormat::I16 => build_input!(i16), + _ => return None, + } + .ok()?; stream.play().ok()?; Some(stream) }); @@ -455,94 +473,109 @@ pub fn build_stream( let mut live_scratch = vec![0.0f32; 4096]; let mut input_consumer = input_consumer; let mut current_pos: u64 = 0; + let output_format = default_config.sample_format(); - let stream = device - .build_output_stream( - &stream_config, - move |data: &mut [f32], _| { - if !rt_set { - let ok = super::realtime::set_realtime_priority(); - rt_set = true; - if !ok { - super::realtime::warn_no_rt("audio"); + macro_rules! build_output { + ($T:ty) => {{ + let mut conv_buf: Vec = Vec::new(); + device.build_output_stream( + &stream_config, + move |data: &mut [$T], _| { + conv_buf.resize(data.len(), 0.0f32); + + if !rt_set { + let ok = super::realtime::set_realtime_priority(); + rt_set = true; + if !ok { + super::realtime::warn_no_rt("audio"); + } } - } - let buffer_samples = data.len() / channels; - let buffer_time_ns = (buffer_samples as f64 / sr as f64 * 1e9) as u64; + let buffer_samples = conv_buf.len() / channels; + let buffer_time_ns = (buffer_samples as f64 / sr as f64 * 1e9) as u64; - while let Ok(cmd) = audio_rx.try_recv() { - match cmd { - AudioCommand::Evaluate { cmd, tick } => { - let cmd_ref = match tick { - Some(t) => { - cmd_buffer.clear(); - use std::fmt::Write; - let _ = write!(&mut cmd_buffer, "{cmd}/tick/{t}"); - cmd_buffer.as_str() + while let Ok(cmd) = audio_rx.try_recv() { + match cmd { + AudioCommand::Evaluate { cmd, tick } => { + let cmd_ref = match tick { + Some(t) => { + cmd_buffer.clear(); + use std::fmt::Write; + let _ = write!(&mut cmd_buffer, "{cmd}/tick/{t}"); + cmd_buffer.as_str() + } + None => &cmd, + }; + engine.evaluate(cmd_ref); + } + AudioCommand::Hush => { + engine.hush(); + } + AudioCommand::Panic => { + engine.panic(); + } + AudioCommand::LoadSamples(samples) => { + engine.sample_index.extend(samples); + } + AudioCommand::LoadSoundfont(path) => { + if let Err(e) = engine.load_soundfont(&path) { + eprintln!("Failed to load soundfont: {e}"); } - None => &cmd, - }; - engine.evaluate(cmd_ref); - } - AudioCommand::Hush => { - engine.hush(); - } - AudioCommand::Panic => { - engine.panic(); - } - AudioCommand::LoadSamples(samples) => { - engine.sample_index.extend(samples); - } - AudioCommand::LoadSoundfont(path) => { - if let Err(e) = engine.load_soundfont(&path) { - eprintln!("Failed to load soundfont: {e}"); } } } - } - let nch_in = input_channels.max(1); - let raw_len = buffer_samples * nch_in; - if live_scratch.len() < raw_len { - live_scratch.resize(raw_len, 0.0); - } - live_scratch[..raw_len].fill(0.0); - input_consumer.pop_slice(&mut live_scratch[..raw_len]); - - engine.metrics.load.set_buffer_time(buffer_time_ns); - engine.process_block(data, &[], &live_scratch[..raw_len]); - - // Publish accurate audio reference AFTER process_block - // so sample_pos matches doux's internal tick exactly. - current_pos += buffer_samples as u64; - audio_ref.store(Arc::new(AudioRef { - sample_pos: current_pos, - timestamp: Instant::now(), - sample_rate: sr as f64, - })); - - scope_buffer.write(data); - - // Feed mono mix to analysis thread via ring buffer (non-blocking) - for chunk in data.chunks(channels) { - let mono = chunk.iter().sum::() / channels as f32; - let _ = fft_producer.try_push(mono); - } - }, - move |err: cpal::StreamError| { - let _ = error_tx.try_send(format!("stream error: {err}")); - match err { - cpal::StreamError::DeviceNotAvailable - | cpal::StreamError::StreamInvalidated => { - device_lost.store(true, Ordering::Release); + let nch_in = input_channels.max(1); + let raw_len = buffer_samples * nch_in; + if live_scratch.len() < raw_len { + live_scratch.resize(raw_len, 0.0); } - _ => {} - } - }, - None, - ) - .map_err(|e| format!("Failed to build stream: {e}"))?; + live_scratch[..raw_len].fill(0.0); + input_consumer.pop_slice(&mut live_scratch[..raw_len]); + + engine.metrics.load.set_buffer_time(buffer_time_ns); + engine.process_block(&mut conv_buf, &[], &live_scratch[..raw_len]); + + current_pos += buffer_samples as u64; + audio_ref.store(Arc::new(AudioRef { + sample_pos: current_pos, + timestamp: Instant::now(), + sample_rate: sr as f64, + })); + + scope_buffer.write(&conv_buf); + + for chunk in conv_buf.chunks(channels) { + let mono = chunk.iter().sum::() / channels as f32; + let _ = fft_producer.try_push(mono); + } + + for (out, &src) in data.iter_mut().zip(conv_buf.iter()) { + *out = <$T as FromSample>::from_sample_(src); + } + }, + move |err: cpal::StreamError| { + let _ = error_tx.try_send(format!("stream error: {err}")); + match err { + cpal::StreamError::DeviceNotAvailable + | cpal::StreamError::StreamInvalidated => { + device_lost.store(true, Ordering::Release); + } + _ => {} + } + }, + None, + ) + }}; + } + + let stream = match output_format { + cpal::SampleFormat::F32 => build_output!(f32), + cpal::SampleFormat::I32 => build_output!(i32), + cpal::SampleFormat::I16 => build_output!(i16), + format => return Err(format!("unsupported output sample format: {format:?}")), + } + .map_err(|e| format!("Failed to build stream: {e}"))?; stream .play()