diff --git a/.cargo/config.toml b/.cargo/config.toml index 1263c61..e0222a5 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,6 @@ +# Uncomment to use local doux for development +paths = ["/Users/bubo/doux"] + [alias] xtask = "run --package xtask --release --" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5935ebc..26137b9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -266,6 +266,18 @@ jobs: -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}" @@ -303,6 +315,12 @@ jobs: 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: @@ -328,7 +346,9 @@ jobs: mkdir -p release for dir in artifacts/*/; do name=$(basename "$dir") - if [[ "$name" == "cagire-macos-universal-pkg" ]]; then + 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" diff --git a/assets/DMG-README.txt b/assets/DMG-README.txt new file mode 100644 index 0000000..bc94aac --- /dev/null +++ b/assets/DMG-README.txt @@ -0,0 +1,19 @@ +Cagire - A Forth-based music sequencer +Made by BuboBubo and his friends +====================================== + +Installation +------------ +Drag Cagire.app into the Applications folder. + +Unquarantine +------------ +Since this app is not signed with an Apple Developer certificate, +macOS will block it from running. To fix this, open Terminal and run: + + xattr -cr /Applications/Cagire.app + +Support +------- +If you enjoy Cagire, consider supporting development: +https://ko-fi.com/raphaelbubo diff --git a/docs/engine/samples.md b/docs/engine/samples.md index 6c583af..6cef145 100644 --- a/docs/engine/samples.md +++ b/docs/engine/samples.md @@ -45,6 +45,8 @@ snare sound 0.5 speed . ( play snare at half speed ) | `n` | 0+ | Sample index within a folder (wraps around) | | `begin` | 0-1 | Playback start position | | `end` | 0-1 | Playback end position | +| `slice` | 1+ | Divide sample into N equal slices | +| `pick` | 0+ | Select which slice to play (0-indexed, wraps) | | `speed` | any | Playback speed multiplier | | `freq` | Hz | Base frequency for pitch tracking | | `fit` | seconds | Stretch/compress sample to fit duration | @@ -62,6 +64,21 @@ kick sound 0.5 end . ( play first half ) If begin is greater than end, they swap automatically. +## Slice and Pick + +For evenly-spaced slicing, `slice` divides the sample into N equal parts and `pick` selects which one (0-indexed, wraps around). + +```forth +break sound 8 slice 3 pick . ( play the 4th eighth of the sample ) +break sound 16 slice step pick . ( scan through 16 slices by step ) +``` + +Combine with `fit` to time-stretch each slice to a target duration. `fit` accounts for the sliced range automatically. + +```forth +break sound 4 slice 2 pick 1 loop . ( quarter of the sample, fitted to 1 beat ) +``` + ## Speed and Pitch The `speed` parameter affects both tempo and pitch. A speed of 2 plays twice as fast and an octave higher. diff --git a/scripts/build-all.sh b/scripts/build-all.sh index 088e232..d6e8880 100755 --- a/scripts/build-all.sh +++ b/scripts/build-all.sh @@ -229,6 +229,14 @@ bundle_plugins_native() { cargo xtask bundle "$PLUGIN_NAME" --release $tf } +bundle_desktop_native() { + local platform="$1" + local tf + tf=$(target_flag "$platform") + # shellcheck disable=SC2086 + cargo bundle --release --features desktop --bin cagire-desktop $tf +} + bundle_plugins_cross() { local platform="$1" local rd @@ -300,6 +308,18 @@ copy_artifacts() { local dst="$OUT/cagire-desktop-${os}-${arch}${suffix}" cp "$src" "$dst" echo " cagire-desktop -> $dst" + + # macOS .app bundle + if [[ "$os" == "macos" ]]; then + local app_src="$rd/bundle/osx/Cagire.app" + if [[ -d "$app_src" ]]; then + local app_dst="$OUT/Cagire-${arch}.app" + rm -rf "$app_dst" + cp -R "$app_src" "$app_dst" + echo " Cagire.app -> $app_dst" + scripts/make-dmg.sh "$app_dst" "$OUT" + fi + fi fi # AppImage for Linux targets @@ -407,6 +427,10 @@ for platform in "${selected_platforms[@]}"; do if $build_desktop; then echo " -> cagire-desktop" build_binary "$platform" --features desktop --bin cagire-desktop + if ! is_cross_target "$platform"; then + echo " -> bundling cagire-desktop .app" + bundle_desktop_native "$platform" + fi fi if $build_plugins; then diff --git a/scripts/make-dmg.sh b/scripts/make-dmg.sh new file mode 100755 index 0000000..d568c48 --- /dev/null +++ b/scripts/make-dmg.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: scripts/make-dmg.sh +# Produces a .dmg from a macOS .app bundle using only hdiutil. + +if [[ $# -ne 2 ]]; then + echo "Usage: $0 " + exit 1 +fi + +APP_PATH="$1" +OUTDIR="$2" +REPO_ROOT="$(git rev-parse --show-toplevel)" + +if [[ ! -d "$APP_PATH" ]]; then + echo "ERROR: $APP_PATH is not a directory" + exit 1 +fi + +LIPO_OUTPUT=$(lipo -info "$APP_PATH/Contents/MacOS/cagire-desktop" 2>/dev/null) + +if [[ -z "$LIPO_OUTPUT" ]]; then + echo "ERROR: could not determine architecture from $APP_PATH" + exit 1 +fi + +if echo "$LIPO_OUTPUT" | grep -q "Architectures in the fat file"; then + ARCH="universal" +else + ARCH=$(echo "$LIPO_OUTPUT" | awk '{print $NF}') + case "$ARCH" in + arm64) ARCH="aarch64" ;; + esac +fi + +STAGING="$(mktemp -d)" +trap 'rm -rf "$STAGING"' EXIT + +cp -R "$APP_PATH" "$STAGING/Cagire.app" +ln -s /Applications "$STAGING/Applications" +cp "$REPO_ROOT/assets/DMG-README.txt" "$STAGING/README.txt" + +DMG_NAME="Cagire-${ARCH}.dmg" +mkdir -p "$OUTDIR" + +hdiutil create -volname "Cagire" \ + -srcfolder "$STAGING" \ + -ov -format UDZO \ + "$OUTDIR/$DMG_NAME" + +echo " DMG -> $OUTDIR/$DMG_NAME"