Compare commits
17 Commits
v0.1.0
...
35370a6f2c
| Author | SHA1 | Date | |
|---|---|---|---|
| 35370a6f2c | |||
| 4e1c04f9c7 | |||
| 80a3d91f76 | |||
| f130c9b54a | |||
| bdd2f9210e | |||
| 1fb599f574 | |||
| e8cf8c506b | |||
| 16d6d76422 | |||
| cf1d2be140 | |||
| cc89021cc0 | |||
| 470f62df89 | |||
| 88cb43a760 | |||
| eeefb7d54d | |||
| cfd7d31d3d | |||
| e9f5d8bb6d | |||
| 17643b3332 | |||
| 95879c852d |
135
.github/workflows/assemble-macos.yml
vendored
Normal file
135
.github/workflows/assemble-macos.yml
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
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
|
||||
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="${GITHUB_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
|
||||
49
.github/workflows/build-cross.yml
vendored
Normal file
49
.github/workflows/build-cross.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
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
|
||||
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
|
||||
131
.github/workflows/build-linux.yml
vendored
Normal file
131
.github/workflows/build-linux.yml
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
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
|
||||
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/
|
||||
127
.github/workflows/build-macos.yml
vendored
Normal file
127
.github/workflows/build-macos.yml
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
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
|
||||
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/
|
||||
56
.github/workflows/build-plugins-linux.yml
vendored
Normal file
56
.github/workflows/build-plugins-linux.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
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
|
||||
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/
|
||||
66
.github/workflows/build-plugins-macos.yml
vendored
Normal file
66
.github/workflows/build-plugins-macos.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
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
|
||||
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/
|
||||
59
.github/workflows/build-plugins-rpi.yml
vendored
Normal file
59
.github/workflows/build-plugins-rpi.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
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
|
||||
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
|
||||
# CLAP: single .so renamed to .clap
|
||||
cp target/aarch64-unknown-linux-gnu/release/libcagire_plugins.so target/bundled/cagire-plugins.clap
|
||||
# VST3: correct directory structure
|
||||
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/
|
||||
59
.github/workflows/build-plugins-windows.yml
vendored
Normal file
59
.github/workflows/build-plugins-windows.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
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
|
||||
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/
|
||||
18
.github/workflows/build-plugins.yml
vendored
Normal file
18
.github/workflows/build-plugins.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Build Plugins
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
uses: ./.github/workflows/build-plugins-linux.yml
|
||||
|
||||
macos:
|
||||
uses: ./.github/workflows/build-plugins-macos.yml
|
||||
|
||||
windows:
|
||||
uses: ./.github/workflows/build-plugins-windows.yml
|
||||
|
||||
rpi:
|
||||
uses: ./.github/workflows/build-plugins-rpi.yml
|
||||
122
.github/workflows/build-windows.yml
vendored
Normal file
122
.github/workflows/build-windows.yml
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
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
|
||||
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 --target x86_64-pc-windows-msvc
|
||||
|
||||
- name: Build desktop
|
||||
run: cargo build --release --features desktop --bin cagire-desktop --target x86_64-pc-windows-msvc
|
||||
|
||||
- name: Test
|
||||
if: inputs.run-tests
|
||||
run: cargo test --target x86_64-pc-windows-msvc
|
||||
|
||||
- name: Clippy
|
||||
if: inputs.run-clippy
|
||||
run: cargo clippy --target x86_64-pc-windows-msvc -- -D warnings
|
||||
|
||||
- name: Bundle CLAP plugin
|
||||
if: inputs.build-packages
|
||||
run: cargo xtask bundle cagire-plugins --release --target x86_64-pc-windows-msvc
|
||||
|
||||
- name: Install cargo-wix
|
||||
if: inputs.build-packages
|
||||
run: cargo install cargo-wix
|
||||
|
||||
- name: Build MSI installer
|
||||
if: inputs.build-packages
|
||||
run: cargo wix --no-build --nocapture --package cagire -C -arch -C x64
|
||||
|
||||
- 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 MSI artifact
|
||||
if: inputs.build-packages
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cagire-windows-x86_64-msi
|
||||
path: target/wix/*.msi
|
||||
|
||||
- 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-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/
|
||||
69
.github/workflows/ci.yml
vendored
69
.github/workflows/ci.yml
vendored
@@ -4,70 +4,25 @@ on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: macos-14
|
||||
target: aarch64-apple-darwin
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
linux:
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
with:
|
||||
submodules: recursive
|
||||
run-tests: true
|
||||
run-clippy: true
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
macos:
|
||||
uses: ./.github/workflows/build-macos.yml
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
components: clippy
|
||||
run-tests: true
|
||||
run-clippy: true
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
windows:
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
with:
|
||||
key: ${{ matrix.target }}
|
||||
|
||||
- name: Install dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
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
|
||||
|
||||
- name: Install dependencies (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: brew list cmake &>/dev/null || brew install cmake
|
||||
|
||||
- name: Install dependencies (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
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 --target ${{ matrix.target }}
|
||||
|
||||
- name: Build desktop
|
||||
run: cargo build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }}
|
||||
|
||||
- name: Test
|
||||
run: cargo test --target ${{ matrix.target }}
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --target ${{ matrix.target }} -- -D warnings
|
||||
run-tests: true
|
||||
run-clippy: true
|
||||
|
||||
344
.github/workflows/release.yml
vendored
344
.github/workflows/release.yml
vendored
@@ -5,346 +5,44 @@ on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
MACOSX_DEPLOYMENT_TARGET: "12.0"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
linux:
|
||||
if: github.server_url == 'https://github.com'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
artifact: cagire-linux-x86_64
|
||||
- os: macos-15-intel
|
||||
target: x86_64-apple-darwin
|
||||
artifact: cagire-macos-x86_64
|
||||
- os: macos-14
|
||||
target: aarch64-apple-darwin
|
||||
artifact: cagire-macos-aarch64
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
artifact: cagire-windows-x86_64
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
with:
|
||||
submodules: recursive
|
||||
build-packages: true
|
||||
|
||||
- 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 }}
|
||||
|
||||
- name: Install cargo-binstall
|
||||
uses: cargo-bins/cargo-binstall@main
|
||||
|
||||
- name: Install dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
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
|
||||
cargo binstall -y cargo-bundle
|
||||
|
||||
- name: Install dependencies (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew list cmake &>/dev/null || brew install cmake
|
||||
cargo binstall -y cargo-bundle
|
||||
|
||||
- name: Install dependencies (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
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 --target ${{ matrix.target }}
|
||||
|
||||
- name: Build desktop
|
||||
run: cargo build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }}
|
||||
|
||||
- name: Bundle desktop app
|
||||
if: runner.os != 'Windows'
|
||||
run: cargo bundle --release --features desktop --bin cagire-desktop --target ${{ matrix.target }}
|
||||
|
||||
- name: Build AppImages (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
mkdir -p target/releases
|
||||
scripts/make-appimage.sh target/${{ matrix.target }}/release/cagire x86_64 target/releases
|
||||
scripts/make-appimage.sh target/${{ matrix.target }}/release/cagire-desktop x86_64 target/releases
|
||||
|
||||
- name: Upload AppImage artifacts (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-appimage
|
||||
path: target/releases/*.AppImage
|
||||
|
||||
- name: Bundle CLAP plugin
|
||||
run: cargo xtask bundle cagire-plugins --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Zip macOS app bundle
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
cd target/${{ matrix.target }}/release/bundle/osx
|
||||
zip -r Cagire.app.zip Cagire.app
|
||||
|
||||
- name: Upload artifact (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
path: target/${{ matrix.target }}/release/cagire
|
||||
|
||||
- name: Upload artifact (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
path: target/${{ matrix.target }}/release/cagire.exe
|
||||
|
||||
- name: Upload desktop artifact (Linux deb)
|
||||
if: runner.os == 'Linux'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-desktop
|
||||
path: target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||
|
||||
- name: Upload desktop artifact (macOS app bundle)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-desktop
|
||||
path: target/${{ matrix.target }}/release/bundle/osx/Cagire.app.zip
|
||||
|
||||
- name: Upload desktop artifact (Windows exe)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-desktop
|
||||
path: target/${{ matrix.target }}/release/cagire-desktop.exe
|
||||
|
||||
- name: Install cargo-wix (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: cargo install cargo-wix
|
||||
|
||||
- name: Build MSI installer (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: cargo wix --no-build --nocapture -C -p -C x64
|
||||
|
||||
- name: Upload MSI installer (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-msi
|
||||
path: target/wix/*.msi
|
||||
|
||||
- name: Upload CLAP artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-clap
|
||||
path: target/bundled/cagire-plugins.clap
|
||||
|
||||
- name: Upload VST3 artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-vst3
|
||||
path: target/bundled/cagire-plugins.vst3
|
||||
|
||||
build-cross:
|
||||
macos:
|
||||
if: github.server_url == 'https://github.com'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
artifact: cagire-linux-aarch64
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
uses: ./.github/workflows/build-macos.yml
|
||||
with:
|
||||
submodules: recursive
|
||||
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"}
|
||||
]
|
||||
|
||||
- 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 }}
|
||||
|
||||
- name: Install cross
|
||||
run: cargo install cross --git https://github.com/cross-rs/cross
|
||||
|
||||
- name: Build
|
||||
run: cross build --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Build desktop
|
||||
run: cross build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
path: target/${{ matrix.target }}/release/cagire
|
||||
|
||||
- name: Upload desktop artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}-desktop
|
||||
path: target/${{ matrix.target }}/release/cagire-desktop
|
||||
|
||||
universal-macos:
|
||||
windows:
|
||||
if: github.server_url == 'https://github.com'
|
||||
needs: build
|
||||
runs-on: macos-14
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Download macOS artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
with:
|
||||
pattern: cagire-macos-*
|
||||
path: artifacts
|
||||
build-packages: true
|
||||
|
||||
- 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
|
||||
cross:
|
||||
if: github.server_url == 'https://github.com'
|
||||
uses: ./.github/workflows/build-cross.yml
|
||||
|
||||
- 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
|
||||
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="${GITHUB_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: Upload universal CLAP plugin
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cagire-macos-universal-clap
|
||||
path: cagire-plugins.clap
|
||||
|
||||
- name: Upload universal VST3 plugin
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cagire-macos-universal-vst3
|
||||
path: cagire-plugins.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
|
||||
assemble-macos:
|
||||
needs: macos
|
||||
uses: ./.github/workflows/assemble-macos.yml
|
||||
|
||||
release:
|
||||
needs: [build, build-cross, universal-macos]
|
||||
needs: [linux, macos, windows, cross, assemble-macos]
|
||||
if: startsWith(github.ref, 'refs/tags/v') && github.server_url == 'https://github.com'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -2,6 +2,28 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.1.1]
|
||||
|
||||
### Forth Language
|
||||
- `map` word: apply a quotation to each stack element (`1 2 3 ( 10 * ) map => 10 20 30`).
|
||||
- `loop` fix: now operates in steps instead of beats, uses `step_duration()` for correct timing.
|
||||
|
||||
### Fixed
|
||||
- Crash on missing sample directories: sample path scanning now validates directories exist before scanning.
|
||||
- Audio channel minimum enforced to 2, preventing crash on devices reporting fewer channels.
|
||||
- Audio device disconnect: automatic stream restart when device is lost (terminal and desktop).
|
||||
- Live keys (e.g. `f` for fill) no longer trigger while searching in dictionary or help views.
|
||||
- Side panel always uses horizontal layout (removed broken vertical fallback for narrow terminals).
|
||||
|
||||
### Changed
|
||||
- Runtime highlight enabled by default.
|
||||
|
||||
### Packaging
|
||||
- Modular CI: split monolithic release workflow into per-platform builds (Linux, macOS, Windows, cross-compilation).
|
||||
- Separate CI workflows for CLAP/VST plugin builds (Linux, macOS, Windows, Raspberry Pi).
|
||||
- Windows MSI installer workflow fixes.
|
||||
- Website download matrix updated.
|
||||
|
||||
## [0.1.0]
|
||||
|
||||
### Breaking
|
||||
|
||||
16
Cargo.lock
generated
16
Cargo.lock
generated
@@ -846,7 +846,7 @@ checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21"
|
||||
|
||||
[[package]]
|
||||
name = "cagire"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"arc-swap",
|
||||
@@ -885,7 +885,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cagire-forth"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"parking_lot",
|
||||
@@ -894,7 +894,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cagire-markdown"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"minimad",
|
||||
"ratatui",
|
||||
@@ -902,7 +902,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cagire-plugins"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"cagire",
|
||||
@@ -926,7 +926,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cagire-project"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"brotli",
|
||||
@@ -938,7 +938,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cagire-ratatui"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"ratatui",
|
||||
@@ -1809,8 +1809,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "doux"
|
||||
version = "0.0.5"
|
||||
source = "git+https://github.com/sova-org/doux#886702b4fe937d26ed681a2f6d7626d26d6890d0"
|
||||
version = "0.0.6"
|
||||
source = "git+https://github.com/sova-org/doux#14ccf68c0ac626718664f32ede20f13087df8de6"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"clap",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
members = ["crates/forth", "crates/markdown", "crates/project", "crates/ratatui", "plugins/cagire-plugins", "plugins/baseview", "plugins/egui-baseview", "plugins/nih-plug-egui", "xtask"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
authors = ["Raphaël Forment <raphael.forment@gmail.com>"]
|
||||
license = "AGPL-3.0"
|
||||
|
||||
@@ -118,6 +118,7 @@ pub enum Op {
|
||||
Euclid,
|
||||
EuclidRot,
|
||||
Times,
|
||||
Map,
|
||||
Chord(&'static [i64]),
|
||||
Transpose,
|
||||
Invert,
|
||||
|
||||
@@ -1180,11 +1180,11 @@ impl Forth {
|
||||
}
|
||||
|
||||
Op::Loop => {
|
||||
let beats = pop_float(stack)?;
|
||||
let steps = pop_float(stack)?;
|
||||
if ctx.tempo == 0.0 || ctx.speed == 0.0 {
|
||||
return Err("tempo and speed must be non-zero".into());
|
||||
}
|
||||
let dur = beats * 60.0 / ctx.tempo / ctx.speed;
|
||||
let dur = steps * ctx.step_duration();
|
||||
cmd.set_param("fit", Value::Float(dur, None));
|
||||
cmd.set_param("dur", Value::Float(dur, None));
|
||||
}
|
||||
@@ -1374,6 +1374,15 @@ impl Forth {
|
||||
}
|
||||
}
|
||||
|
||||
Op::Map => {
|
||||
let quot = pop(stack)?;
|
||||
let items = std::mem::take(stack);
|
||||
for item in items {
|
||||
stack.push(item);
|
||||
run_quotation(quot.clone(), stack, outputs, cmd)?;
|
||||
}
|
||||
}
|
||||
|
||||
Op::GeomRange => {
|
||||
let count = pop_int(stack)?;
|
||||
let ratio = pop_float(stack)?;
|
||||
|
||||
@@ -110,6 +110,7 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
|
||||
"euclid" => Op::Euclid,
|
||||
"euclidrot" => Op::EuclidRot,
|
||||
"times" => Op::Times,
|
||||
"map" => Op::Map,
|
||||
"m." => Op::MidiEmit,
|
||||
"ccval" => Op::GetMidiCC,
|
||||
"mclock" => Op::MidiClock,
|
||||
|
||||
@@ -567,6 +567,16 @@ pub(super) const WORDS: &[Word] = &[
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
Word {
|
||||
name: "map",
|
||||
aliases: &[],
|
||||
category: "Control",
|
||||
stack: "(..vals quot -- ..results)",
|
||||
desc: "Apply quotation to each stack element",
|
||||
example: "1 2 3 ( 10 * ) map => 10 20 30",
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
// Variables
|
||||
Word {
|
||||
name: "@<var>",
|
||||
|
||||
@@ -280,8 +280,8 @@ pub(super) const WORDS: &[Word] = &[
|
||||
aliases: &[],
|
||||
category: "Time",
|
||||
stack: "(n --)",
|
||||
desc: "Fit sample to n beats",
|
||||
example: "\"break\" s 4 loop @",
|
||||
desc: "Fit sample to n steps",
|
||||
example: "\"break\" s 16 loop @",
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
|
||||
8371
demos/03.cagire
8371
demos/03.cagire
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ Each pattern is an independent sequence of steps with its own properties:
|
||||
| Sync Mode | Reset or Phase-Lock on re-trigger | `Reset` |
|
||||
| Follow Up | What happens when the pattern finishes an iteration | `Loop` |
|
||||
|
||||
Press `e` in the patterns view to edit these settings. After editing properties, you will have to hit the `c` key to _commit_ these changes. More about that later!
|
||||
Press `e` in the patterns view to edit these settings. After editing properties, you will have to hit the `c` key to _launch_ these changes. More about that later!
|
||||
|
||||
### Follow Up
|
||||
|
||||
@@ -46,12 +46,12 @@ The follow-up action determines what happens when a pattern reaches the end of i
|
||||
Access the patterns view with `F2` (or `Ctrl+Up` from the sequencer). The view shows all banks and patterns in a grid. Indicators show pattern state:
|
||||
|
||||
- `>` Currently playing
|
||||
- `+` Staged to play
|
||||
- `-` Staged to stop
|
||||
- `+` Armed to play
|
||||
- `-` Armed to stop
|
||||
- `M` Muted
|
||||
- `S` Soloed
|
||||
|
||||
It is quite essential for you to understand the stage / commit system in order to use patterns. Please read the next section carefully!
|
||||
It is quite essential for you to understand the arm / launch system in order to use patterns. Please read the next section carefully!
|
||||
|
||||
### Keybindings
|
||||
|
||||
@@ -59,13 +59,13 @@ It is quite essential for you to understand the stage / commit system in order t
|
||||
|-----|--------|
|
||||
| `Arrows` | Navigate banks and patterns |
|
||||
| `Enter` | Select and return to sequencer |
|
||||
| `p` | Stage pattern to play/stop |
|
||||
| `c` | Commit staged changes |
|
||||
| `m` / `x` | Stage mute / solo toggle |
|
||||
| `p` | Arm pattern to play/stop |
|
||||
| `c` | Launch armed changes |
|
||||
| `m` / `x` | Arm mute / solo toggle |
|
||||
| `e` | Edit pattern properties |
|
||||
| `r` | Rename bank or pattern |
|
||||
| `Ctrl+c` / `Ctrl+v` | Copy / Paste |
|
||||
| `Delete` | Reset to empty pattern |
|
||||
| `Esc` | Cancel staged changes |
|
||||
| `Esc` | Cancel armed changes |
|
||||
|
||||
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
# Stage / Commit
|
||||
# Arm / Launch
|
||||
|
||||
In Cagire, changes to playback happen in two steps. First you **stage**: you mark what you want to happen. Then you **commit**: you apply all staged changes at once. Nothing changes until you commit. It is simpler than it sounds.
|
||||
In Cagire, changes to playback happen in two steps. First you **arm**: you mark what you want to happen. Then you **launch**: you apply all armed changes at once. Nothing changes until you launch. It is simpler than it sounds.
|
||||
|
||||
Say you want patterns `04` and `05` to start playing together. You stage both (`p` on each), then commit (`c`). Both start at the same time. Want to stop them later? Stage them again, commit again. That's it.
|
||||
Say you want patterns `04` and `05` to start playing together. You arm both (`p` on each), then launch (`c`). Both start at the same time. Want to stop them later? Arm them again, launch again. That's it.
|
||||
|
||||
This two-step process exists for good reasons:
|
||||
|
||||
- **Multiple changes at once**: queue several patterns to start/stop, commit them together.
|
||||
- **Multiple changes at once**: queue several patterns to start/stop, launch them together.
|
||||
- **Clean timing**: all changes land on beat or bar boundaries, never mid-step.
|
||||
- **Safe preparation**: set up the next section while the current one keeps playing.
|
||||
|
||||
## Push changes, then apply
|
||||
## Arm changes, then launch
|
||||
|
||||
Staging is an essential feature to understand to be effective when doing live performances:
|
||||
Arming is an essential feature to understand to be effective when doing live performances:
|
||||
|
||||
1. Open the **Patterns** view (`F2` or `Ctrl+Up` from sequencer)
|
||||
2. Navigate to a pattern you wish to change/play
|
||||
3. Press `p` to stage it. The pending change is going to be displayed:
|
||||
- `+` (staged to play)
|
||||
- `-` (staged to stop)
|
||||
- `m` (staged to mute)
|
||||
- `s` (staged to solo)
|
||||
3. Press `p` to arm it. The pending change is going to be displayed:
|
||||
- `+` (armed to play)
|
||||
- `-` (armed to stop)
|
||||
- `m` (armed to mute)
|
||||
- `s` (armed to solo)
|
||||
- etc.
|
||||
4. Repeat for other patterns you want to change
|
||||
5. Press `c` to commit all changes
|
||||
5. Press `c` to launch all changes
|
||||
6. Or press `Esc` to cancel
|
||||
|
||||
You can also stage mute/solo changes:
|
||||
You can also arm mute/solo changes:
|
||||
|
||||
- Press `m` to stage a mute toggle
|
||||
- Press `x` to stage a solo toggle
|
||||
- Press `m` to arm a mute toggle
|
||||
- Press `x` to arm a solo toggle
|
||||
- Press `Shift+m` to clear all mutes
|
||||
- Press `Shift+x` to clear all solos
|
||||
|
||||
@@ -41,16 +41,18 @@ It might wait for the next beat/bar boundary.
|
||||
| Indicator | Meaning |
|
||||
|-----------|---------|
|
||||
| `>` | Currently playing |
|
||||
| `+` | Staged to play |
|
||||
| `-` | Staged to stop |
|
||||
| `+` | Armed to play |
|
||||
| `-` | Armed to stop |
|
||||
| `M` | Muted |
|
||||
| `S` | Soloed |
|
||||
|
||||
A pattern can show combined indicators, e.g. `>` (playing) and `-` (staged to stop), or `>M` (playing and muted).
|
||||
A pattern can show combined indicators, e.g. `>` (playing) and `-` (armed to stop), or `>M` (playing and muted).
|
||||
|
||||
Armed patterns blink to make pending changes impossible to miss.
|
||||
|
||||
## Quantization
|
||||
|
||||
Committed changes don't execute immediately. They wait for a quantization boundary:
|
||||
Launched changes don't execute immediately. They wait for a quantization boundary:
|
||||
|
||||
| Setting | Behavior |
|
||||
|---------|----------|
|
||||
|
||||
@@ -330,7 +330,7 @@ copy_artifacts() {
|
||||
# MSI installer for Windows targets
|
||||
if [[ "$os" == "windows" ]] && command -v cargo-wix &>/dev/null; then
|
||||
echo " Building MSI installer..."
|
||||
cargo wix --no-build --nocapture -C -p -C x64
|
||||
cargo wix --no-build --nocapture --package cagire -C -arch -C x64
|
||||
cp target/wix/*.msi "$OUT/" 2>/dev/null && echo " MSI -> $OUT/" || true
|
||||
fi
|
||||
|
||||
|
||||
@@ -14,4 +14,8 @@ RUN dpkg --add-architecture arm64 && \
|
||||
libxcb-xfixes0-dev:arm64 \
|
||||
libxkbcommon-dev:arm64 \
|
||||
libgl1-mesa-dev:arm64 \
|
||||
libxcursor-dev:arm64 \
|
||||
libxrandr-dev:arm64 \
|
||||
libxi-dev:arm64 \
|
||||
libwayland-dev:arm64 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -13,4 +13,8 @@ RUN apt-get update && \
|
||||
libxcb-xfixes0-dev \
|
||||
libxkbcommon-dev \
|
||||
libgl1-mesa-dev \
|
||||
libxcursor-dev \
|
||||
libxrandr-dev \
|
||||
libxi-dev \
|
||||
libwayland-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
66
scripts/make-app-bundle.sh
Executable file
66
scripts/make-app-bundle.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Usage: scripts/make-app-bundle.sh <target>
|
||||
# Creates a macOS .app bundle at target/<target>/release/bundle/osx/Cagire.app
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <target>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET="$1"
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
BINARY="$REPO_ROOT/target/$TARGET/release/cagire-desktop"
|
||||
ICON="$REPO_ROOT/assets/Cagire.icns"
|
||||
VERSION="0.1.0"
|
||||
|
||||
if [[ ! -f "$BINARY" ]]; then
|
||||
echo "ERROR: binary not found at $BINARY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
APP_DIR="$REPO_ROOT/target/$TARGET/release/bundle/osx/Cagire.app"
|
||||
CONTENTS="$APP_DIR/Contents"
|
||||
rm -rf "$APP_DIR"
|
||||
mkdir -p "$CONTENTS/MacOS" "$CONTENTS/Resources"
|
||||
|
||||
cp "$BINARY" "$CONTENTS/MacOS/cagire-desktop"
|
||||
[[ -f "$ICON" ]] && cp "$ICON" "$CONTENTS/Resources/Cagire.icns"
|
||||
|
||||
cat > "$CONTENTS/Info.plist" <<PLIST
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleName</key>
|
||||
<string>Cagire</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Cagire</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.sova.cagire</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${VERSION}</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${VERSION}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>cagire-desktop</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Cagire.icns</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.music</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) 2025 Raphaël Forment</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Cagire needs microphone access for audio input.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
PLIST
|
||||
|
||||
echo " APP -> $APP_DIR"
|
||||
@@ -215,7 +215,7 @@ impl App {
|
||||
},
|
||||
);
|
||||
self.ui
|
||||
.set_status(format!("{} props staged", bp_label(bank, pattern)));
|
||||
.set_status(format!("{} props armed", bp_label(bank, pattern)));
|
||||
}
|
||||
|
||||
// Page navigation
|
||||
|
||||
@@ -24,7 +24,7 @@ impl App {
|
||||
if let Some(idx) = existing {
|
||||
self.playback.staged_changes.remove(idx);
|
||||
self.ui
|
||||
.set_status(format!("{} unstaged", bp_label(bank, pattern)));
|
||||
.set_status(format!("{} disarmed", bp_label(bank, pattern)));
|
||||
} else if is_playing {
|
||||
self.playback.staged_changes.push(StagedChange {
|
||||
change: PatternChange::Stop { bank, pattern },
|
||||
@@ -32,7 +32,7 @@ impl App {
|
||||
sync_mode: pattern_data.sync_mode,
|
||||
});
|
||||
self.ui
|
||||
.set_status(format!("{} staged to stop", bp_label(bank, pattern)));
|
||||
.set_status(format!("{} armed to stop", bp_label(bank, pattern)));
|
||||
} else {
|
||||
self.playback.staged_changes.push(StagedChange {
|
||||
change: PatternChange::Start { bank, pattern },
|
||||
@@ -40,7 +40,7 @@ impl App {
|
||||
sync_mode: pattern_data.sync_mode,
|
||||
});
|
||||
self.ui
|
||||
.set_status(format!("{} staged to play", bp_label(bank, pattern)));
|
||||
.set_status(format!("{} armed to play", bp_label(bank, pattern)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ impl App {
|
||||
let prop_count = self.playback.staged_prop_changes.len();
|
||||
|
||||
if pattern_count == 0 && mute_count == 0 && prop_count == 0 {
|
||||
self.ui.set_status("No changes to commit".to_string());
|
||||
self.ui.set_status("No changes to launch".to_string());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ impl App {
|
||||
}
|
||||
|
||||
let total = pattern_count + mute_count + prop_count;
|
||||
let status = format!("Committed {total} changes");
|
||||
let status = format!("Launched {total} changes");
|
||||
self.ui.set_status(status);
|
||||
|
||||
mute_changed
|
||||
@@ -110,7 +110,7 @@ impl App {
|
||||
self.playback.staged_prop_changes.clear();
|
||||
|
||||
let total = pattern_count + mute_count + prop_count;
|
||||
let status = format!("Cleared {total} staged changes");
|
||||
let status = format!("Cleared {total} armed changes");
|
||||
self.ui.set_status(status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ struct CagireDesktop {
|
||||
_input_stream: Option<cpal::Stream>,
|
||||
_analysis_handle: Option<AnalysisHandle>,
|
||||
midi_rx: Receiver<MidiCommand>,
|
||||
device_lost: Arc<AtomicBool>,
|
||||
stream_error_rx: crossbeam_channel::Receiver<String>,
|
||||
current_font: FontChoice,
|
||||
zoom_factor: f32,
|
||||
@@ -207,6 +208,7 @@ impl CagireDesktop {
|
||||
_input_stream: b.input_stream,
|
||||
_analysis_handle: b.analysis_handle,
|
||||
midi_rx: b.midi_rx,
|
||||
device_lost: b.device_lost,
|
||||
stream_error_rx: b.stream_error_rx,
|
||||
current_font,
|
||||
zoom_factor,
|
||||
@@ -251,9 +253,13 @@ impl CagireDesktop {
|
||||
let mut restart_samples = Vec::new();
|
||||
self.app.audio.config.sample_counts.clear();
|
||||
for path in &self.app.audio.config.sample_paths {
|
||||
if path.is_dir() {
|
||||
let index = doux::sampling::scan_samples_dir(path);
|
||||
self.app.audio.config.sample_counts.push(index.len());
|
||||
restart_samples.extend(index);
|
||||
} else {
|
||||
self.app.audio.config.sample_counts.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
self.audio_sample_pos.store(0, Ordering::Release);
|
||||
@@ -273,6 +279,7 @@ impl CagireDesktop {
|
||||
Arc::clone(&self.audio_sample_pos),
|
||||
new_error_tx,
|
||||
&self.app.audio.config.sample_paths,
|
||||
Arc::clone(&self.device_lost),
|
||||
) {
|
||||
Ok((new_stream, new_input, info, new_analysis, registry)) => {
|
||||
self._stream = Some(new_stream);
|
||||
@@ -369,6 +376,11 @@ impl eframe::App for CagireDesktop {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
self.handle_audio_restart();
|
||||
|
||||
if self.device_lost.load(Ordering::Acquire) {
|
||||
self.device_lost.store(false, Ordering::Release);
|
||||
self.app.audio.restart_pending = true;
|
||||
}
|
||||
|
||||
while let Ok(err) = self.stream_error_rx.try_recv() {
|
||||
self.app.ui.flash(&err, 3000, cagire::state::FlashKind::Error);
|
||||
}
|
||||
|
||||
@@ -309,6 +309,7 @@ pub fn build_stream(
|
||||
audio_sample_pos: Arc<AtomicU64>,
|
||||
error_tx: Sender<String>,
|
||||
sample_paths: &[std::path::PathBuf],
|
||||
device_lost: Arc<AtomicBool>,
|
||||
) -> Result<BuildStreamResult, String> {
|
||||
let device = match &config.output_device {
|
||||
Some(name) => doux::audio::find_output_device(name)
|
||||
@@ -320,7 +321,7 @@ pub fn build_stream(
|
||||
let sample_rate = default_config.sample_rate() as f32;
|
||||
|
||||
let max_channels = doux::audio::max_output_channels(&device);
|
||||
let channels = config.channels.min(max_channels);
|
||||
let channels = config.channels.min(max_channels).max(2);
|
||||
|
||||
let host_name = doux::audio::preferred_host().id().name().to_string();
|
||||
let is_jack = host_name.to_lowercase().contains("jack");
|
||||
@@ -410,7 +411,13 @@ pub fn build_stream(
|
||||
drop(b.drain(..excess));
|
||||
}
|
||||
},
|
||||
|err| eprintln!("input stream error: {err}"),
|
||||
{
|
||||
let device_lost = Arc::clone(&device_lost);
|
||||
move |err| {
|
||||
eprintln!("input stream error: {err}");
|
||||
device_lost.store(true, Ordering::Release);
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.ok()?;
|
||||
@@ -521,7 +528,10 @@ pub fn build_stream(
|
||||
let _ = fft_producer.try_push(mono);
|
||||
}
|
||||
},
|
||||
move |err| { let _ = error_tx.try_send(format!("stream error: {err}")); },
|
||||
move |err| {
|
||||
let _ = error_tx.try_send(format!("stream error: {err}"));
|
||||
device_lost.store(true, Ordering::Release);
|
||||
},
|
||||
None,
|
||||
)
|
||||
.map_err(|e| format!("Failed to build stream: {e}"))?;
|
||||
|
||||
@@ -43,6 +43,7 @@ pub struct Init {
|
||||
pub input_stream: Option<cpal::Stream>,
|
||||
pub analysis_handle: Option<AnalysisHandle>,
|
||||
pub midi_rx: Receiver<MidiCommand>,
|
||||
pub device_lost: Arc<AtomicBool>,
|
||||
pub stream_error_rx: crossbeam_channel::Receiver<String>,
|
||||
#[cfg(feature = "desktop")]
|
||||
pub settings: Settings,
|
||||
@@ -158,9 +159,14 @@ pub fn init(args: InitArgs) -> Init {
|
||||
let sample_rate_shared = Arc::new(AtomicU32::new(44100));
|
||||
let mut initial_samples = Vec::new();
|
||||
for path in &app.audio.config.sample_paths {
|
||||
if path.is_dir() {
|
||||
let index = doux::sampling::scan_samples_dir(path);
|
||||
app.audio.config.sample_counts.push(index.len());
|
||||
initial_samples.extend(index);
|
||||
} else {
|
||||
eprintln!("Sample path not found: {}", path.display());
|
||||
app.audio.config.sample_counts.push(0);
|
||||
}
|
||||
}
|
||||
let preload_entries: Vec<(String, std::path::PathBuf)> = initial_samples
|
||||
.iter()
|
||||
@@ -197,6 +203,7 @@ pub fn init(args: InitArgs) -> Init {
|
||||
seq_config,
|
||||
);
|
||||
|
||||
let device_lost = Arc::new(AtomicBool::new(false));
|
||||
let (stream_error_tx, stream_error_rx) = crossbeam_channel::bounded(16);
|
||||
|
||||
let stream_config = AudioStreamConfig {
|
||||
@@ -217,6 +224,7 @@ pub fn init(args: InitArgs) -> Init {
|
||||
Arc::clone(&audio_sample_pos),
|
||||
stream_error_tx,
|
||||
&app.audio.config.sample_paths,
|
||||
Arc::clone(&device_lost),
|
||||
) {
|
||||
Ok((s, input, info, analysis, registry)) => {
|
||||
app.audio.config.sample_rate = info.sample_rate;
|
||||
@@ -262,6 +270,7 @@ pub fn init(args: InitArgs) -> Init {
|
||||
input_stream,
|
||||
analysis_handle,
|
||||
midi_rx,
|
||||
device_lost,
|
||||
stream_error_rx,
|
||||
#[cfg(feature = "desktop")]
|
||||
settings,
|
||||
|
||||
@@ -85,6 +85,7 @@ fn handle_live_keys(ctx: &mut InputContext, key: &KeyEvent) -> bool {
|
||||
match (key.code, key.kind) {
|
||||
_ if !matches!(ctx.app.ui.modal, Modal::None) => false,
|
||||
_ if ctx.app.page == Page::Script && ctx.app.script_editor.focused => false,
|
||||
_ if ctx.app.ui.dict_search_active || ctx.app.ui.help_search_active => false,
|
||||
(KeyCode::Char('f'), KeyEventKind::Press) if !key.modifiers.contains(KeyModifiers::ALT) => {
|
||||
ctx.dispatch(AppCommand::ToggleLiveKeysFill);
|
||||
true
|
||||
|
||||
19
src/main.rs
19
src/main.rs
@@ -103,6 +103,7 @@ fn main() -> io::Result<()> {
|
||||
let mut _input_stream = b.input_stream;
|
||||
let mut _analysis_handle = b.analysis_handle;
|
||||
let mut midi_rx = b.midi_rx;
|
||||
let device_lost = b.device_lost;
|
||||
let mut stream_error_rx = b.stream_error_rx;
|
||||
|
||||
enable_raw_mode()?;
|
||||
@@ -141,9 +142,13 @@ fn main() -> io::Result<()> {
|
||||
let mut restart_samples = Vec::new();
|
||||
app.audio.config.sample_counts.clear();
|
||||
for path in &app.audio.config.sample_paths {
|
||||
if path.is_dir() {
|
||||
let index = doux::sampling::scan_samples_dir(path);
|
||||
app.audio.config.sample_counts.push(index.len());
|
||||
restart_samples.extend(index);
|
||||
} else {
|
||||
app.audio.config.sample_counts.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
audio_sample_pos.store(0, Ordering::Relaxed);
|
||||
@@ -163,6 +168,7 @@ fn main() -> io::Result<()> {
|
||||
Arc::clone(&audio_sample_pos),
|
||||
new_error_tx,
|
||||
&app.audio.config.sample_paths,
|
||||
Arc::clone(&device_lost),
|
||||
) {
|
||||
Ok((new_stream, new_input, info, new_analysis, registry)) => {
|
||||
_stream = Some(new_stream);
|
||||
@@ -193,6 +199,11 @@ fn main() -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
if device_lost.load(Ordering::Acquire) {
|
||||
device_lost.store(false, Ordering::Release);
|
||||
app.audio.restart_pending = true;
|
||||
}
|
||||
|
||||
while let Ok(err) = stream_error_rx.try_recv() {
|
||||
app.ui.flash(&err, 3000, state::FlashKind::Error);
|
||||
}
|
||||
@@ -344,10 +355,16 @@ fn main() -> io::Result<()> {
|
||||
let elapsed = last_frame.elapsed();
|
||||
last_frame = Instant::now();
|
||||
|
||||
let has_armed = app.playback.has_armed();
|
||||
if has_armed {
|
||||
let rate = std::f32::consts::TAU; // 1 Hz full cycle
|
||||
app.ui.pulse_phase = (app.ui.pulse_phase + elapsed.as_secs_f32() * rate) % std::f32::consts::TAU;
|
||||
}
|
||||
let effects_active = app.ui.effects.borrow().is_running()
|
||||
|| app.ui.modal_fx.borrow().is_some()
|
||||
|| app.ui.title_fx.borrow().is_some()
|
||||
|| app.ui.nav_fx.borrow().is_some();
|
||||
|| app.ui.nav_fx.borrow().is_some()
|
||||
|| has_armed;
|
||||
let cursor_pulse = app.page == page::Page::Main && !app.ui.performance_mode && !app.playback.playing;
|
||||
let audio_cooldown = !app.playback.playing && last_stop_time.elapsed() < Duration::from_secs(1);
|
||||
if app.playback.playing || had_event || app.ui.show_title || effects_active || app.ui.show_minimap() || cursor_pulse || audio_cooldown {
|
||||
|
||||
@@ -30,12 +30,12 @@ pub fn for_page(page: Page) -> &'static [(&'static str, &'static [(&'static str,
|
||||
],
|
||||
Page::Patterns => &[
|
||||
(
|
||||
"Organize your project into banks and patterns. The left column lists 32 banks, the right shows patterns in the selected bank. The bottom strip previews steps and pattern properties. Stage patterns to play or stop, then commit to apply all changes at once.",
|
||||
"Organize your project into banks and patterns. The left column lists 32 banks, the right shows patterns in the selected bank. The bottom strip previews steps and pattern properties. Arm patterns to play or stop, then launch to apply all changes at once.",
|
||||
&[
|
||||
("Arrows", "navigate"),
|
||||
("Enter", "open in sequencer"),
|
||||
("Space", "stage play/stop"),
|
||||
("c", "commit changes"),
|
||||
("p", "arm play/stop"),
|
||||
("c", "launch changes"),
|
||||
("r", "rename"),
|
||||
("e", "properties"),
|
||||
("?", "all keys"),
|
||||
@@ -44,8 +44,8 @@ pub fn for_page(page: Page) -> &'static [(&'static str, &'static [(&'static str,
|
||||
(
|
||||
"Mute and solo patterns to control the mix. Use euclidean distribution to generate rhythmic patterns from a single step. Select multiple patterns with Shift for bulk operations.",
|
||||
&[
|
||||
("m", "stage mute"),
|
||||
("s", "stage solo"),
|
||||
("m", "arm mute"),
|
||||
("s", "arm solo"),
|
||||
("E", "euclidean"),
|
||||
("Shift+↑↓", "select range"),
|
||||
("y", "copy"),
|
||||
|
||||
@@ -112,7 +112,7 @@ impl Default for DisplaySettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
fps: 60,
|
||||
runtime_highlight: false,
|
||||
runtime_highlight: true,
|
||||
show_scope: true,
|
||||
show_spectrum: true,
|
||||
show_lissajous: true,
|
||||
|
||||
@@ -130,6 +130,34 @@ impl PlaybackState {
|
||||
self.soloed.contains(&(bank, pattern))
|
||||
}
|
||||
|
||||
pub fn has_armed(&self) -> bool {
|
||||
!self.staged_changes.is_empty()
|
||||
|| !self.staged_mute_changes.is_empty()
|
||||
|| !self.staged_prop_changes.is_empty()
|
||||
}
|
||||
|
||||
pub fn armed_summary(&self) -> Option<String> {
|
||||
let play = self.staged_changes.iter().filter(|c| matches!(c.change, PatternChange::Start { .. })).count();
|
||||
let stop = self.staged_changes.iter().filter(|c| matches!(c.change, PatternChange::Stop { .. })).count();
|
||||
let mute = self.staged_mute_changes.iter().filter(|c| matches!(c, StagedMuteChange::ToggleMute { .. })).count();
|
||||
let solo = self.staged_mute_changes.iter().filter(|c| matches!(c, StagedMuteChange::ToggleSolo { .. })).count();
|
||||
let props = self.staged_prop_changes.len();
|
||||
|
||||
let parts: Vec<String> = [
|
||||
(play, "play"),
|
||||
(stop, "stop"),
|
||||
(mute, "mute"),
|
||||
(solo, "solo"),
|
||||
(props, "props"),
|
||||
]
|
||||
.into_iter()
|
||||
.filter(|(n, _)| *n > 0)
|
||||
.map(|(n, label)| format!("{n} {label}"))
|
||||
.collect();
|
||||
|
||||
if parts.is_empty() { None } else { Some(parts.join(", ")) }
|
||||
}
|
||||
|
||||
pub fn is_effectively_muted(&self, bank: usize, pattern: usize) -> bool {
|
||||
if self.muted.contains(&(bank, pattern)) {
|
||||
return true;
|
||||
|
||||
@@ -86,6 +86,7 @@ pub struct UiState {
|
||||
pub demo_index: usize,
|
||||
pub nav_indicator_until: Option<Instant>,
|
||||
pub nav_fx: RefCell<Option<Effect>>,
|
||||
pub pulse_phase: f32,
|
||||
pub last_click: Option<(Instant, u16, u16)>,
|
||||
}
|
||||
|
||||
@@ -142,6 +143,7 @@ impl Default for UiState {
|
||||
demo_index: 0,
|
||||
nav_indicator_until: None,
|
||||
nav_fx: RefCell::new(None),
|
||||
pulse_phase: 0.0,
|
||||
last_click: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ pub fn bindings_for(page: Page, plugin_mode: bool) -> Vec<(&'static str, &'stati
|
||||
bindings.push(("Ctrl+R", "Run", "Run step script immediately"));
|
||||
bindings.push((":", "Jump", "Jump to step number"));
|
||||
bindings.push(("e", "Euclidean", "Distribute linked steps using Euclidean rhythm"));
|
||||
bindings.push(("m", "Mute", "Stage mute for current pattern"));
|
||||
bindings.push(("x", "Solo", "Stage solo for current pattern"));
|
||||
bindings.push(("m", "Mute", "Arm mute for current pattern"));
|
||||
bindings.push(("x", "Solo", "Arm solo for current pattern"));
|
||||
bindings.push(("M", "Clear mutes", "Clear all mutes"));
|
||||
bindings.push(("X", "Clear solos", "Clear all solos"));
|
||||
bindings.push(("d", "Eval prelude", "Re-evaluate prelude without editing"));
|
||||
@@ -65,14 +65,14 @@ pub fn bindings_for(page: Page, plugin_mode: bool) -> Vec<(&'static str, &'stati
|
||||
if !plugin_mode {
|
||||
bindings.push(("Space", "Play", "Toggle pattern playback"));
|
||||
}
|
||||
bindings.push(("Esc", "Back", "Clear staged or go back"));
|
||||
bindings.push(("c", "Commit", "Commit staged changes"));
|
||||
bindings.push(("p", "Stage play", "Stage pattern play toggle"));
|
||||
bindings.push(("Esc", "Back", "Clear armed or go back"));
|
||||
bindings.push(("c", "Launch", "Launch armed changes"));
|
||||
bindings.push(("p", "Arm play", "Arm pattern play toggle"));
|
||||
bindings.push(("r", "Rename", "Rename bank/pattern"));
|
||||
bindings.push(("d", "Describe", "Add description to pattern"));
|
||||
bindings.push(("e", "Properties", "Edit pattern properties"));
|
||||
bindings.push(("m", "Mute", "Stage mute for pattern"));
|
||||
bindings.push(("x", "Solo", "Stage solo for pattern"));
|
||||
bindings.push(("m", "Mute", "Arm mute for pattern"));
|
||||
bindings.push(("x", "Solo", "Arm solo for pattern"));
|
||||
bindings.push(("M", "Clear mutes", "Clear all mutes"));
|
||||
bindings.push(("X", "Clear solos", "Clear all solos"));
|
||||
bindings.push(("g", "Share", "Export bank or pattern to clipboard"));
|
||||
|
||||
@@ -13,6 +13,20 @@ use crate::widgets::{render_scroll_indicators, IndicatorAlign};
|
||||
|
||||
const MIN_ROW_HEIGHT: u16 = 1;
|
||||
|
||||
fn pulse_value(phase: f32) -> f32 {
|
||||
phase.sin() * 0.5 + 0.5
|
||||
}
|
||||
|
||||
fn pulse_color(from: Color, to: Color, t: f32) -> Color {
|
||||
match (from, to) {
|
||||
(Color::Rgb(r1, g1, b1), Color::Rgb(r2, g2, b2)) => {
|
||||
let l = |a: u8, b: u8| (a as f32 + (b as f32 - a as f32) * t) as u8;
|
||||
Color::Rgb(l(r1, r2), l(g1, g2), l(b1, b2))
|
||||
}
|
||||
_ => from,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces the background color of spans beyond `filled_cols` with `unfilled_bg`.
|
||||
fn apply_progress_bg(spans: Vec<Span<'_>>, filled_cols: usize, unfilled_bg: Color) -> Vec<Span<'_>> {
|
||||
let mut result = Vec::with_capacity(spans.len() + 1);
|
||||
@@ -54,7 +68,32 @@ pub fn render(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area:
|
||||
Layout::horizontal([Constraint::Fill(1), Constraint::Length(22)]).areas(bottom_area);
|
||||
|
||||
render_banks(frame, app, snapshot, banks_area);
|
||||
render_patterns(frame, app, snapshot, patterns_area);
|
||||
|
||||
let armed_summary = app.playback.armed_summary();
|
||||
let (patterns_main, launch_bar_area) = if armed_summary.is_some() {
|
||||
let [main, bar] =
|
||||
Layout::vertical([Constraint::Fill(1), Constraint::Length(1)]).areas(patterns_area);
|
||||
(main, Some(bar))
|
||||
} else {
|
||||
(patterns_area, None)
|
||||
};
|
||||
|
||||
render_patterns(frame, app, snapshot, patterns_main);
|
||||
|
||||
if let (Some(bar_area), Some(summary)) = (launch_bar_area, armed_summary) {
|
||||
let pulse = pulse_value(app.ui.pulse_phase);
|
||||
let pulsed_fg = pulse_color(theme.list.staged_play_fg, theme.list.staged_play_bg, pulse * 0.6);
|
||||
let text = format!("\u{25b6} {summary} \u{2014} c to launch");
|
||||
let bar = Paragraph::new(text)
|
||||
.alignment(Alignment::Center)
|
||||
.style(
|
||||
Style::new()
|
||||
.fg(pulsed_fg)
|
||||
.bg(theme.list.staged_play_bg)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
frame.render_widget(bar, bar_area);
|
||||
}
|
||||
|
||||
let bank = app.patterns_nav.bank_cursor;
|
||||
let pattern_idx = app.patterns_nav.pattern_cursor;
|
||||
@@ -82,6 +121,7 @@ pub fn render(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area:
|
||||
|
||||
fn render_banks(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area: Rect) {
|
||||
let theme = theme::get();
|
||||
let pulse = pulse_value(app.ui.pulse_phase);
|
||||
let is_focused = matches!(app.patterns_nav.column, PatternsColumn::Banks);
|
||||
|
||||
let border_color = if is_focused { theme.ui.header } else { theme.ui.border };
|
||||
@@ -215,6 +255,12 @@ fn render_banks(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area
|
||||
} else {
|
||||
style
|
||||
};
|
||||
let style = if (is_staged || has_staged_mute_solo) && !is_cursor && !is_in_range {
|
||||
let pulsed = pulse_color(fg, bg, pulse * 0.6);
|
||||
style.fg(pulsed)
|
||||
} else {
|
||||
style
|
||||
};
|
||||
|
||||
let bg_block = Block::default().style(Style::new().bg(bg));
|
||||
frame.render_widget(bg_block, row_area);
|
||||
@@ -247,6 +293,7 @@ fn render_banks(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area
|
||||
|
||||
fn render_patterns(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area: Rect) {
|
||||
use crate::model::PatternSpeed;
|
||||
let pulse = pulse_value(app.ui.pulse_phase);
|
||||
|
||||
let theme = theme::get();
|
||||
let is_focused = matches!(app.patterns_nav.column, PatternsColumn::Patterns);
|
||||
@@ -454,6 +501,14 @@ fn render_patterns(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, a
|
||||
};
|
||||
let dim_style = base_style.remove_modifier(Modifier::BOLD);
|
||||
|
||||
let is_armed = is_staged_play || is_staged_stop || has_staged_mute || has_staged_solo || has_staged_props;
|
||||
let (name_style, dim_style) = if is_armed && !is_cursor && !is_in_range {
|
||||
let pulsed = pulse_color(fg, bg, pulse * 0.6);
|
||||
(name_style.fg(pulsed), dim_style.fg(pulsed))
|
||||
} else {
|
||||
(name_style, dim_style)
|
||||
};
|
||||
|
||||
let mut spans = vec![Span::styled(format!("{}{:02}", prefix, idx + 1), name_style)];
|
||||
if !name.is_empty() {
|
||||
spans.push(Span::styled(format!(" {name}"), name_style));
|
||||
|
||||
@@ -165,19 +165,11 @@ pub fn render(
|
||||
}
|
||||
|
||||
let (page_area, panel_area) = if app.panel.visible && app.panel.side.is_some() {
|
||||
if body_area.width >= 120 {
|
||||
let panel_width = body_area.width * 35 / 100;
|
||||
let [main, side] =
|
||||
Layout::horizontal([Constraint::Fill(1), Constraint::Length(panel_width)])
|
||||
.areas(body_area);
|
||||
(main, Some(side))
|
||||
} else {
|
||||
let panel_height = body_area.height * 40 / 100;
|
||||
let [main, side] =
|
||||
Layout::vertical([Constraint::Fill(1), Constraint::Length(panel_height)])
|
||||
.areas(body_area);
|
||||
(main, Some(side))
|
||||
}
|
||||
} else {
|
||||
(body_area, None)
|
||||
};
|
||||
@@ -560,7 +552,7 @@ fn render_footer(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, are
|
||||
Page::Patterns => vec![
|
||||
("Enter", "Select"),
|
||||
("Space", "Play"),
|
||||
("c", "Commit"),
|
||||
("c", "Launch"),
|
||||
("r", "Rename"),
|
||||
("?", "Keys"),
|
||||
],
|
||||
|
||||
@@ -66,3 +66,6 @@ mod case_statement;
|
||||
|
||||
#[path = "forth/harmony.rs"]
|
||||
mod harmony;
|
||||
|
||||
#[path = "forth/map.rs"]
|
||||
mod map;
|
||||
|
||||
55
tests/forth/map.rs
Normal file
55
tests/forth/map.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use crate::harness::{expect_error, expect_int, expect_stack, run};
|
||||
use cagire::forth::Value;
|
||||
|
||||
#[test]
|
||||
fn map_add() {
|
||||
expect_stack(
|
||||
"1 2 3 4 5 ( 2 + ) map",
|
||||
&[
|
||||
Value::Int(3, None),
|
||||
Value::Int(4, None),
|
||||
Value::Int(5, None),
|
||||
Value::Int(6, None),
|
||||
Value::Int(7, None),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_multiply() {
|
||||
expect_stack(
|
||||
"1 2 3 ( 10 * ) map",
|
||||
&[
|
||||
Value::Int(10, None),
|
||||
Value::Int(20, None),
|
||||
Value::Int(30, None),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_single_element() {
|
||||
expect_int("42 ( 1 + ) map", 43);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_empty_stack() {
|
||||
run("( 1 + ) map");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_identity() {
|
||||
expect_stack(
|
||||
"1 2 3 ( ) map",
|
||||
&[
|
||||
Value::Int(1, None),
|
||||
Value::Int(2, None),
|
||||
Value::Int(3, None),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_missing_quotation() {
|
||||
expect_error("1 2 3 map", "expected quotation");
|
||||
}
|
||||
@@ -62,33 +62,33 @@ const DL = 'https://dlcagire.raphaelforment.fr';
|
||||
</tr>
|
||||
<tr>
|
||||
<td>macOS (ARM)</td>
|
||||
<td><a href={`${DL}/cagire-macos-aarch64`}>binary</a></td>
|
||||
<td><a href={`${DL}/Cagire-aarch64.dmg`}>.dmg</a></td>
|
||||
<td><a href={`${DL}/cagire-plugins-macos-aarch64.clap`}>CLAP</a> · <a href={`${DL}/cagire-plugins-macos-aarch64.vst3`}>VST3</a></td>
|
||||
<td><a href={`${DL}/cagire-macos-aarch64.zip`}>zip</a></td>
|
||||
<td><a href={`${DL}/cagire-macos-aarch64-desktop.zip`}>zip</a></td>
|
||||
<td><a href={`${DL}/cagire-macos-aarch64-clap.zip`}>CLAP</a> · <a href={`${DL}/cagire-macos-aarch64-vst3.zip`}>VST3</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>macOS (Intel)</td>
|
||||
<td><a href={`${DL}/cagire-macos-x86_64`}>binary</a></td>
|
||||
<td><a href={`${DL}/Cagire-x86_64.dmg`}>.dmg</a></td>
|
||||
<td><a href={`${DL}/cagire-plugins-macos-x86_64.clap`}>CLAP</a> · <a href={`${DL}/cagire-plugins-macos-x86_64.vst3`}>VST3</a></td>
|
||||
<td><a href={`${DL}/cagire-macos-x86_64.zip`}>zip</a></td>
|
||||
<td><a href={`${DL}/cagire-macos-x86_64-desktop.zip`}>zip</a></td>
|
||||
<td><a href={`${DL}/cagire-macos-x86_64-clap.zip`}>CLAP</a> · <a href={`${DL}/cagire-macos-x86_64-vst3.zip`}>VST3</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux (x86_64)</td>
|
||||
<td><a href={`${DL}/cagire-linux-x86_64.AppImage`}>AppImage</a></td>
|
||||
<td><a href={`${DL}/cagire-desktop-linux-x86_64.AppImage`}>AppImage</a></td>
|
||||
<td><a href={`${DL}/cagire-plugins-linux-x86_64.clap`}>CLAP</a> · <a href={`${DL}/cagire-plugins-linux-x86_64.vst3`}>VST3</a></td>
|
||||
<td><a href={`${DL}/cagire-linux-x86_64.zip`}>zip</a></td>
|
||||
<td><a href={`${DL}/cagire-linux-x86_64-desktop.zip`}>zip</a> · <a href={`${DL}/cagire-linux-x86_64-appimage.zip`}>AppImage</a></td>
|
||||
<td><a href={`${DL}/cagire-linux-x86_64-clap.zip`}>CLAP</a> · <a href={`${DL}/cagire-linux-x86_64-vst3.zip`}>VST3</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linux (ARM)</td>
|
||||
<td><a href={`${DL}/cagire-linux-aarch64.AppImage`}>AppImage</a></td>
|
||||
<td><a href={`${DL}/cagire-desktop-linux-aarch64.AppImage`}>AppImage</a></td>
|
||||
<td><a href={`${DL}/cagire-plugins-linux-aarch64.clap`}>CLAP</a> · <a href={`${DL}/cagire-plugins-linux-aarch64.vst3`}>VST3</a></td>
|
||||
<td><a href={`${DL}/cagire-linux-aarch64.zip`}>zip</a></td>
|
||||
<td><a href={`${DL}/cagire-linux-aarch64-desktop.zip`}>zip</a></td>
|
||||
<td><s>CLAP</s> · <s>VST3</s></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows (x86_64)</td>
|
||||
<td><a href={`${DL}/cagire-windows-x86_64.exe`}>.exe</a></td>
|
||||
<td><a href={`${DL}/cagire-desktop-windows-x86_64.exe`}>.exe</a> · <a href={`${DL}/cagire-windows-x86_64.msi`}>.msi</a></td>
|
||||
<td><a href={`${DL}/cagire-plugins-windows-x86_64.clap`}>CLAP</a> · <a href={`${DL}/cagire-plugins-windows-x86_64.vst3`}>VST3</a></td>
|
||||
<td><a href={`${DL}/cagire-windows-x86_64.zip`}>zip</a></td>
|
||||
<td><a href={`${DL}/cagire-desktop-windows-x86_64.zip`}>zip</a> · <s>.msi</s></td>
|
||||
<td><a href={`${DL}/plugins-windows-x86_64-clap.zip`}>CLAP</a> · <a href={`${DL}/plugins-windows-x86_64-vst3.zip`}>VST3</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p class="note">Source code and issue tracker on <a href="https://github.com/Bubobubobubobubo/cagire">GitHub</a>. You can also compile the software yourself from source!</p>
|
||||
|
||||
Reference in New Issue
Block a user