diff --git a/.github/scripts/init-submodules.sh b/.github/scripts/init-submodules.sh
new file mode 100755
index 0000000..0c3817f
--- /dev/null
+++ b/.github/scripts/init-submodules.sh
@@ -0,0 +1,243 @@
+#!/bin/bash
+# Initialize submodules for CI/CD builds
+# This script initializes only the submodules needed for building,
+# skipping examples and demos to speed up checkout and avoid path length issues on Windows.
+
+set -e
+
+echo "========================================"
+echo "Initializing Build Submodules"
+echo "========================================"
+echo ""
+
+# Configure git for long paths (Windows compatibility)
+git config --global core.longpaths true 2>/dev/null || true
+
+# Configure git to use HTTPS instead of SSH for GitHub (needed for CI without SSH keys)
+git config --global url."https://github.com/".insteadOf "git@github.com:" 2>/dev/null || true
+
+# Initialize top-level submodules
+echo "Initializing top-level submodules..."
+git submodule update --init --depth 1 m1-monitor
+git submodule update --init --depth 1 m1-panner
+git submodule update --init --depth 1 m1-player
+git submodule update --init --depth 1 m1-orientationmanager
+git submodule update --init --depth 1 m1-transcoder
+git submodule update --init --depth 1 services/m1-system-helper 2>/dev/null || true
+
+# Function to initialize nested submodules for a project
+init_project_submodules() {
+ local project=$1
+ echo ""
+ echo "Initializing $project submodules..."
+
+ cd "$project"
+
+ # Core dependencies
+ git submodule update --init --depth 1 JUCE 2>/dev/null || true
+ git submodule update --init --depth 1 Modules/juce_murka 2>/dev/null || true
+ git submodule update --init --depth 1 Modules/juce_libvlc 2>/dev/null || true
+ git submodule update --init --depth 1 Modules/m1-sdk 2>/dev/null || true
+ # m1_orientation_client needs recursive init for its nested submodules (m1-mathematics)
+ git submodule update --init --recursive --depth 1 Modules/m1_orientation_client 2>/dev/null || {
+ # Fallback: init without recursive, then manually init nested
+ git submodule update --init --depth 1 Modules/m1_orientation_client 2>/dev/null || true
+ }
+
+ # m1-sdk build dependencies (skip examples - they have deep paths)
+ if [ -d "Modules/m1-sdk" ]; then
+ cd Modules/m1-sdk
+ git submodule update --init --depth 1 libmach1spatial/deps/glm 2>/dev/null || true
+ git submodule update --init --depth 1 libmach1spatial/deps/nlohmann 2>/dev/null || true
+ git submodule update --init --depth 1 libmach1spatial/deps/pugixml 2>/dev/null || true
+ git submodule update --init --depth 1 libmach1spatial/deps/yaml 2>/dev/null || true
+ git submodule update --init --depth 1 libmach1spatial/deps/acutest 2>/dev/null || true
+ # SKIP: examples/* - These have deep paths and aren't needed for builds
+ cd ../..
+ fi
+
+ # juce_murka dependencies (Murka uses SSH URL that needs HTTPS conversion)
+ if [ -d "Modules/juce_murka" ]; then
+ cd Modules/juce_murka
+
+ # fontstash uses HTTPS, should work directly
+ git submodule update --init --depth 1 fontstash 2>/dev/null || true
+
+ # Murka uses SSH URL git@github.com:Kiberchaika/Murka.git - needs HTTPS conversion
+ git submodule init Murka 2>/dev/null || true
+ git submodule update --depth 1 Murka 2>/dev/null || {
+ echo " Murka shallow update failed, trying with URL conversion..."
+ rm -rf Murka 2>/dev/null || true
+ MURKA_URL=$(git config -f .gitmodules --get submodule.Murka.url 2>/dev/null || echo "git@github.com:Kiberchaika/Murka.git")
+ MURKA_URL_HTTPS=$(echo "$MURKA_URL" | sed 's|git@github.com:|https://github.com/|')
+ git clone --depth 1 "$MURKA_URL_HTTPS" Murka 2>/dev/null || true
+ }
+
+ # Verify
+ if [ -f "Murka/src/Murka.h" ]; then
+ echo " Murka initialized"
+ else
+ echo " WARNING: Murka.h not found"
+ fi
+ cd ../..
+ fi
+
+ # juce_libvlc dependencies (m1-player only)
+ if [ -d "Modules/juce_libvlc" ]; then
+ cd Modules/juce_libvlc
+ git submodule update --init --depth 1 vlc 2>/dev/null || true
+ cd ../..
+ fi
+
+ # m1_orientation_client dependencies (includes m1-mathematics)
+ if [ -d "Modules/m1_orientation_client" ]; then
+ cd Modules/m1_orientation_client
+ # Initialize all direct submodules first
+ git submodule update --init --depth 1 2>/dev/null || true
+
+ # Explicitly initialize m1-mathematics (REQUIRED for build)
+ echo " Initializing libs/m1-mathematics..."
+
+ # Configure git to use HTTPS instead of SSH for GitHub (needed for CI)
+ git config --global url."https://github.com/".insteadOf "git@github.com:" 2>/dev/null || true
+
+ git submodule init libs/m1-mathematics 2>/dev/null || true
+ git submodule update --depth 1 --force libs/m1-mathematics 2>/dev/null || {
+ echo " Shallow update failed, trying full clone..."
+ git submodule update --force libs/m1-mathematics 2>/dev/null || {
+ echo " Standard update failed, trying manual clone..."
+ # Last resort: manually clone the submodule
+ rm -rf libs/m1-mathematics 2>/dev/null || true
+ # Get the URL and convert SSH to HTTPS
+ MATH_URL=$(git config -f .gitmodules --get submodule.libs/m1-mathematics.url 2>/dev/null)
+ # Convert git@github.com:org/repo.git to https://github.com/org/repo.git
+ MATH_URL_HTTPS=$(echo "$MATH_URL" | sed 's|git@github.com:|https://github.com/|')
+ echo " Cloning from: $MATH_URL_HTTPS"
+ git clone --depth 1 "$MATH_URL_HTTPS" libs/m1-mathematics 2>/dev/null || {
+ # Try without .git suffix
+ MATH_URL_HTTPS="${MATH_URL_HTTPS%.git}"
+ git clone --depth 1 "$MATH_URL_HTTPS" libs/m1-mathematics 2>/dev/null || true
+ }
+ }
+ }
+
+ # Verify m1-mathematics was initialized
+ if [ -f "libs/m1-mathematics/CMakeLists.txt" ]; then
+ echo " m1-mathematics initialized successfully"
+ else
+ echo " ERROR: m1-mathematics CMakeLists.txt not found!"
+ echo " Contents of libs/m1-mathematics:"
+ ls -la libs/m1-mathematics/ 2>/dev/null || echo " (empty or not found)"
+ fi
+ cd ../..
+ fi
+
+ cd ..
+}
+
+# Initialize each project's submodules
+echo ""
+echo "--- Processing m1-monitor ---"
+init_project_submodules "m1-monitor"
+
+echo ""
+echo "--- Processing m1-panner ---"
+init_project_submodules "m1-panner"
+
+echo ""
+echo "--- Processing m1-player ---"
+init_project_submodules "m1-player"
+
+# m1-orientationmanager - needs juce_murka (with Murka submodule) and m1_orientation_client (with m1-mathematics)
+echo ""
+echo "Initializing m1-orientationmanager submodules..."
+cd m1-orientationmanager
+git submodule update --init --depth 1 2>/dev/null || true
+
+# juce_murka has nested submodules (Murka uses SSH URL that needs conversion)
+if [ -d "Modules/juce_murka" ]; then
+ echo " Initializing juce_murka submodules (Murka, fontstash)..."
+ cd Modules/juce_murka
+
+ # Initialize fontstash (uses HTTPS, should work)
+ git submodule update --init --depth 1 fontstash 2>/dev/null || true
+
+ # Initialize Murka (uses SSH URL git@github.com:Kiberchaika/Murka.git)
+ git submodule init Murka 2>/dev/null || true
+ git submodule update --depth 1 Murka 2>/dev/null || {
+ echo " Murka shallow update failed, trying with URL conversion..."
+ # Manual clone with HTTPS conversion
+ rm -rf Murka 2>/dev/null || true
+ mkdir -p Murka
+ MURKA_URL=$(git config -f .gitmodules --get submodule.Murka.url 2>/dev/null || echo "git@github.com:Kiberchaika/Murka.git")
+ MURKA_URL_HTTPS=$(echo "$MURKA_URL" | sed 's|git@github.com:|https://github.com/|')
+ echo " Cloning from: $MURKA_URL_HTTPS"
+ git clone --depth 1 "$MURKA_URL_HTTPS" Murka 2>/dev/null || {
+ echo " ERROR: Could not clone Murka"
+ }
+ }
+
+ # Verify Murka was initialized (check for Murka.h header)
+ if [ -f "Murka/src/Murka.h" ]; then
+ echo " Murka initialized successfully"
+ else
+ echo " WARNING: Murka.h not found - juce_murka may fail to build"
+ ls -la Murka/ 2>/dev/null || echo " (Murka directory empty or missing)"
+ fi
+ cd ../..
+fi
+
+# Init nested submodules for m1_orientation_client (contains m1-mathematics)
+if [ -d "Modules/m1_orientation_client" ]; then
+ cd Modules/m1_orientation_client
+ git submodule update --init --depth 1 2>/dev/null || true
+
+ echo " Initializing libs/m1-mathematics..."
+ git config --global url."https://github.com/".insteadOf "git@github.com:" 2>/dev/null || true
+
+ git submodule init libs/m1-mathematics 2>/dev/null || true
+ git submodule update --depth 1 --force libs/m1-mathematics 2>/dev/null || {
+ git submodule update --force libs/m1-mathematics 2>/dev/null || {
+ rm -rf libs/m1-mathematics 2>/dev/null || true
+ MATH_URL=$(git config -f .gitmodules --get submodule.libs/m1-mathematics.url 2>/dev/null)
+ MATH_URL_HTTPS=$(echo "$MATH_URL" | sed 's|git@github.com:|https://github.com/|')
+ git clone --depth 1 "$MATH_URL_HTTPS" libs/m1-mathematics 2>/dev/null || true
+ }
+ }
+
+ if [ -f "libs/m1-mathematics/CMakeLists.txt" ]; then
+ echo " m1-mathematics initialized in m1-orientationmanager"
+ else
+ echo " WARNING: m1-mathematics not found in m1-orientationmanager"
+ fi
+ cd ../..
+fi
+cd ..
+
+# m1-transcoder (electron app, skip juce_plugin deep submodules)
+echo ""
+echo "Initializing m1-transcoder submodules..."
+cd m1-transcoder
+# Only init top level, skip juce_plugin as it has the problematic deep paths
+git submodule update --init --depth 1 2>/dev/null || {
+ echo " Note: Some m1-transcoder submodules skipped (not needed for electron build)"
+}
+cd ..
+
+# services/m1-system-helper
+if [ -d "services/m1-system-helper" ]; then
+ echo ""
+ echo "Initializing m1-system-helper submodules..."
+ cd services/m1-system-helper
+ git submodule update --init --depth 1 2>/dev/null || true
+ cd ../..
+fi
+
+echo ""
+echo "========================================"
+echo "Submodules initialized successfully!"
+echo "========================================"
+echo ""
+echo "Note: Example submodules (Unity, Unreal, FMOD, etc.) were skipped"
+echo " to speed up builds and avoid path length issues on Windows."
+
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..70c89ed
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,1218 @@
+name: Build and Release
+
+# This workflow builds all components and uploads artifacts.
+# AAX signing requires a physical USB iLok dongle and must be done locally.
+#
+# Workflow:
+# 1. CI/CD builds everything, signs non-AAX plugins, uploads to S3
+# 2. Local machine downloads artifacts, signs AAX, creates installer
+#
+# Use `make package-from-ci` locally to complete the release.
+
+on:
+ push:
+ tags:
+ - 'v*'
+ - 'test-cd'
+ branches:
+ - main
+ - master
+ pull_request:
+ branches:
+ - main
+ - master
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version number (e.g., 2.0.1) - leave empty to use commit SHA'
+ required: false
+ type: string
+ build_macos_arm64:
+ description: 'Build macOS ARM64'
+ required: false
+ default: true
+ type: boolean
+ build_macos_x86:
+ description: 'Build macOS x86_64'
+ required: false
+ default: true
+ type: boolean
+ build_windows:
+ description: 'Build Windows'
+ required: false
+ default: true
+ type: boolean
+
+env:
+ # Version - from tag, input, or commit SHA
+ VERSION: ${{ github.event.inputs.version || github.ref_name || github.sha }}
+ # S3 bucket for build artifacts
+ ARTIFACTS_BUCKET: mach1-build-artifacts
+
+jobs:
+ # =============================================================================
+ # macOS ARM64 Build (Apple Silicon)
+ # =============================================================================
+ build-macos-arm64:
+ if: ${{ github.event.inputs.build_macos_arm64 != 'false' }}
+ runs-on: macos-15 # ARM64 runner
+ timeout-minutes: 180
+
+ env:
+ APPLE_TEAM_CODE: ${{ secrets.APPLE_TEAM_CODE }}
+ APPLE_CODESIGN_CODE: ${{ secrets.APPLE_CODESIGN_CODE }}
+ APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
+ APPLE_CODESIGN_INSTALLER_ID: ${{ secrets.APPLE_CODESIGN_INSTALLER_ID }}
+ APPLE_USERNAME: ${{ secrets.APPLE_USERNAME }}
+ ALTOOL_APPPASS: ${{ secrets.ALTOOL_APPPASS }}
+ PANNER_FREE_GUID: ${{ secrets.PANNER_FREE_GUID }}
+ MONITOR_FREE_GUID: ${{ secrets.MONITOR_FREE_GUID }}
+ # Aliases for electron-builder notarization (m1-transcoder/scripts/notarize.js)
+ APPLEID: ${{ secrets.APPLE_USERNAME }}
+ APPLEIDPASS: ${{ secrets.ALTOOL_APPPASS }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_CODE }}
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ submodules: false # Handle submodules manually for speed
+ fetch-depth: 0
+
+ # Initialize only build-required submodules (skip examples for faster builds)
+ - name: Initialize submodules
+ run: |
+ chmod +x .github/scripts/init-submodules.sh 2>/dev/null || true
+ .github/scripts/init-submodules.sh || {
+ # Fallback: recursive with depth
+ git submodule update --init --recursive --depth 1
+ }
+
+ - name: Setup Xcode
+ uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: latest-stable
+
+ # ===========================================
+ # Caching for faster builds
+ # ===========================================
+ # NOTE: Homebrew caching removed - symlinks don't cache properly
+ # VLC is cached in ~/.vlc-cache (outside build dir so `clean` doesn't delete it)
+
+ - name: Cache VLC build
+ uses: actions/cache@v4
+ id: vlc-cache
+ with:
+ path: ~/.vlc-cache
+ key: vlc-macos-${{ runner.arch }}-${{ hashFiles('m1-player/build_vlc.sh', 'm1-player/CMakeLists.txt') }}
+ restore-keys: |
+ vlc-macos-${{ runner.arch }}-
+
+ - name: Cache npm dependencies
+ uses: actions/cache@v4
+ with:
+ path: |
+ m1-transcoder/node_modules
+ ~/.npm
+ key: npm-macos-${{ runner.arch }}-${{ hashFiles('m1-transcoder/package-lock.json') }}
+ restore-keys: |
+ npm-macos-${{ runner.arch }}-
+
+ - name: Cache Electron
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/Library/Caches/electron
+ ~/Library/Caches/electron-builder
+ key: electron-macos-${{ runner.arch }}-${{ hashFiles('m1-transcoder/package-lock.json') }}
+ restore-keys: |
+ electron-macos-${{ runner.arch }}-
+
+ - name: Cache Python venv
+ uses: actions/cache@v4
+ with:
+ path: ~/.transcoder-venv
+ key: python-venv-macos-${{ runner.arch }}-pyinstaller
+ restore-keys: |
+ python-venv-macos-${{ runner.arch }}-
+
+ # ===========================================
+ # Install dependencies
+ # ===========================================
+
+ - name: Install Homebrew dependencies
+ run: |
+ brew update
+ brew install cmake ninja pkg-config autoconf automake libtool
+ brew install ffmpeg@6 && brew link ffmpeg@6 --force
+ brew install libass flac mpg123 libvpx x264 x265 dav1d aom
+ brew install opus libvorbis theora speex libogg libpng jpeg-turbo
+ brew install libssh2 srt libbluray aribb24
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '18'
+
+ - name: Setup Python environment for m1-transcoder
+ run: |
+ # Create/reuse venv for Python packages
+ if [ ! -d "$HOME/.transcoder-venv" ]; then
+ python3 -m venv $HOME/.transcoder-venv
+ fi
+ source $HOME/.transcoder-venv/bin/activate
+ pip install --upgrade pip
+ pip install pyinstaller
+ echo "$HOME/.transcoder-venv/bin" >> $GITHUB_PATH
+ echo "Python venv ready with pyinstaller"
+
+ - name: Import Apple Developer Certificate
+ env:
+ APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
+ APPLE_CERTIFICATE_P12_PWD: ${{ secrets.APPLE_CERTIFICATE_P12_PWD }}
+ MACOS_CI_KEYCHAIN_PWD: ${{ secrets.MACOS_CI_KEYCHAIN_PWD }}
+ run: |
+ # Create a temporary keychain
+ KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
+ security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
+ security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
+ security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
+
+ # Import certificate
+ echo "$APPLE_CERTIFICATE_P12" | base64 --decode > $RUNNER_TEMP/certificate.p12
+ security import $RUNNER_TEMP/certificate.p12 -P "$APPLE_CERTIFICATE_P12_PWD" \
+ -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+ security list-keychain -d user -s $KEYCHAIN_PATH
+
+ # Allow codesign to access the keychain
+ security set-key-partition-list -S apple-tool:,apple:,codesign: \
+ -s -k "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
+
+ echo "Certificate imported successfully"
+
+ - name: Setup notarization credentials
+ run: |
+ xcrun notarytool store-credentials 'notarize-app' \
+ --apple-id "$APPLE_USERNAME" \
+ --team-id "$APPLE_TEAM_CODE" \
+ --password "$ALTOOL_APPPASS"
+
+ - name: Setup SDKs (VST2)
+ env:
+ VST2_SDK_URL: ${{ secrets.VST2_SDK_URL }}
+ run: |
+ mkdir -p SDKs
+
+ # Download VST2 SDK if URL provided
+ if [ -n "$VST2_SDK_URL" ]; then
+ echo "Downloading VST2 SDK..."
+ curl -L "$VST2_SDK_URL" -o SDKs/vst2_sdk.zip
+ unzip -q SDKs/vst2_sdk.zip -d SDKs/
+
+ # Handle different archive structures
+ if [ -d "SDKs/VST2_SDK" ]; then
+ echo "VST2 SDK extracted to SDKs/VST2_SDK"
+ elif [ -d "SDKs/vstsdk2.4" ]; then
+ mv SDKs/vstsdk2.4 SDKs/VST2_SDK
+ echo "VST2 SDK extracted and renamed"
+ elif [ -d "SDKs/pluginterfaces" ]; then
+ mkdir -p SDKs/VST2_SDK
+ mv SDKs/pluginterfaces SDKs/VST2_SDK/
+ echo "VST2 SDK headers extracted"
+ fi
+
+ echo "BUILD_VST2=ON" >> $GITHUB_ENV
+ echo "VST2 SDK ready"
+ else
+ echo "VST2_SDK_URL not provided - VST2 builds will be skipped"
+ echo "BUILD_VST2=OFF" >> $GITHUB_ENV
+ fi
+
+ - name: Setup Makefile.variables
+ run: |
+ # Set VST2 path only if SDK exists
+ VST2_PATH_VALUE=""
+ if [ "$BUILD_VST2" = "ON" ] && [ -d "${{ github.workspace }}/SDKs/VST2_SDK" ]; then
+ VST2_PATH_VALUE="${{ github.workspace }}/SDKs/VST2_SDK"
+ fi
+
+ cat > Makefile.variables << EOF
+ M1SDK_PATH=
+ VST2_PATH=$VST2_PATH_VALUE
+ APPLE_TEAM_CODE=${{ secrets.APPLE_TEAM_CODE }}
+ APPLE_CODESIGN_ID=${{ secrets.APPLE_CODESIGN_ID }}
+ APPLE_CODESIGN_CODE=${{ secrets.APPLE_CODESIGN_CODE }}
+ APPLE_CODESIGN_INSTALLER_ID=${{ secrets.APPLE_CODESIGN_INSTALLER_ID }}
+ PANNER_FREE_GUID=${{ secrets.PANNER_FREE_GUID }}
+ MONITOR_FREE_GUID=${{ secrets.MONITOR_FREE_GUID }}
+ M1_GLOBAL_GUID=${{ secrets.M1_GLOBAL_GUID }}
+ APPLE_USERNAME=${{ secrets.APPLE_USERNAME }}
+ ALTOOL_APPPASS=${{ secrets.ALTOOL_APPPASS }}
+ EOF
+ echo "Makefile.variables created (VST2: $BUILD_VST2)"
+
+ - name: Update version
+ run: |
+ VERSION_RAW="${VERSION#v}"
+
+ # Check if version is valid numeric format (X.Y.Z or X.Y)
+ # CMake requires numeric-only versions
+ if [[ "$VERSION_RAW" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
+ VERSION_CLEAN="$VERSION_RAW"
+ echo "Release build, using version: $VERSION_CLEAN"
+ else
+ # For non-release builds (test-cd, feature branches, SHAs), use 0.0
+ # After generate_version.sh appends date, this becomes 0.0.YYYYMMDD (valid semver)
+ # Using 0.0.0 would result in 0.0.0.YYYYMMDD (4 parts - invalid for npm/electron-builder)
+ VERSION_CLEAN="0.0"
+ echo "CI_BUILD_TAG=$VERSION_RAW" >> $GITHUB_ENV
+ echo "Non-release build ($VERSION_RAW), using CMake version: $VERSION_CLEAN"
+ fi
+
+ echo "$VERSION_CLEAN" > VERSION
+
+ # Update component versions (may add date suffixes)
+ make update-versions || echo "Version update completed with warnings"
+ echo "Final VERSION file:"
+ cat VERSION
+
+ - name: Configure and build all components
+ run: |
+ echo "Configuring all components..."
+
+ # Configure with or without VST2 based on SDK availability
+ if [ "$BUILD_VST2" = "ON" ]; then
+ echo "Building with VST2 support"
+ make configure
+ else
+ echo "Building without VST2 (SDK not available)"
+ # Configure each project manually without VST2
+ cmake m1-monitor -Bm1-monitor/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DBUILD_AU=ON -DBUILD_VST=OFF -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
+ cmake m1-panner -Bm1-panner/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DBUILD_AU=ON -DBUILD_VST=OFF -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
+ cmake m1-player -Bm1-player/build -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ cmake m1-orientationmanager -Bm1-orientationmanager/build
+ cmake services/m1-system-helper -Bservices/m1-system-helper/build
+ fi
+
+ # Restore VLC from cache if available (cache is stored outside build dir)
+ if [ -d "$HOME/.vlc-cache/vlc-install" ]; then
+ echo "Restoring VLC from cache (saves 20-40 min)..."
+ mkdir -p m1-player/build
+ cp -r "$HOME/.vlc-cache/vlc-install" m1-player/build/
+ cp -r "$HOME/.vlc-cache/vlc-source" m1-player/build/ 2>/dev/null || true
+ fi
+
+ # Build VLC if needed
+ if [ -f "m1-player/build/vlc-install/lib/libvlc.dylib" ]; then
+ echo "VLC available, skipping build"
+ else
+ echo "Building VLC from source (this takes 20-40 minutes)..."
+ cd m1-player && ./build_vlc.sh build && cd ..
+ # Save to cache for next run
+ mkdir -p "$HOME/.vlc-cache"
+ cp -r m1-player/build/vlc-install "$HOME/.vlc-cache/"
+ cp -r m1-player/build/vlc-source "$HOME/.vlc-cache/" 2>/dev/null || true
+ fi
+
+ # Always reconfigure m1-player to pick up VLC
+ cmake m1-player -Bm1-player/build -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF
+
+ echo "Building all components..."
+ make build
+
+ - name: Code sign non-AAX binaries
+ run: |
+ echo "Code signing VST3, AU, and Apps..."
+ # Sign everything EXCEPT AAX (requires USB iLok)
+ if [ "$BUILD_VST2" = "ON" ]; then
+ make codesign-vst || true
+ fi
+ make codesign-vst3
+ make codesign-au
+ make codesign-apps
+
+ - name: Notarize applications
+ run: |
+ echo "Notarizing applications..."
+ make notarize
+
+ - name: Package build artifacts
+ run: |
+ echo "Packaging build artifacts..."
+ mkdir -p artifacts/macos-arm64
+
+ # Copy plugin builds
+ cp -r m1-monitor/build/M1-Monitor_artefacts/ artifacts/macos-arm64/M1-Monitor/
+ cp -r m1-panner/build/M1-Panner_artefacts/ artifacts/macos-arm64/M1-Panner/
+ cp -r m1-player/build/M1-Player_artefacts/ artifacts/macos-arm64/M1-Player/
+ cp -r m1-orientationmanager/build/m1-orientationmanager_artefacts/ artifacts/macos-arm64/m1-orientationmanager/
+ cp -r services/m1-system-helper/build/m1-system-helper_artefacts/ artifacts/macos-arm64/m1-system-helper/
+
+ # Create archive
+ cd artifacts && tar -czvf macos-arm64-builds.tar.gz macos-arm64/
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: macos-arm64-builds
+ path: artifacts/macos-arm64-builds.tar.gz
+ retention-days: 30
+
+ - name: Upload to S3 artifacts bucket
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ run: |
+ VERSION_RAW="${VERSION#v}"
+ COMMIT_SHA="${{ github.sha }}"
+ SHORT_SHA="${COMMIT_SHA:0:8}"
+
+ # Use original tag/branch name for S3 path (not the CMake-safe version)
+ S3_VERSION="$VERSION_RAW"
+
+ echo "Uploading to S3..."
+ aws s3 cp artifacts/macos-arm64-builds.tar.gz \
+ "s3://$ARTIFACTS_BUCKET/builds/$S3_VERSION/macos-arm64-builds.tar.gz" \
+ --region us-east-1
+
+ # Also upload with commit SHA for exact version matching
+ aws s3 cp artifacts/macos-arm64-builds.tar.gz \
+ "s3://$ARTIFACTS_BUCKET/commits/$SHORT_SHA/macos-arm64-builds.tar.gz" \
+ --region us-east-1
+
+ echo "Artifacts uploaded to:"
+ echo " s3://$ARTIFACTS_BUCKET/builds/$S3_VERSION/"
+ echo " s3://$ARTIFACTS_BUCKET/commits/$SHORT_SHA/"
+
+ # =============================================================================
+ # macOS x86_64 Build (Intel) - for m1-player only
+ # =============================================================================
+ build-macos-x86:
+ if: ${{ github.event.inputs.build_macos_x86 != 'false' }}
+ runs-on: macos-15-intel # Intel runner
+ timeout-minutes: 180
+
+ env:
+ APPLE_TEAM_CODE: ${{ secrets.APPLE_TEAM_CODE }}
+ APPLE_CODESIGN_CODE: ${{ secrets.APPLE_CODESIGN_CODE }}
+ APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
+ APPLE_CODESIGN_INSTALLER_ID: ${{ secrets.APPLE_CODESIGN_INSTALLER_ID }}
+ APPLE_USERNAME: ${{ secrets.APPLE_USERNAME }}
+ ALTOOL_APPPASS: ${{ secrets.ALTOOL_APPPASS }}
+ PANNER_FREE_GUID: ${{ secrets.PANNER_FREE_GUID }}
+ MONITOR_FREE_GUID: ${{ secrets.MONITOR_FREE_GUID }}
+ # Aliases for electron-builder notarization (m1-transcoder/scripts/notarize.js)
+ APPLEID: ${{ secrets.APPLE_USERNAME }}
+ APPLEIDPASS: ${{ secrets.ALTOOL_APPPASS }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_CODE }}
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ submodules: false # Handle submodules manually for speed
+ fetch-depth: 0
+
+ # Initialize only build-required submodules (skip examples for faster builds)
+ - name: Initialize submodules
+ run: |
+ chmod +x .github/scripts/init-submodules.sh 2>/dev/null || true
+ .github/scripts/init-submodules.sh || {
+ # Fallback: recursive with depth
+ git submodule update --init --recursive --depth 1
+ }
+
+ - name: Setup Xcode
+ uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: latest-stable
+
+ # ===========================================
+ # Caching for faster builds
+ # ===========================================
+ # NOTE: Homebrew caching removed - symlinks don't cache properly
+ # VLC is cached in ~/.vlc-cache (outside build dir so `clean` doesn't delete it)
+
+ - name: Cache VLC build
+ uses: actions/cache@v4
+ id: vlc-cache-x86
+ with:
+ path: ~/.vlc-cache
+ key: vlc-macos-${{ runner.arch }}-${{ hashFiles('m1-player/build_vlc.sh', 'm1-player/CMakeLists.txt') }}
+ restore-keys: |
+ vlc-macos-${{ runner.arch }}-
+
+ - name: Cache npm dependencies
+ uses: actions/cache@v4
+ with:
+ path: |
+ m1-transcoder/node_modules
+ ~/.npm
+ key: npm-macos-${{ runner.arch }}-${{ hashFiles('m1-transcoder/package-lock.json') }}
+ restore-keys: |
+ npm-macos-${{ runner.arch }}-
+
+ - name: Cache Electron
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/Library/Caches/electron
+ ~/Library/Caches/electron-builder
+ key: electron-macos-${{ runner.arch }}-${{ hashFiles('m1-transcoder/package-lock.json') }}
+ restore-keys: |
+ electron-macos-${{ runner.arch }}-
+
+ - name: Cache Python venv
+ uses: actions/cache@v4
+ with:
+ path: ~/.transcoder-venv
+ key: python-venv-macos-${{ runner.arch }}-pyinstaller
+ restore-keys: |
+ python-venv-macos-${{ runner.arch }}-
+
+ # ===========================================
+ # Install dependencies
+ # ===========================================
+
+ - name: Install Homebrew dependencies
+ run: |
+ brew update
+ brew install cmake ninja pkg-config autoconf automake libtool
+ brew install ffmpeg@6 && brew link ffmpeg@6 --force
+ brew install libass flac mpg123 libvpx x264 x265 dav1d aom
+ brew install opus libvorbis theora speex libogg libpng jpeg-turbo
+ brew install libssh2 srt libbluray aribb24
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '18'
+
+ - name: Setup Python environment for m1-transcoder
+ run: |
+ # Create/reuse venv for Python packages
+ if [ ! -d "$HOME/.transcoder-venv" ]; then
+ python3 -m venv $HOME/.transcoder-venv
+ fi
+ source $HOME/.transcoder-venv/bin/activate
+ pip install --upgrade pip
+ pip install pyinstaller
+ echo "$HOME/.transcoder-venv/bin" >> $GITHUB_PATH
+ echo "Python venv ready with pyinstaller"
+
+ - name: Import Apple Developer Certificate
+ env:
+ APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
+ APPLE_CERTIFICATE_P12_PWD: ${{ secrets.APPLE_CERTIFICATE_P12_PWD }}
+ MACOS_CI_KEYCHAIN_PWD: ${{ secrets.MACOS_CI_KEYCHAIN_PWD }}
+ run: |
+ KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
+ security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
+ security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
+ security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
+
+ echo "$APPLE_CERTIFICATE_P12" | base64 --decode > $RUNNER_TEMP/certificate.p12
+ security import $RUNNER_TEMP/certificate.p12 -P "$APPLE_CERTIFICATE_P12_PWD" \
+ -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+ security list-keychain -d user -s $KEYCHAIN_PATH
+ security set-key-partition-list -S apple-tool:,apple:,codesign: \
+ -s -k "$MACOS_CI_KEYCHAIN_PWD" $KEYCHAIN_PATH
+
+ - name: Setup notarization credentials
+ run: |
+ xcrun notarytool store-credentials 'notarize-app' \
+ --apple-id "$APPLE_USERNAME" \
+ --team-id "$APPLE_TEAM_CODE" \
+ --password "$ALTOOL_APPPASS"
+
+ - name: Setup SDKs (VST2)
+ env:
+ VST2_SDK_URL: ${{ secrets.VST2_SDK_URL }}
+ run: |
+ mkdir -p SDKs
+
+ if [ -n "$VST2_SDK_URL" ]; then
+ echo "Downloading VST2 SDK..."
+ curl -L "$VST2_SDK_URL" -o SDKs/vst2_sdk.zip
+ unzip -q SDKs/vst2_sdk.zip -d SDKs/
+
+ # Handle different archive structures
+ if [ -d "SDKs/VST2_SDK" ]; then
+ echo "VST2 SDK extracted"
+ elif [ -d "SDKs/vstsdk2.4" ]; then
+ mv SDKs/vstsdk2.4 SDKs/VST2_SDK
+ elif [ -d "SDKs/pluginterfaces" ]; then
+ mkdir -p SDKs/VST2_SDK
+ mv SDKs/pluginterfaces SDKs/VST2_SDK/
+ fi
+
+ echo "BUILD_VST2=ON" >> $GITHUB_ENV
+ else
+ echo "VST2_SDK_URL not provided - VST2 builds will be skipped"
+ echo "BUILD_VST2=OFF" >> $GITHUB_ENV
+ fi
+
+ - name: Setup Makefile.variables
+ run: |
+ VST2_PATH_VALUE=""
+ if [ "$BUILD_VST2" = "ON" ] && [ -d "${{ github.workspace }}/SDKs/VST2_SDK" ]; then
+ VST2_PATH_VALUE="${{ github.workspace }}/SDKs/VST2_SDK"
+ fi
+
+ cat > Makefile.variables << EOF
+ M1SDK_PATH=
+ VST2_PATH=$VST2_PATH_VALUE
+ APPLE_TEAM_CODE=${{ secrets.APPLE_TEAM_CODE }}
+ APPLE_CODESIGN_ID=${{ secrets.APPLE_CODESIGN_ID }}
+ APPLE_CODESIGN_CODE=${{ secrets.APPLE_CODESIGN_CODE }}
+ APPLE_CODESIGN_INSTALLER_ID=${{ secrets.APPLE_CODESIGN_INSTALLER_ID }}
+ PANNER_FREE_GUID=${{ secrets.PANNER_FREE_GUID }}
+ MONITOR_FREE_GUID=${{ secrets.MONITOR_FREE_GUID }}
+ M1_GLOBAL_GUID=${{ secrets.M1_GLOBAL_GUID }}
+ APPLE_USERNAME=${{ secrets.APPLE_USERNAME }}
+ ALTOOL_APPPASS=${{ secrets.ALTOOL_APPPASS }}
+ EOF
+
+ - name: Update version
+ run: |
+ VERSION_RAW="${VERSION#v}"
+
+ # Check if version is valid numeric format (X.Y.Z or X.Y)
+ if [[ "$VERSION_RAW" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
+ VERSION_CLEAN="$VERSION_RAW"
+ echo "Release build, using version: $VERSION_CLEAN"
+ else
+ # Use 0.0 so after date append we get 0.0.YYYYMMDD (valid 3-part semver)
+ VERSION_CLEAN="0.0"
+ echo "CI_BUILD_TAG=$VERSION_RAW" >> $GITHUB_ENV
+ echo "Non-release build ($VERSION_RAW), using CMake version: $VERSION_CLEAN"
+ fi
+
+ echo "$VERSION_CLEAN" > VERSION
+ make update-versions || echo "Version update completed with warnings"
+ cat VERSION
+
+ - name: Configure and build all components
+ run: |
+ # Configure with or without VST2 based on SDK availability
+ if [ "$BUILD_VST2" = "ON" ]; then
+ echo "Building with VST2 support"
+ make configure
+ else
+ echo "Building without VST2 (SDK not available)"
+ cmake m1-monitor -Bm1-monitor/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DBUILD_AU=ON -DBUILD_VST=OFF -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
+ cmake m1-panner -Bm1-panner/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DBUILD_AU=ON -DBUILD_VST=OFF -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
+ cmake m1-player -Bm1-player/build -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ cmake m1-orientationmanager -Bm1-orientationmanager/build
+ cmake services/m1-system-helper -Bservices/m1-system-helper/build
+ fi
+
+ # Restore VLC from cache if available (cache is stored outside build dir)
+ if [ -d "$HOME/.vlc-cache/vlc-install" ]; then
+ echo "Restoring VLC from cache (saves 20-40 min)..."
+ mkdir -p m1-player/build
+ cp -r "$HOME/.vlc-cache/vlc-install" m1-player/build/
+ cp -r "$HOME/.vlc-cache/vlc-source" m1-player/build/ 2>/dev/null || true
+ fi
+
+ # Build VLC if needed
+ if [ -f "m1-player/build/vlc-install/lib/libvlc.dylib" ]; then
+ echo "VLC available, skipping build"
+ else
+ echo "Building VLC from source (this takes 20-40 minutes)..."
+ cd m1-player && ./build_vlc.sh build && cd ..
+ # Save to cache for next run
+ mkdir -p "$HOME/.vlc-cache"
+ cp -r m1-player/build/vlc-install "$HOME/.vlc-cache/"
+ cp -r m1-player/build/vlc-source "$HOME/.vlc-cache/" 2>/dev/null || true
+ fi
+
+ # Always reconfigure m1-player to pick up VLC
+ cmake m1-player -Bm1-player/build -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF
+
+ make build
+
+ - name: Code sign non-AAX binaries
+ run: |
+ # Sign everything EXCEPT AAX (requires USB iLok)
+ if [ "$BUILD_VST2" = "ON" ]; then
+ make codesign-vst || true
+ fi
+ make codesign-vst3
+ make codesign-au
+ make codesign-apps
+
+ - name: Notarize applications
+ run: |
+ make notarize
+
+ - name: Package build artifacts
+ run: |
+ mkdir -p artifacts/macos-x86
+ cp -r m1-monitor/build/M1-Monitor_artefacts/ artifacts/macos-x86/M1-Monitor/
+ cp -r m1-panner/build/M1-Panner_artefacts/ artifacts/macos-x86/M1-Panner/
+ cp -r m1-player/build/M1-Player_artefacts/ artifacts/macos-x86/M1-Player/
+ cp -r m1-orientationmanager/build/m1-orientationmanager_artefacts/ artifacts/macos-x86/m1-orientationmanager/
+ cp -r services/m1-system-helper/build/m1-system-helper_artefacts/ artifacts/macos-x86/m1-system-helper/
+ cd artifacts && tar -czvf macos-x86-builds.tar.gz macos-x86/
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: macos-x86-builds
+ path: artifacts/macos-x86-builds.tar.gz
+ retention-days: 30
+
+ - name: Upload to S3 artifacts bucket
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ run: |
+ VERSION_RAW="${VERSION#v}"
+ COMMIT_SHA="${{ github.sha }}"
+ SHORT_SHA="${COMMIT_SHA:0:8}"
+
+ aws s3 cp artifacts/macos-x86-builds.tar.gz \
+ "s3://$ARTIFACTS_BUCKET/builds/$VERSION_RAW/macos-x86-builds.tar.gz" \
+ --region us-east-1
+
+ aws s3 cp artifacts/macos-x86-builds.tar.gz \
+ "s3://$ARTIFACTS_BUCKET/commits/$SHORT_SHA/macos-x86-builds.tar.gz" \
+ --region us-east-1
+
+ # =============================================================================
+ # Windows Build
+ # =============================================================================
+ build-windows:
+ if: ${{ github.event.inputs.build_windows != 'false' }}
+ runs-on: windows-latest
+ timeout-minutes: 180
+
+ env:
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SECRET_ID }}
+
+ steps:
+ # Enable long paths on Windows to handle deeply nested submodules
+ - name: Enable long paths
+ run: |
+ git config --system core.longpaths true
+ # Also set via registry for good measure
+ New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force | Out-Null
+ shell: pwsh
+
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ submodules: false # We'll handle submodules manually
+ fetch-depth: 0
+
+ # Initialize submodules with depth limit to avoid deep nesting issues
+ - name: Initialize submodules (with depth limit)
+ run: |
+ # Use the shared script (works on Windows via Git Bash)
+ bash .github/scripts/init-submodules.sh
+ shell: bash
+ continue-on-error: false
+
+ - name: Setup MSVC
+ uses: microsoft/setup-msbuild@v2
+
+ - name: Setup CMake
+ uses: lukka/get-cmake@latest
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '18'
+
+ # ===========================================
+ # Caching for faster builds
+ # ===========================================
+
+ - name: Cache npm dependencies
+ uses: actions/cache@v4
+ with:
+ path: |
+ m1-transcoder/node_modules
+ ~\AppData\Local\npm-cache
+ key: npm-windows-${{ hashFiles('m1-transcoder/package-lock.json') }}
+ restore-keys: |
+ npm-windows-
+
+ - name: Cache Electron
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~\AppData\Local\electron\Cache
+ ~\AppData\Local\electron-builder\Cache
+ key: electron-windows-${{ hashFiles('m1-transcoder/package-lock.json') }}
+ restore-keys: |
+ electron-windows-
+
+ - name: Cache Python venv
+ uses: actions/cache@v4
+ with:
+ path: ~\.transcoder-venv
+ key: python-venv-windows-pyinstaller
+ restore-keys: |
+ python-venv-windows-
+
+ # ===========================================
+ # Install dependencies
+ # ===========================================
+
+ - name: Setup Python environment for m1-transcoder
+ run: |
+ if (-not (Test-Path "$env:USERPROFILE\.transcoder-venv")) {
+ python -m venv $env:USERPROFILE\.transcoder-venv
+ }
+ & $env:USERPROFILE\.transcoder-venv\Scripts\Activate.ps1
+ pip install --upgrade pip
+ pip install pyinstaller
+ echo "$env:USERPROFILE\.transcoder-venv\Scripts" >> $env:GITHUB_PATH
+ echo "Python venv ready with pyinstaller"
+
+ - name: Install dependencies
+ run: |
+ choco install innosetup -y
+ choco install 7zip -y
+
+ - name: Setup Azure Trusted Signing
+ run: |
+ # Download Microsoft Trusted Signing Client (contains the Dlib for signtool)
+ # This is the same approach used locally via aax-signtool.bat
+
+ $packageName = "Microsoft.Trusted.Signing.Client"
+ $outputDir = "trusted-signing-client"
+
+ # Use nuget to download the package
+ nuget install $packageName -OutputDirectory $outputDir -Source https://api.nuget.org/v3/index.json
+
+ # Find the Dlib DLL
+ $dlibPath = Get-ChildItem -Path $outputDir -Recurse -Filter "Azure.CodeSigning.Dlib.dll" |
+ Where-Object { $_.FullName -like "*x64*" } |
+ Select-Object -First 1
+
+ if (-not $dlibPath) {
+ # Fallback: try any location
+ $dlibPath = Get-ChildItem -Path $outputDir -Recurse -Filter "Azure.CodeSigning.Dlib.dll" |
+ Select-Object -First 1
+ }
+
+ if ($dlibPath) {
+ echo "Found Azure.CodeSigning.Dlib.dll at: $($dlibPath.FullName)"
+ echo "ACS_DLIB=$($dlibPath.FullName)" >> $env:GITHUB_ENV
+ } else {
+ echo "ERROR: Could not find Azure.CodeSigning.Dlib.dll"
+ Get-ChildItem -Path $outputDir -Recurse | ForEach-Object { echo $_.FullName }
+ exit 1
+ }
+
+ # Set other required paths
+ echo "ACS_JSON=${{ github.workspace }}\signing-metadata.json" >> $env:GITHUB_ENV
+
+ # Find signtool.exe from Windows SDK
+ $signtoolPaths = @(
+ "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe",
+ "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe",
+ "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe"
+ )
+
+ $signtool = $signtoolPaths | Where-Object { Test-Path $_ } | Select-Object -First 1
+
+ if (-not $signtool) {
+ # Find any signtool
+ $signtool = Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits\10\bin" -Recurse -Filter "signtool.exe" |
+ Where-Object { $_.FullName -like "*x64*" } |
+ Select-Object -First 1 -ExpandProperty FullName
+ }
+
+ if ($signtool) {
+ echo "Found signtool at: $signtool"
+ echo "SIGNTOOL_PATH=$signtool" >> $env:GITHUB_ENV
+ } else {
+ echo "ERROR: Could not find signtool.exe"
+ exit 1
+ }
+
+ echo "Azure Trusted Signing setup complete"
+
+ - name: Setup SDKs (VST2)
+ env:
+ VST2_SDK_URL: ${{ secrets.VST2_SDK_URL }}
+ run: |
+ New-Item -ItemType Directory -Force -Path SDKs
+
+ if ($env:VST2_SDK_URL) {
+ echo "Downloading VST2 SDK..."
+ Invoke-WebRequest -Uri $env:VST2_SDK_URL -OutFile SDKs\vst2_sdk.zip
+ Expand-Archive -Path SDKs\vst2_sdk.zip -DestinationPath SDKs
+
+ # Handle different archive structures
+ if (Test-Path "SDKs\VST2_SDK") {
+ echo "VST2 SDK extracted"
+ } elseif (Test-Path "SDKs\vstsdk2.4") {
+ Rename-Item "SDKs\vstsdk2.4" "SDKs\VST2_SDK"
+ } elseif (Test-Path "SDKs\pluginterfaces") {
+ New-Item -ItemType Directory -Force -Path "SDKs\VST2_SDK"
+ Move-Item "SDKs\pluginterfaces" "SDKs\VST2_SDK\"
+ }
+
+ echo "BUILD_VST2=ON" >> $env:GITHUB_ENV
+ } else {
+ echo "VST2_SDK_URL not provided - VST2 builds will be skipped"
+ echo "BUILD_VST2=OFF" >> $env:GITHUB_ENV
+ }
+
+ - name: Create signing metadata
+ run: |
+ @"
+ {
+ "Endpoint": "https://eus.codesigning.azure.net/",
+ "CodeSigningAccountName": "Mach1",
+ "CertificateProfileName": "mach1-cert"
+ }
+ "@ | Out-File -FilePath signing-metadata.json -Encoding UTF8
+
+ - name: Setup Makefile.variables
+ shell: bash
+ run: |
+ # Set VST2 path only if SDK exists
+ VST2_PATH_VALUE=""
+ if [ "$BUILD_VST2" = "ON" ] && [ -d "SDKs/VST2_SDK" ]; then
+ VST2_PATH_VALUE="${{ github.workspace }}/SDKs/VST2_SDK"
+ fi
+
+ cat > Makefile.variables << EOF
+ M1SDK_PATH=
+ VST2_PATH=$VST2_PATH_VALUE
+ WIN_INNO_PATH=C:\Program Files (x86)\Inno Setup 6\ISCC.exe
+ WIN_SIGNTOOL_PATH=C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe
+ AZURE_DLIB_PATH=${{ github.workspace }}\azure-codesigning\lib\net8.0\any\Azure.CodeSigning.Dlib.dll
+ AZURE_METADATA_PATH=${{ github.workspace }}\signing-metadata.json
+ AZURE_TIMESTAMP_URL=http://timestamp.acs.microsoft.com
+ AZURE_CLIENT_ID=${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_TENANT_ID=${{ secrets.AZURE_TENANT_ID }}
+ AZURE_CLIENT_SECRET=${{ secrets.AZURE_SECRET_ID }}
+ PANNER_FREE_GUID=${{ secrets.PANNER_FREE_GUID }}
+ MONITOR_FREE_GUID=${{ secrets.MONITOR_FREE_GUID }}
+ M1_GLOBAL_GUID=${{ secrets.M1_GLOBAL_GUID }}
+ EOF
+ echo "Makefile.variables created (VST2: $BUILD_VST2)"
+
+ - name: Update version
+ shell: bash
+ run: |
+ VERSION_RAW="${VERSION#v}"
+
+ # Check if version is valid numeric format (X.Y.Z or X.Y)
+ if [[ "$VERSION_RAW" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
+ VERSION_CLEAN="$VERSION_RAW"
+ echo "Release build, using version: $VERSION_CLEAN"
+ else
+ # Use 0.0 so after date append we get 0.0.YYYYMMDD (valid 3-part semver)
+ VERSION_CLEAN="0.0"
+ echo "CI_BUILD_TAG=$VERSION_RAW" >> $GITHUB_ENV
+ echo "Non-release build ($VERSION_RAW), using CMake version: $VERSION_CLEAN"
+ fi
+
+ echo "$VERSION_CLEAN" > VERSION
+
+ # Update component versions (propagates to package.json for electron-builder)
+ # Note: make update-versions skips Windows in Makefile, so run script directly
+ chmod +x ./installer/generate_version.sh
+ ./installer/generate_version.sh || echo "Version update completed with warnings"
+ echo "Final versions:"
+ cat VERSION
+ cat m1-transcoder/VERSION 2>/dev/null || true
+
+ - name: Download VLC SDK for Windows
+ id: vlc-download
+ run: |
+ cd m1-player
+ call build_vlc.bat build
+ if exist "build\vlc-install\lib\libvlc.lib" (
+ echo VLC SDK downloaded successfully
+ echo vlc_available=true >> %GITHUB_OUTPUT%
+ ) else (
+ echo WARNING: VLC SDK download may have failed
+ echo vlc_available=false >> %GITHUB_OUTPUT%
+ )
+ shell: cmd
+ continue-on-error: true
+
+ - name: Configure projects
+ shell: bash
+ run: |
+ cmake m1-monitor -Bm1-monitor/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
+ cmake m1-panner -Bm1-panner/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
+
+ # Only configure m1-player if VLC is available
+ if [ -f "m1-player/build/vlc-install/lib/libvlc.lib" ]; then
+ echo "VLC SDK found, configuring m1-player..."
+ cmake m1-player -Bm1-player/build -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF
+ else
+ echo "WARNING: VLC SDK not found, skipping m1-player configuration"
+ fi
+
+ cmake m1-orientationmanager -Bm1-orientationmanager/build
+ cmake services/m1-system-helper -Bservices/m1-system-helper/build
+
+ - name: Build projects
+ shell: bash
+ run: |
+ cmake --build m1-monitor/build --config Release
+ cmake --build m1-panner/build --config Release
+
+ # Only build m1-player if it was configured
+ if [ -d "m1-player/build" ] && [ -f "m1-player/build/vlc-install/lib/libvlc.lib" ]; then
+ echo "Building m1-player..."
+ cmake --build m1-player/build --config Release
+ else
+ echo "WARNING: Skipping m1-player build (VLC SDK not available)"
+ fi
+
+ cmake --build m1-orientationmanager/build --config Release
+ cmake --build services/m1-system-helper/build --config Release
+
+ - name: Build Transcoder
+ run: |
+ cd m1-transcoder
+ npm install
+ npm run package-win
+
+ - name: Code sign Windows binaries with Azure Trusted Signing
+ timeout-minutes: 10
+ env:
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SECRET_ID }}
+ run: |
+ # Sign binaries using signtool + Azure Trusted Signing Dlib
+ # This matches the local aax-signtool.bat approach
+
+ # Skip if secrets not configured
+ if ([string]::IsNullOrEmpty($env:AZURE_CLIENT_ID)) {
+ echo "Azure Trusted Signing not configured, skipping code signing"
+ exit 0
+ }
+
+ # Verify Azure credentials are set
+ if ([string]::IsNullOrEmpty($env:AZURE_CLIENT_SECRET)) {
+ echo "WARNING: AZURE_CLIENT_SECRET (from AZURE_SECRET_ID) is empty"
+ echo "Code signing may fail - check org secrets"
+ }
+
+ # Verify required files exist
+ if (-not (Test-Path $env:SIGNTOOL_PATH)) {
+ echo "ERROR: signtool.exe not found at $env:SIGNTOOL_PATH"
+ exit 1
+ }
+ if (-not (Test-Path $env:ACS_DLIB)) {
+ echo "ERROR: Azure.CodeSigning.Dlib.dll not found at $env:ACS_DLIB"
+ exit 1
+ }
+ if (-not (Test-Path $env:ACS_JSON)) {
+ echo "ERROR: signing-metadata.json not found at $env:ACS_JSON"
+ exit 1
+ }
+
+ # Collect files to sign
+ $filesToSign = @()
+
+ # Find VST3 plugins (the actual .vst3 DLL inside the bundle)
+ Get-ChildItem -Path "m1-monitor/build" -Recurse -Filter "*.vst3" -File | ForEach-Object { $filesToSign += $_.FullName }
+ Get-ChildItem -Path "m1-panner/build" -Recurse -Filter "*.vst3" -File | ForEach-Object { $filesToSign += $_.FullName }
+
+ # Find executables
+ @(
+ "m1-player/build/M1-Player_artefacts/Release/M1-Player.exe",
+ "m1-orientationmanager/build/m1-orientationmanager_artefacts/Release/m1-orientationmanager.exe",
+ "services/m1-system-helper/build/m1-system-helper_artefacts/Release/m1-system-helper.exe"
+ ) | ForEach-Object {
+ if (Test-Path $_) { $filesToSign += $_ }
+ }
+
+ echo "Files to sign: $($filesToSign.Count)"
+ echo "Using signtool: $env:SIGNTOOL_PATH"
+ echo "Using Dlib: $env:ACS_DLIB"
+ echo "Using metadata: $env:ACS_JSON"
+
+ $successCount = 0
+ $failCount = 0
+
+ foreach ($file in $filesToSign) {
+ echo ""
+ echo "Signing: $file"
+
+ # Use the same command as aax-signtool.bat
+ & $env:SIGNTOOL_PATH sign /v /fd SHA256 `
+ /tr "http://timestamp.acs.microsoft.com" /td SHA256 `
+ /dlib $env:ACS_DLIB `
+ /dmdf $env:ACS_JSON `
+ $file
+
+ if ($LASTEXITCODE -eq 0) {
+ echo "SUCCESS: Signed $file"
+ $successCount++
+ } else {
+ echo "WARNING: Failed to sign $file (exit code: $LASTEXITCODE)"
+ $failCount++
+ }
+ }
+
+ echo ""
+ echo "=========================================="
+ echo "Signing complete: $successCount succeeded, $failCount failed"
+ echo "=========================================="
+ shell: pwsh
+ continue-on-error: true
+
+ - name: Package build artifacts
+ run: |
+ mkdir -p artifacts/windows
+
+ # Copy each artifact, handling missing ones gracefully
+ if [ -d "m1-monitor/build/M1-Monitor_artefacts/Release" ]; then
+ cp -r m1-monitor/build/M1-Monitor_artefacts/Release/ artifacts/windows/M1-Monitor/
+ echo "Packaged: M1-Monitor"
+ else
+ echo "WARNING: M1-Monitor artifacts not found"
+ fi
+
+ if [ -d "m1-panner/build/M1-Panner_artefacts/Release" ]; then
+ cp -r m1-panner/build/M1-Panner_artefacts/Release/ artifacts/windows/M1-Panner/
+ echo "Packaged: M1-Panner"
+ else
+ echo "WARNING: M1-Panner artifacts not found"
+ fi
+
+ if [ -d "m1-player/build/M1-Player_artefacts/Release" ]; then
+ cp -r m1-player/build/M1-Player_artefacts/Release/ artifacts/windows/M1-Player/
+ echo "Packaged: M1-Player"
+ else
+ echo "WARNING: M1-Player artifacts not found (VLC SDK may have failed to download)"
+ fi
+
+ if [ -d "m1-orientationmanager/build/m1-orientationmanager_artefacts/Release" ]; then
+ cp -r m1-orientationmanager/build/m1-orientationmanager_artefacts/Release/ artifacts/windows/m1-orientationmanager/
+ echo "Packaged: m1-orientationmanager"
+ else
+ echo "WARNING: m1-orientationmanager artifacts not found"
+ fi
+
+ if [ -d "services/m1-system-helper/build/m1-system-helper_artefacts/Release" ]; then
+ cp -r services/m1-system-helper/build/m1-system-helper_artefacts/Release/ artifacts/windows/m1-system-helper/
+ echo "Packaged: m1-system-helper"
+ else
+ echo "WARNING: m1-system-helper artifacts not found"
+ fi
+
+ echo ""
+ echo "Artifacts packaged:"
+ ls -la artifacts/windows/ || true
+ shell: bash
+
+ - name: Create artifacts archive
+ run: |
+ cd artifacts
+ 7z a -tzip windows-builds.zip windows/
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: windows-builds
+ path: artifacts/windows-builds.zip
+ retention-days: 30
+
+ - name: Upload to S3 artifacts bucket
+ env:
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ run: |
+ $VersionRaw = "$env:VERSION" -replace '^v', ''
+ $CommitSha = "${{ github.sha }}"
+ $ShortSha = $CommitSha.Substring(0, 8)
+
+ aws s3 cp artifacts/windows-builds.zip `
+ "s3://$env:ARTIFACTS_BUCKET/builds/$VersionRaw/windows-builds.zip" `
+ --region us-east-1
+
+ aws s3 cp artifacts/windows-builds.zip `
+ "s3://$env:ARTIFACTS_BUCKET/commits/$ShortSha/windows-builds.zip" `
+ --region us-east-1
+
+ # =============================================================================
+ # Create Build Summary
+ # =============================================================================
+ summary:
+ needs: [build-macos-arm64, build-macos-x86, build-windows]
+ if: always()
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Determine version info
+ id: version
+ run: |
+ VERSION="${{ github.event.inputs.version || github.ref_name }}"
+ VERSION="${VERSION#v}"
+ COMMIT_SHA="${{ github.sha }}"
+ SHORT_SHA="${COMMIT_SHA:0:8}"
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
+ echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT
+
+ - name: Create build summary
+ run: |
+ VERSION="${{ steps.version.outputs.version }}"
+ SHORT_SHA="${{ steps.version.outputs.short_sha }}"
+
+ echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Version:** $VERSION" >> $GITHUB_STEP_SUMMARY
+ echo "**Commit:** $SHORT_SHA" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ echo "### Build Status" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ if [ "${{ needs.build-macos-arm64.result }}" == "success" ]; then
+ echo "- macOS ARM64 (Apple Silicon)" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "- macOS ARM64 (Apple Silicon) - ${{ needs.build-macos-arm64.result }}" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ if [ "${{ needs.build-macos-x86.result }}" == "success" ]; then
+ echo "- macOS x86_64 (Intel)" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "- macOS x86_64 (Intel) - ${{ needs.build-macos-x86.result }}" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ if [ "${{ needs.build-windows.result }}" == "success" ]; then
+ echo "- Windows x64" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "- Windows x64 - ${{ needs.build-windows.result }}" >> $GITHUB_STEP_SUMMARY
+ fi
+
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "### Download Artifacts" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "Artifacts uploaded to S3:" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+ echo "s3://mach1-build-artifacts/builds/$VERSION/" >> $GITHUB_STEP_SUMMARY
+ echo "s3://mach1-build-artifacts/commits/$SHORT_SHA/" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ echo "### Complete Release Locally" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "AAX signing requires a physical USB iLok dongle. Run locally:" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
+ echo "# Download CI artifacts and complete the release" >> $GITHUB_STEP_SUMMARY
+ echo "make package-from-ci VERSION=$VERSION" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "# Or by commit SHA" >> $GITHUB_STEP_SUMMARY
+ echo "make package-from-ci COMMIT=$SHORT_SHA" >> $GITHUB_STEP_SUMMARY
+ echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
+
diff --git a/Makefile b/Makefile
index 24ae395..672438a 100755
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
# MACH1 SPATIAL SYSTEM MakeFile
-.PHONY: help
+.PHONY: help show-arch
help:
@echo "MACH1 SPATIAL SYSTEM - Available Commands:"
@echo ""
@@ -15,10 +15,27 @@ help:
@echo " make clean - Clean all build directories"
@echo " make configure - Configure for release build"
@echo " make build - Build all components"
+ @echo " make build-vlc - Build VLC from source (for m1-player)"
+ @echo ""
+ @echo "Cross-compilation (macOS only - requires x86_64 Homebrew at /usr/local):"
+ @echo " make dev-player-x86 - Configure m1-player for x86_64 (dev build)"
+ @echo " make configure-player-x86 - Configure m1-player for x86_64 (release build)"
+ @echo " make build-player-x86 - Build m1-player for x86_64"
+ @echo " make show-arch - Show current build architecture info"
@echo ""
@echo "Packaging:"
- @echo " make package - Full package build (configure, build, codesign, notarize, installer)"
- @echo " make installer-pkg - Build installer packages (Windows installer is signed automatically)"
+ @echo " make package - Full local build (configure, build, codesign, notarize, installer)"
+ @echo " make package-from-ci VERSION=x.x.x - Download CI builds, sign AAX locally, create installer"
+ @echo " make package-from-ci COMMIT=abc123 - Same as above, but by commit SHA"
+ @echo " make list-ci-builds - List available CI builds in S3"
+ @echo " make installer-pkg - Build installer packages only"
+ @echo ""
+ @echo "CI/CD Testing (local simulation):"
+ @echo " make test-ci-build - Simulate full CI build locally"
+ @echo " make test-ci-build-player-only - Test just m1-player build (fastest)"
+ @echo " make test-ci-yaml - Validate workflow YAML syntax"
+ @echo " make test-ci-act-arm - Run macOS ARM64 job with act"
+ @echo " make test-ci-act-arm DRYRUN=1 - Dry-run (show what would run)"
@echo ""
@echo "Code Signing:"
@echo " make codesign - Sign all binaries (macOS/Windows)"
@@ -29,6 +46,35 @@ help:
@echo ""
@echo "For more details, see the Makefile or run individual commands with --help"
+# Show current build architecture (useful for CI/CD and distribution)
+show-arch:
+ifeq ($(detected_OS),Darwin)
+ @echo "=== Build Architecture Information ==="
+ @echo "Host OS: macOS"
+ @echo "Host Architecture: $$(uname -m)"
+ @if [ "$$(uname -m)" = "arm64" ]; then \
+ echo "Target: Apple Silicon (ARM64)"; \
+ echo "Homebrew: /opt/homebrew"; \
+ echo "Deployment Target: macOS 11.0+"; \
+ else \
+ echo "Target: Intel (x86_64)"; \
+ echo "Homebrew: /usr/local"; \
+ echo "Deployment Target: macOS 10.14+"; \
+ fi
+ @echo ""
+ @echo "NOTE: m1-player builds for HOST architecture only."
+ @echo " For distribution, build on each target platform separately."
+else ifeq ($(detected_OS),Windows)
+ @echo "=== Build Architecture Information ==="
+ @echo "Host OS: Windows"
+ @if "%PROCESSOR_ARCHITECTURE%"=="AMD64" echo "Architecture: x86_64 (64-bit)"
+ @if "%PROCESSOR_ARCHITECTURE%"=="x86" echo "Architecture: x86 (32-bit)"
+else
+ @echo "=== Build Architecture Information ==="
+ @echo "Host OS: $(detected_OS)"
+ @echo "Architecture: $$(uname -m)"
+endif
+
# Auto-generate Makefile.variables from example if it doesn't exist
Makefile.variables:
@if [ ! -f "Makefile.variables" ] && [ -f "Makefile.variables.example" ]; then \
@@ -82,6 +128,7 @@ ifneq ($(detected_OS),Windows)
@echo "m1-player: $$(cat m1-player/VERSION)"
@echo "m1-orientationmanager: $$(cat m1-orientationmanager/VERSION)"
@echo "m1-system-helper: $$(cat services/m1-system-helper/VERSION)"
+ @echo "m1-transcoder: $$(cat m1-transcoder/VERSION)"
@echo ""
@echo "Installer versions updated:"
@echo "macOS: $$(grep -c "$(VERSION)" installer/osx/Mach1\ Spatial\ System\ Installer.pkgproj) packages"
@@ -92,6 +139,8 @@ endif
.PHONY: test-aax-monitor test-aax-panner test-aax-plugins test-aax-release
.PHONY: verify-aax-signing diagnose-aax
+.PHONY: test-ci-build test-ci-build-player-only test-ci-yaml
+.PHONY: test-ci-act-arm
pull:
git pull --recurse-submodules
@@ -120,6 +169,9 @@ setup:
ifeq ($(detected_OS),Darwin)
# Assumes you have installed Homebrew package manager
brew install yasm cmake p7zip ninja act pre-commit launchcontrol
+ # VLC 3.x build dependencies (use FFmpeg 6.x for compatibility)
+ brew install autoconf automake libtool pkg-config
+ brew install ffmpeg@6 && brew link ffmpeg@6
npm install -g nodemon
cd m1-transcoder && ./scripts/setup.sh
cd m1-panner && pre-commit install
@@ -128,6 +180,8 @@ else ifeq ($(detected_OS),Windows)
@choco version >nul || (echo "chocolately is not working or installed" && exit 1)
@echo "choco is installed and working"
@choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' --apply-install-arguments-to-dependencies
+ @choco install pkgconfiglite autoconf automake libtool
+ @pip3 install meson
@if not exist "$(pip show pre-commit)" (pip install pre-commit)
npm install -g nodemon
cd m1-panner && pre-commit install
@@ -341,9 +395,63 @@ endif
dev-player:
ifeq ($(detected_OS),Darwin)
- cmake m1-player -Bm1-player/build-dev -G "Xcode"
+ @echo "Configuring m1-player (dev)..."
+ cmake m1-player -Bm1-player/build-dev -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ @if [ ! -f "m1-player/build-dev/vlc-install/lib/libvlc.dylib" ]; then \
+ echo ""; \
+ echo "VLC libraries not found. Building VLC from source..."; \
+ echo ""; \
+ cd m1-player && ./build_vlc.sh build-dev && \
+ echo "" && \
+ echo "VLC build complete! Reconfiguring CMake..." && \
+ echo "" && \
+ cd .. && cmake m1-player -Bm1-player/build-dev -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF; \
+ fi
else
- cmake m1-player -Bm1-player/build-dev
+ @echo "Configuring m1-player (dev)..."
+ cmake m1-player -Bm1-player/build-dev -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ @if [ ! -f "m1-player/build-dev/vlc-install/lib/libvlc.lib" ] && [ ! -f "m1-player/build-dev/vlc-install/lib/libvlc.dll.a" ]; then \
+ echo ""; \
+ echo "VLC libraries not found. Building VLC from source..."; \
+ echo "This will take 20-40 minutes..."; \
+ echo ""; \
+ cd m1-player && ./build_vlc.sh build-dev && \
+ echo "" && \
+ echo "VLC build complete! Reconfiguring CMake..." && \
+ echo "" && \
+ cd .. && cmake m1-player -Bm1-player/build-dev -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF; \
+ fi
+endif
+
+# Cross-compile m1-player for x86_64 on Apple Silicon (via Rosetta 2)
+# Requires x86_64 Homebrew installed at /usr/local with all VLC dependencies
+dev-player-x86:
+ifeq ($(detected_OS),Darwin)
+ @echo "Configuring m1-player for x86_64 (cross-compilation via Rosetta)..."
+ @if [ ! -d "/usr/local/bin" ]; then \
+ echo "ERROR: x86_64 Homebrew not found at /usr/local"; \
+ echo "Install it with:"; \
+ echo " arch -x86_64 /bin/bash -c \"\$$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""; \
+ exit 1; \
+ fi
+ arch -x86_64 cmake m1-player -Bm1-player/build-dev-x86 -G "Xcode" \
+ -DCMAKE_OSX_ARCHITECTURES=x86_64 \
+ -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ @if [ ! -f "m1-player/build-dev-x86/vlc-install/lib/libvlc.dylib" ]; then \
+ echo ""; \
+ echo "VLC libraries not found. Building VLC for x86_64..."; \
+ echo ""; \
+ cd m1-player && arch -x86_64 ./build_vlc.sh build-dev-x86 && \
+ echo "" && \
+ echo "VLC build complete! Reconfiguring CMake..." && \
+ echo "" && \
+ cd .. && arch -x86_64 cmake m1-player -Bm1-player/build-dev-x86 -G "Xcode" \
+ -DCMAKE_OSX_ARCHITECTURES=x86_64 \
+ -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF; \
+ fi
+else
+ @echo "ERROR: dev-player-x86 is only available on macOS"
+ @exit 1
endif
dev-orientationmanager:
@@ -392,17 +500,313 @@ endif
overlay-debug:
cd m1-panner/Resources/overlay_debug && ./run_simulator.sh --title "Avid Video Engine"
-# run configure first
+# =============================================================================
+# Release Packaging
+# =============================================================================
+# Full local build: configure → build → sign → notarize → installer
package: update-versions build docs-build codesign notarize installer-pkg
+# =============================================================================
+# Hybrid CI/CD Release (Recommended)
+# =============================================================================
+# Downloads pre-built artifacts from CI/CD, then signs AAX locally and creates installer.
+# This is the recommended workflow since AAX signing requires a physical USB iLok dongle.
+#
+# Usage:
+# make package-from-ci VERSION=2.0.1 # By version tag
+# make package-from-ci COMMIT=abc12345 # By commit SHA
+#
+# Prerequisites:
+# - AWS CLI configured with access to mach1-build-artifacts bucket
+# - USB iLok dongle connected for AAX signing
+# - Apple Developer certificate in keychain for macOS
+#
+ARTIFACTS_BUCKET ?= mach1-build-artifacts
+CI_ARTIFACTS_DIR ?= ci-artifacts
+
+package-from-ci: download-ci-artifacts sign-aax-local installer-pkg-from-ci
+ @echo ""
+ @echo "========================================"
+ @echo "Release Complete!"
+ @echo "========================================"
+ @echo ""
+
+download-ci-artifacts:
+ @echo "========================================"
+ @echo "Downloading CI Build Artifacts"
+ @echo "========================================"
+ifeq ($(detected_OS),Darwin)
+ @if [ -z "$(VERSION)" ] && [ -z "$(COMMIT)" ]; then \
+ echo "ERROR: Specify VERSION or COMMIT"; \
+ echo " make package-from-ci VERSION=2.0.1"; \
+ echo " make package-from-ci COMMIT=abc12345"; \
+ exit 1; \
+ fi
+ @mkdir -p $(CI_ARTIFACTS_DIR)
+ @if [ -n "$(VERSION)" ]; then \
+ echo "Downloading version $(VERSION) artifacts..."; \
+ aws s3 cp "s3://$(ARTIFACTS_BUCKET)/builds/$(VERSION)/macos-arm64-builds.tar.gz" \
+ "$(CI_ARTIFACTS_DIR)/macos-arm64-builds.tar.gz" --region us-east-1 || \
+ (echo "ERROR: Artifacts not found for version $(VERSION)" && exit 1); \
+ elif [ -n "$(COMMIT)" ]; then \
+ echo "Downloading commit $(COMMIT) artifacts..."; \
+ aws s3 cp "s3://$(ARTIFACTS_BUCKET)/commits/$(COMMIT)/macos-arm64-builds.tar.gz" \
+ "$(CI_ARTIFACTS_DIR)/macos-arm64-builds.tar.gz" --region us-east-1 || \
+ (echo "ERROR: Artifacts not found for commit $(COMMIT)" && exit 1); \
+ fi
+ @echo "Extracting artifacts..."
+ @cd $(CI_ARTIFACTS_DIR) && tar -xzf macos-arm64-builds.tar.gz
+ @echo ""
+ @echo "Installing artifacts to build directories..."
+ @mkdir -p m1-monitor/build m1-panner/build m1-player/build
+ @mkdir -p m1-orientationmanager/build services/m1-system-helper/build
+ @cp -r $(CI_ARTIFACTS_DIR)/macos-arm64/M1-Monitor/* m1-monitor/build/ 2>/dev/null || true
+ @cp -r $(CI_ARTIFACTS_DIR)/macos-arm64/M1-Panner/* m1-panner/build/ 2>/dev/null || true
+ @cp -r $(CI_ARTIFACTS_DIR)/macos-arm64/M1-Player/* m1-player/build/ 2>/dev/null || true
+ @cp -r $(CI_ARTIFACTS_DIR)/macos-arm64/m1-orientationmanager/* m1-orientationmanager/build/ 2>/dev/null || true
+ @cp -r $(CI_ARTIFACTS_DIR)/macos-arm64/m1-system-helper/* services/m1-system-helper/build/ 2>/dev/null || true
+ @echo "Artifacts downloaded and installed"
+else ifeq ($(detected_OS),Windows)
+ @echo "Downloading Windows artifacts..."
+ @if not defined VERSION if not defined COMMIT ( \
+ echo ERROR: Specify VERSION or COMMIT && \
+ echo make package-from-ci VERSION=2.0.1 && \
+ echo make package-from-ci COMMIT=abc12345 && \
+ exit 1 \
+ )
+ @if not exist $(CI_ARTIFACTS_DIR) mkdir $(CI_ARTIFACTS_DIR)
+ @if defined VERSION ( \
+ aws s3 cp "s3://$(ARTIFACTS_BUCKET)/builds/$(VERSION)/windows-builds.zip" \
+ "$(CI_ARTIFACTS_DIR)\windows-builds.zip" --region us-east-1 \
+ ) else ( \
+ aws s3 cp "s3://$(ARTIFACTS_BUCKET)/commits/$(COMMIT)/windows-builds.zip" \
+ "$(CI_ARTIFACTS_DIR)\windows-builds.zip" --region us-east-1 \
+ )
+ @7z x -y "$(CI_ARTIFACTS_DIR)\windows-builds.zip" -o"$(CI_ARTIFACTS_DIR)"
+ @echo Artifacts downloaded and extracted
+endif
+
+sign-aax-local:
+ @echo ""
+ @echo "========================================"
+ @echo "Signing AAX Plugins (USB iLok Required)"
+ @echo "========================================"
+ifeq ($(detected_OS),Darwin)
+ @echo "Ensure your USB iLok dongle is connected..."
+ @echo ""
+ @if [ -d "m1-monitor/build/M1-Monitor_artefacts/AAX" ] || [ -d "m1-monitor/build/AAX" ]; then \
+ echo "Signing M1-Monitor AAX..."; \
+ AAX_PATH=$$(find m1-monitor/build -name "M1-Monitor.aaxplugin" -type d | head -1); \
+ if [ -n "$$AAX_PATH" ]; then \
+ codesign --force --sign $(APPLE_CODESIGN_CODE) --timestamp "$$AAX_PATH"; \
+ $(WRAPTOOL) sign --verbose --account $(PACE_ACCOUNT) --wcguid "$(MONITOR_FREE_GUID)" \
+ --signid $(APPLE_CODESIGN_ID) --in "$$AAX_PATH" --out "$$AAX_PATH" --autoinstall on; \
+ echo "M1-Monitor AAX signed"; \
+ else \
+ echo "M1-Monitor.aaxplugin not found"; \
+ fi; \
+ fi
+ @if [ -d "m1-panner/build/M1-Panner_artefacts/AAX" ] || [ -d "m1-panner/build/AAX" ]; then \
+ echo "Signing M1-Panner AAX..."; \
+ AAX_PATH=$$(find m1-panner/build -name "M1-Panner.aaxplugin" -type d | head -1); \
+ if [ -n "$$AAX_PATH" ]; then \
+ codesign --force --sign $(APPLE_CODESIGN_CODE) --timestamp "$$AAX_PATH"; \
+ $(WRAPTOOL) sign --verbose --account $(PACE_ACCOUNT) --wcguid "$(PANNER_FREE_GUID)" \
+ --signid $(APPLE_CODESIGN_ID) --in "$$AAX_PATH" --out "$$AAX_PATH" --autoinstall on; \
+ echo "M1-Panner AAX signed"; \
+ else \
+ echo "M1-Panner.aaxplugin not found"; \
+ fi; \
+ fi
+ @echo ""
+ @echo "AAX signing complete!"
+else ifeq ($(detected_OS),Windows)
+ @echo "Signing AAX plugins on Windows..."
+ @echo "Ensure iLok License Manager is running..."
+ @if exist "m1-monitor\build\M1-Monitor_artefacts\Release\AAX\M1-Monitor.aaxplugin" ( \
+ set SIGNTOOL_PATH=$(WIN_SIGNTOOL_PATH) && \
+ set ACS_DLIB=$(AZURE_DLIB_PATH) && \
+ set ACS_JSON=$(AZURE_METADATA_PATH) && \
+ set AZURE_TENANT_ID=$(AZURE_TENANT_ID) && \
+ set AZURE_CLIENT_ID=$(AZURE_CLIENT_ID) && \
+ set AZURE_SECRET_ID=$(AZURE_CLIENT_SECRET) && \
+ $(WRAPTOOL) sign --signtool "$(CURDIR)/installer/win/aax-signtool.bat" --signid 1 --verbose \
+ --installedbinaries --account $(PACE_ACCOUNT) --wcguid "$(MONITOR_FREE_GUID)" \
+ --in m1-monitor\build\M1-Monitor_artefacts\Release\AAX\M1-Monitor.aaxplugin \
+ --out m1-monitor\build\M1-Monitor_artefacts\Release\AAX\M1-Monitor.aaxplugin \
+ )
+ @if exist "m1-panner\build\M1-Panner_artefacts\Release\AAX\M1-Panner.aaxplugin" ( \
+ set SIGNTOOL_PATH=$(WIN_SIGNTOOL_PATH) && \
+ set ACS_DLIB=$(AZURE_DLIB_PATH) && \
+ set ACS_JSON=$(AZURE_METADATA_PATH) && \
+ set AZURE_TENANT_ID=$(AZURE_TENANT_ID) && \
+ set AZURE_CLIENT_ID=$(AZURE_CLIENT_ID) && \
+ set AZURE_SECRET_ID=$(AZURE_CLIENT_SECRET) && \
+ $(WRAPTOOL) sign --signtool "$(CURDIR)/installer/win/aax-signtool.bat" --signid 1 --verbose \
+ --installedbinaries --account $(PACE_ACCOUNT) --wcguid "$(PANNER_FREE_GUID)" \
+ --in m1-panner\build\M1-Panner_artefacts\Release\AAX\M1-Panner.aaxplugin \
+ --out m1-panner\build\M1-Panner_artefacts\Release\AAX\M1-Panner.aaxplugin \
+ )
+endif
+
+installer-pkg-from-ci: sign-aax-local
+ @echo ""
+ @echo "========================================"
+ @echo "Creating Installer Package"
+ @echo "========================================"
+ifeq ($(detected_OS),Darwin)
+ @echo "Building and signing installer..."
+ packagesbuild -v installer/osx/Mach1\ Spatial\ System\ Installer.pkgproj
+ codesign --force --sign $(APPLE_CODESIGN_CODE) --timestamp installer/osx/build/Mach1\ Spatial\ System\ Installer.pkg
+ mkdir -p installer/osx/build/signed
+ productsign --sign $(APPLE_CODESIGN_INSTALLER_ID) \
+ "installer/osx/build/Mach1 Spatial System Installer.pkg" \
+ "installer/osx/build/signed/Mach1 Spatial System Installer.pkg"
+ @echo ""
+ @echo "Notarizing installer..."
+ xcrun notarytool submit --wait --keychain-profile 'notarize-app' \
+ --apple-id $(APPLE_USERNAME) --password $(ALTOOL_APPPASS) --team-id $(APPLE_TEAM_CODE) \
+ "installer/osx/build/signed/Mach1 Spatial System Installer.pkg"
+ xcrun stapler staple installer/osx/build/signed/Mach1\ Spatial\ System\ Installer.pkg
+ @echo ""
+ @echo "Installer created at: installer/osx/build/signed/Mach1 Spatial System Installer.pkg"
+else ifeq ($(detected_OS),Windows)
+ @echo "Building Windows installer..."
+ $(WIN_INNO_PATH) "${CURDIR}/installer/win/installer.iss"
+ @echo "Signing installer..."
+ powershell -ExecutionPolicy Bypass -File installer\win\sign-file.ps1 \
+ -FilePath "installer\win\Output\Mach1 Spatial System Installer.exe"
+ @echo "Installer created at: installer\win\Output\Mach1 Spatial System Installer.exe"
+endif
+
+# List available CI builds
+list-ci-builds:
+ @echo "Available builds in S3:"
+ @echo ""
+ @echo "By Version:"
+ @aws s3 ls "s3://$(ARTIFACTS_BUCKET)/builds/" --region us-east-1 2>/dev/null || echo " (none or access denied)"
+ @echo ""
+ @echo "By Commit (recent):"
+ @aws s3 ls "s3://$(ARTIFACTS_BUCKET)/commits/" --region us-east-1 2>/dev/null | tail -10 || echo " (none or access denied)"
+
+# Clean CI artifacts
+clean-ci-artifacts:
+ @echo "Cleaning CI artifacts..."
+ rm -rf $(CI_ARTIFACTS_DIR)
+ @echo "CI artifacts cleaned"
+
+# =============================================================================
+# CI/CD Testing (Local Simulation)
+# =============================================================================
+# Simulates what CI/CD does, but runs locally. Useful for testing before push.
+#
+# Usage:
+# make test-ci-build - Simulate full CI build
+# make test-ci-build-player-only - Just build m1-player (fastest test)
+#
+test-ci-build:
+ @echo "========================================"
+ @echo "Simulating CI/CD Build Locally"
+ @echo "========================================"
+ @echo ""
+ @echo "This simulates what GitHub Actions does:"
+ @echo " 1. Clean build"
+ @echo " 2. Configure all projects"
+ @echo " 3. Build all projects"
+ @echo " 4. Sign non-AAX plugins"
+ @echo " 5. Package artifacts"
+ @echo ""
+ @echo "Press Ctrl+C to cancel, or wait 5 seconds..."
+ @sleep 5
+ @echo ""
+ $(MAKE) clean
+ $(MAKE) configure
+ $(MAKE) build
+ $(MAKE) codesign-vst3 || true
+ $(MAKE) codesign-au || true
+ $(MAKE) codesign-apps || true
+ @echo ""
+ @echo "========================================"
+ @echo "CI Build Simulation Complete!"
+ @echo "========================================"
+ @echo ""
+ @echo "Next steps to test full release flow:"
+ @echo " 1. Connect USB iLok"
+ @echo " 2. Run: make sign-aax-local"
+ @echo " 3. Run: make installer-pkg"
+
+test-ci-build-player-only:
+ @echo "========================================"
+ @echo "Testing m1-player Build (CI Simulation)"
+ @echo "========================================"
+ @echo ""
+ @echo "This tests the VLC build + m1-player compilation"
+ @echo "which is the most complex part of CI/CD."
+ @echo ""
+ifeq ($(detected_OS),Darwin)
+ rm -rf m1-player/build-test
+ cmake m1-player -Bm1-player/build-test -G "Xcode" \
+ -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ @if [ ! -f "m1-player/build-test/vlc-install/lib/libvlc.dylib" ]; then \
+ echo "Building VLC from source..."; \
+ cd m1-player && ./build_vlc.sh build-test && cd ..; \
+ cmake m1-player -Bm1-player/build-test -G "Xcode" \
+ -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF; \
+ fi
+ cmake --build m1-player/build-test --config Release
+ @echo ""
+ @echo "m1-player build test complete!"
+ @echo " Output: m1-player/build-test/M1-Player_artefacts/"
+else
+ @echo "This test is currently macOS-only"
+endif
+
+# Validate workflow YAML syntax
+test-ci-yaml:
+ @echo "Validating GitHub Actions workflow syntax..."
+ @if command -v actionlint >/dev/null 2>&1; then \
+ actionlint .github/workflows/*.yml; \
+ echo "Workflow YAML is valid"; \
+ elif command -v act >/dev/null 2>&1; then \
+ act -l > /dev/null 2>&1 && echo "Workflow YAML is valid (act)"; \
+ else \
+ echo "Install actionlint or act for YAML validation:"; \
+ echo " brew install actionlint"; \
+ echo " brew install act"; \
+ fi
+
# clean and configure for release
configure: clean update-versions
cmake m1-monitor -Bm1-monitor/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DBUILD_AU=ON -DBUILD_VST=ON -DVST2_PATH=$(VST2_PATH) -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
cmake m1-panner -Bm1-panner/build -DBUILD_VST3=ON -DBUILD_AAX=ON -DBUILD_AU=ON -DBUILD_VST=ON -DVST2_PATH=$(VST2_PATH) -DJUCE_COPY_PLUGIN_AFTER_BUILD=OFF
ifeq ($(detected_OS),Darwin)
- cmake m1-player -Bm1-player/build -G "Xcode"
+ @echo "Configuring m1-player (release)..."
+ cmake m1-player -Bm1-player/build -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ @if [ ! -f "m1-player/build/vlc-install/lib/libvlc.dylib" ]; then \
+ echo ""; \
+ echo "VLC libraries not found. Building VLC from source..."; \
+ echo "This will take 20-40 minutes..."; \
+ echo ""; \
+ cd m1-player && ./build_vlc.sh build && \
+ echo "" && \
+ echo "VLC build complete! Reconfiguring CMake..." && \
+ echo "" && \
+ cd .. && cmake m1-player -Bm1-player/build -G "Xcode" -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF; \
+ fi
else
- cmake m1-player -Bm1-player/build
+ @echo "Configuring m1-player (release)..."
+ cmake m1-player -Bm1-player/build -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ @if [ ! -f "m1-player/build/vlc-install/lib/libvlc.lib" ] && [ ! -f "m1-player/build/vlc-install/lib/libvlc.dll.a" ]; then \
+ echo ""; \
+ echo "VLC libraries not found. Building VLC from source..."; \
+ echo "This will take 20-40 minutes..."; \
+ echo ""; \
+ cd m1-player && ./build_vlc.sh build && \
+ echo "" && \
+ echo "VLC build complete! Reconfiguring CMake..." && \
+ echo "" && \
+ cd .. && cmake m1-player -Bm1-player/build -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF; \
+ fi
endif
cmake m1-orientationmanager -Bm1-orientationmanager/build
cmake services/m1-system-helper -Bservices/m1-system-helper/build
@@ -422,6 +826,91 @@ build-panner:
build-player:
cmake --build m1-player/build --config "Release"
+# Cross-compile release build for x86_64 on Apple Silicon
+build-player-x86:
+ifeq ($(detected_OS),Darwin)
+ arch -x86_64 cmake --build m1-player/build-x86 --config "Release"
+else
+ @echo "ERROR: build-player-x86 is only available on macOS"
+ @exit 1
+endif
+
+# Configure m1-player for x86_64 release (cross-compilation on Apple Silicon)
+configure-player-x86:
+ifeq ($(detected_OS),Darwin)
+ @echo "Configuring m1-player for x86_64 release (cross-compilation via Rosetta)..."
+ @if [ ! -d "/usr/local/bin" ]; then \
+ echo "ERROR: x86_64 Homebrew not found at /usr/local"; \
+ echo "Install it with:"; \
+ echo " arch -x86_64 /bin/bash -c \"\$$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""; \
+ exit 1; \
+ fi
+ arch -x86_64 cmake m1-player -Bm1-player/build-x86 -G "Xcode" \
+ -DCMAKE_OSX_ARCHITECTURES=x86_64 \
+ -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF || true
+ @if [ ! -f "m1-player/build-x86/vlc-install/lib/libvlc.dylib" ]; then \
+ echo ""; \
+ echo "VLC libraries not found. Building VLC for x86_64..."; \
+ echo "This will take 20-40 minutes..."; \
+ echo ""; \
+ cd m1-player && arch -x86_64 ./build_vlc.sh build-x86 && \
+ echo "" && \
+ echo "VLC build complete! Reconfiguring CMake..." && \
+ echo "" && \
+ cd .. && arch -x86_64 cmake m1-player -Bm1-player/build-x86 -G "Xcode" \
+ -DCMAKE_OSX_ARCHITECTURES=x86_64 \
+ -DLIBVLC_BUILD_FROM_SOURCE=ON -DLIBVLC_STATIC=OFF; \
+ fi
+else
+ @echo "ERROR: configure-player-x86 is only available on macOS"
+ @exit 1
+endif
+
+# Build VLC from source (happens automatically as part of build-player)
+# Use this target if you want to build VLC separately first
+#
+# ARCHITECTURE NOTE:
+# VLC and m1-player are built for the HOST architecture only.
+# Universal binaries are NOT supported due to VLC/Homebrew dependencies.
+# For distribution:
+# - Build on Apple Silicon Mac for ARM64 (.app for M1/M2/M3 Macs)
+# - Build on Intel Mac for x86_64 (.app for older Intel Macs)
+# The installer should be built and deployed separately for each architecture.
+#
+# CROSS-COMPILATION (macOS only):
+# To build x86_64 on Apple Silicon, use the x86 targets:
+# make dev-player-x86 (for development)
+# make build-player-x86 (for release)
+# Requires x86_64 Homebrew installed at /usr/local
+build-vlc:
+ @echo "Building VLC from source..."
+ifeq ($(detected_OS),Darwin)
+ @if [ -d "m1-player/build-dev" ]; then \
+ echo "Using development build directory (build-dev)"; \
+ cd m1-player && ./build_vlc.sh build-dev; \
+ elif [ -d "m1-player/build" ]; then \
+ echo "Using release build directory (build)"; \
+ cd m1-player && ./build_vlc.sh build; \
+ else \
+ echo "Error: Neither m1-player/build nor m1-player/build-dev found."; \
+ echo "Run 'make configure' or 'make dev-player' first."; \
+ exit 1; \
+ fi
+else
+ @if [ -d "m1-player/build-dev" ]; then \
+ echo "Using development build directory (build-dev)"; \
+ cd m1-player && ./build_vlc.sh build-dev; \
+ elif [ -d "m1-player/build" ]; then \
+ echo "Using release build directory (build)"; \
+ cd m1-player && ./build_vlc.sh build; \
+ else \
+ echo "Error: Neither m1-player/build nor m1-player/build-dev found."; \
+ echo "Run 'make configure' or 'make dev-player' first."; \
+ exit 1; \
+ fi
+endif
+ @echo "VLC setup complete"
+
build-orientationmanager:
cmake --build m1-orientationmanager/build --config "Release"
@@ -590,6 +1079,10 @@ endif
codesign-apps:
ifeq ($(detected_OS),Darwin)
@echo "Code signing applications..."
+ # Sign bundled libraries and plugins inside M1-Player.app first (required for notarization)
+ # This signs all dylibs in Contents (Frameworks and PlugIns) with the same identity
+ find m1-player/build/M1-Player_artefacts/Release/M1-Player.app/Contents -type f -name "*.dylib" -exec codesign --force --sign $(APPLE_CODESIGN_CODE) --timestamp -o runtime {} \;
+
codesign -v --force -o runtime --entitlements m1-player/Resources/M1-Player.entitlements --sign $(APPLE_CODESIGN_CODE) --timestamp m1-player/build/M1-Player_artefacts/Release/M1-Player.app
codesign -v --force -o runtime --entitlements m1-orientationmanager/Resources/entitlements.mac.plist --sign $(APPLE_CODESIGN_CODE) --timestamp m1-orientationmanager/build/m1-orientationmanager_artefacts/m1-orientationmanager
codesign -v --force -o runtime --entitlements services/m1-system-helper/entitlements.mac.plist --sign $(APPLE_CODESIGN_CODE) --timestamp services/m1-system-helper/build/m1-system-helper_artefacts/m1-system-helper
diff --git a/installer/osx/Mach1 Spatial System Installer.pkgproj b/installer/osx/Mach1 Spatial System Installer.pkgproj
index 2965b7a..64f7366 100644
--- a/installer/osx/Mach1 Spatial System Installer.pkgproj
+++ b/installer/osx/Mach1 Spatial System Installer.pkgproj
@@ -1038,7 +1038,7 @@
USE_HFS+_COMPRESSION
VERSION
- 2.0.20250902
+ 2.0.20251211
TYPE
0
@@ -1763,7 +1763,7 @@
USE_HFS+_COMPRESSION
VERSION
- 2.0.20251010
+ 2.0.20251211
TYPE
0
@@ -4264,7 +4264,7 @@
USE_HFS+_COMPRESSION
VERSION
- 2.0.20250902
+ 2.0.20251205
TYPE
0
@@ -5387,7 +5387,7 @@
USE_HFS+_COMPRESSION
VERSION
- 2.0.20251011
+ 2.0.20251211
TYPE
0
@@ -6493,7 +6493,7 @@
USE_HFS+_COMPRESSION
VERSION
- 2.0.20251011
+ 2.0.20251211
TYPE
0
@@ -7599,7 +7599,7 @@
USE_HFS+_COMPRESSION
VERSION
- 2.0.20251011
+ 2.0.20251211
TYPE
0
@@ -8705,7 +8705,7 @@
USE_HFS+_COMPRESSION
VERSION
- 2.0.20251011
+ 2.0.20251211
TYPE
0
diff --git a/m1-monitor b/m1-monitor
index 1d698c5..fd86bc1 160000
--- a/m1-monitor
+++ b/m1-monitor
@@ -1 +1 @@
-Subproject commit 1d698c582ede2b27c55d06f910865b516c553593
+Subproject commit fd86bc16e3f5ce997a9512732b482963e91affea
diff --git a/m1-orientationmanager b/m1-orientationmanager
index 99293fa..d04e924 160000
--- a/m1-orientationmanager
+++ b/m1-orientationmanager
@@ -1 +1 @@
-Subproject commit 99293fa41bee6c1eaef2e9f3bcdaffb8eabc8ed2
+Subproject commit d04e924fbd6bb6b02fb23cf5ddda764be75aff58
diff --git a/m1-player b/m1-player
index 71d5cea..1187aaf 160000
--- a/m1-player
+++ b/m1-player
@@ -1 +1 @@
-Subproject commit 71d5ceabaffeade165ca5219fd4e046e5275b3db
+Subproject commit 1187aaf850ce0a74543af0959086a5e43e048904
diff --git a/services/m1-system-helper/VERSION b/services/m1-system-helper/VERSION
index 25f76ba..251113e 100644
--- a/services/m1-system-helper/VERSION
+++ b/services/m1-system-helper/VERSION
@@ -1 +1 @@
-2.0.20251110
+2.0.20251215