diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..57dc572
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,425 @@
+name: Build & Package
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - release
+
+jobs:
+ build:
+ permissions:
+ contents: read
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - platform: ubuntu-22.04
+ target: ''
+ artifact-name: linux-x86_64
+ - platform: macos-latest
+ target: ''
+ artifact-name: macos-arm64
+ - platform: macos-latest
+ target: x86_64-apple-darwin
+ artifact-name: macos-x86_64
+ - platform: windows-latest
+ target: ''
+ artifact-name: windows-x86_64
+
+ runs-on: ${{ matrix.platform }}
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Verify submodules
+ shell: bash
+ run: |
+ echo "=== Submodule status ==="
+ git submodule status --recursive
+ echo "=== NeuralAudio deps ==="
+ ls -la vendor/NeuralAudio/deps/
+ ls vendor/NeuralAudio/deps/RTNeural/CMakeLists.txt
+ ls vendor/NeuralAudio/deps/math_approx/CMakeLists.txt
+
+ - name: Clone egui fork
+ run: git clone --depth 1 -b ibus-wayland-fix https://git.skyler.io/skyler/egui.git ../egui-fork
+ env:
+ GIT_LFS_SKIP_SMUDGE: "1"
+
+ - name: Install Rust stable
+ uses: dtolnay/rust-toolchain@stable
+ with:
+ targets: ${{ matrix.target != '' && matrix.target || '' }}
+
+ - name: Rust cache
+ uses: swatinem/rust-cache@v2
+ with:
+ workspaces: './lightningbeam-ui -> target'
+ key: ${{ matrix.artifact-name }}-v2
+
+ # ── Linux dependencies ──
+ - name: Install dependencies (Linux)
+ if: matrix.platform == 'ubuntu-22.04'
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y \
+ build-essential pkg-config clang nasm cmake \
+ libasound2-dev libwayland-dev libwayland-cursor0 \
+ libx11-dev libxkbcommon-dev libxcb-shape0-dev libxcb-xfixes0-dev \
+ libxdo-dev libglib2.0-dev libgtk-3-dev libvulkan-dev \
+ yasm libx264-dev libx265-dev libvpx-dev libmp3lame-dev libopus-dev \
+ libpulse-dev squashfs-tools dpkg rpm
+
+ - name: Install cargo packaging tools (Linux)
+ if: matrix.platform == 'ubuntu-22.04'
+ uses: taiki-e/install-action@v2
+ with:
+ tool: cargo-deb,cargo-generate-rpm
+
+ # ── macOS dependencies ──
+ - name: Install dependencies (macOS)
+ if: startsWith(matrix.platform, 'macos')
+ run: brew install nasm cmake create-dmg
+
+ # ── Windows dependencies ──
+ - name: Install dependencies (Windows)
+ if: matrix.platform == 'windows-latest'
+ shell: pwsh
+ run: choco install cmake llvm --installargs 'ADD_CMAKE_TO_PATH=System' -y
+
+ # ── Common build steps ──
+ - name: Extract version
+ id: version
+ shell: bash
+ run: |
+ VERSION=$(grep '^version' lightningbeam-ui/lightningbeam-editor/Cargo.toml | sed 's/.*"\(.*\)"/\1/')
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
+
+ - name: Enable FFmpeg build from source (Linux/macOS)
+ if: matrix.platform != 'windows-latest'
+ shell: bash
+ run: |
+ sed -i.bak 's/ffmpeg-next = { version = "8.0", features = \["static"\] }/ffmpeg-next = { version = "8.0", features = ["build", "static"] }/' lightningbeam-ui/lightningbeam-editor/Cargo.toml
+
+ - name: Setup FFmpeg (Windows)
+ if: matrix.platform == 'windows-latest'
+ shell: pwsh
+ run: |
+ # Download FFmpeg 8.0 shared+dev build (headers + import libs + DLLs)
+ $url = "https://github.com/GyanD/codexffmpeg/releases/download/8.0/ffmpeg-8.0-full_build-shared.7z"
+ Invoke-WebRequest -Uri $url -OutFile ffmpeg.7z
+ 7z x ffmpeg.7z -offmpeg-win
+ $ffmpegDir = (Get-ChildItem -Path ffmpeg-win -Directory | Select-Object -First 1).FullName
+ echo "FFMPEG_DIR=$ffmpegDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+ # LLVM/libclang for bindgen
+ echo "LIBCLANG_PATH=C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+ - name: Setup icons
+ shell: bash
+ run: |
+ mkdir -p lightningbeam-ui/lightningbeam-editor/assets/icons
+ cp -f src-tauri/icons/32x32.png lightningbeam-ui/lightningbeam-editor/assets/icons/
+ cp -f src-tauri/icons/128x128.png lightningbeam-ui/lightningbeam-editor/assets/icons/
+ cp -f src-tauri/icons/icon.png lightningbeam-ui/lightningbeam-editor/assets/icons/256x256.png
+
+ - name: Stage factory presets
+ shell: bash
+ run: |
+ mkdir -p lightningbeam-ui/lightningbeam-editor/assets/presets
+ cp -r src/assets/instruments/* lightningbeam-ui/lightningbeam-editor/assets/presets/
+ # Remove empty category dirs and README
+ find lightningbeam-ui/lightningbeam-editor/assets/presets -maxdepth 1 -type d -empty -delete
+ rm -f lightningbeam-ui/lightningbeam-editor/assets/presets/README.md
+
+ - name: Inject preset entries into RPM metadata (Linux)
+ if: matrix.platform == 'ubuntu-22.04'
+ shell: bash
+ run: |
+ cd lightningbeam-ui
+ find lightningbeam-editor/assets/presets -type f | sort | while read -r f; do
+ rel="${f#lightningbeam-editor/}"
+ dest="/usr/share/lightningbeam-editor/presets/${f#lightningbeam-editor/assets/presets/}"
+ printf '\n[[package.metadata.generate-rpm.assets]]\nsource = "%s"\ndest = "%s"\nmode = "644"\n' "$rel" "$dest" >> lightningbeam-editor/Cargo.toml
+ done
+
+ - name: Fix FFmpeg cross-compile OS detection (macOS x86_64)
+ if: matrix.target == 'x86_64-apple-darwin'
+ shell: bash
+ run: |
+ # ffmpeg-sys-next passes --target-os=macos to FFmpeg configure, but FFmpeg
+ # expects --target-os=darwin. Fetch crates, then patch the build script.
+ cd lightningbeam-ui
+ cargo fetch
+ BUILDRS=$(find $HOME/.cargo/registry/src -path '*/ffmpeg-sys-next-*/build.rs' | head -1)
+ echo "Patching $BUILDRS to fix macos -> darwin mapping"
+ # Add "macos" => "darwin" to the match in get_ffmpeg_target_os()
+ sed -i.bak 's/"ios" => "darwin"/"ios" | "macos" => "darwin"/' "$BUILDRS"
+ grep -A4 'fn get_ffmpeg_target_os' "$BUILDRS"
+ echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> "$GITHUB_ENV"
+
+ - name: Build release binary
+ shell: bash
+ env:
+ FFMPEG_STATIC: "1"
+ run: |
+ cd lightningbeam-ui
+ TARGET_FLAG=""
+ if [ -n "${{ matrix.target }}" ]; then
+ TARGET_FLAG="--target ${{ matrix.target }}"
+ fi
+ cargo build --release --bin lightningbeam-editor $TARGET_FLAG
+
+ - name: Copy cross-compiled binary to release dir
+ if: matrix.target != ''
+ shell: bash
+ run: |
+ mkdir -p lightningbeam-ui/target/release
+ cp lightningbeam-ui/target/${{ matrix.target }}/release/lightningbeam-editor lightningbeam-ui/target/release/
+
+ # ── Stage presets next to binary for packaging ──
+ - name: Stage presets in target dir
+ shell: bash
+ run: |
+ mkdir -p lightningbeam-ui/target/release/presets
+ cp -r lightningbeam-ui/lightningbeam-editor/assets/presets/* lightningbeam-ui/target/release/presets/
+
+ # ══════════════════════════════════════════════
+ # Linux Packaging
+ # ══════════════════════════════════════════════
+ - name: Build .deb package
+ if: matrix.platform == 'ubuntu-22.04'
+ shell: bash
+ run: |
+ cd lightningbeam-ui
+ cargo deb -p lightningbeam-editor --no-build --no-strip
+
+ # Inject factory presets into .deb (cargo-deb doesn't handle recursive dirs well)
+ DEB=$(ls target/debian/*.deb | head -1)
+ WORK=$(mktemp -d)
+ dpkg-deb -R "$DEB" "$WORK"
+ mkdir -p "$WORK/usr/share/lightningbeam-editor/presets"
+ cp -r lightningbeam-editor/assets/presets/* "$WORK/usr/share/lightningbeam-editor/presets/"
+ dpkg-deb -b "$WORK" "$DEB"
+ rm -rf "$WORK"
+
+ - name: Build .rpm package
+ if: matrix.platform == 'ubuntu-22.04'
+ shell: bash
+ run: |
+ cd lightningbeam-ui
+ cargo generate-rpm -p lightningbeam-editor
+
+ - name: Build AppImage
+ if: matrix.platform == 'ubuntu-22.04'
+ shell: bash
+ run: |
+ cd lightningbeam-ui
+ VERSION="${{ steps.version.outputs.version }}"
+ APPDIR=/tmp/AppDir
+ ASSETS=lightningbeam-editor/assets
+
+ rm -rf "$APPDIR"
+ mkdir -p "$APPDIR/usr/bin"
+ mkdir -p "$APPDIR/usr/bin/presets"
+ mkdir -p "$APPDIR/usr/share/applications"
+ mkdir -p "$APPDIR/usr/share/metainfo"
+ mkdir -p "$APPDIR/usr/share/icons/hicolor/32x32/apps"
+ mkdir -p "$APPDIR/usr/share/icons/hicolor/128x128/apps"
+ mkdir -p "$APPDIR/usr/share/icons/hicolor/256x256/apps"
+
+ cp target/release/lightningbeam-editor "$APPDIR/usr/bin/"
+ cp -r lightningbeam-editor/assets/presets/* "$APPDIR/usr/bin/presets/"
+
+ cp "$ASSETS/com.lightningbeam.editor.desktop" "$APPDIR/usr/share/applications/"
+ cp "$ASSETS/com.lightningbeam.editor.appdata.xml" "$APPDIR/usr/share/metainfo/"
+ cp "$ASSETS/icons/32x32.png" "$APPDIR/usr/share/icons/hicolor/32x32/apps/lightningbeam-editor.png"
+ cp "$ASSETS/icons/128x128.png" "$APPDIR/usr/share/icons/hicolor/128x128/apps/lightningbeam-editor.png"
+ cp "$ASSETS/icons/256x256.png" "$APPDIR/usr/share/icons/hicolor/256x256/apps/lightningbeam-editor.png"
+
+ ln -sf usr/share/icons/hicolor/256x256/apps/lightningbeam-editor.png "$APPDIR/lightningbeam-editor.png"
+ ln -sf usr/share/applications/com.lightningbeam.editor.desktop "$APPDIR/lightningbeam-editor.desktop"
+
+ printf '#!/bin/bash\nSELF=$(readlink -f "$0")\nHERE=${SELF%%/*}\nexport XDG_DATA_DIRS="${HERE}/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"\nexec "${HERE}/usr/bin/lightningbeam-editor" "$@"\n' > "$APPDIR/AppRun"
+ chmod +x "$APPDIR/AppRun"
+
+ # Download AppImage runtime
+ wget -q "https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-x86_64" \
+ -O /tmp/appimage-runtime
+ chmod +x /tmp/appimage-runtime
+
+ # Build squashfs and concatenate
+ mksquashfs "$APPDIR" /tmp/appimage.squashfs \
+ -root-owned -noappend -no-exports -no-xattrs \
+ -comp gzip -b 131072
+ cat /tmp/appimage-runtime /tmp/appimage.squashfs \
+ > "Lightningbeam_Editor-${VERSION}-x86_64.AppImage"
+ chmod +x "Lightningbeam_Editor-${VERSION}-x86_64.AppImage"
+
+ - name: Upload .deb
+ if: matrix.platform == 'ubuntu-22.04'
+ uses: actions/upload-artifact@v4
+ with:
+ name: deb-package
+ path: lightningbeam-ui/target/debian/*.deb
+ if-no-files-found: error
+
+ - name: Upload .rpm
+ if: matrix.platform == 'ubuntu-22.04'
+ uses: actions/upload-artifact@v4
+ with:
+ name: rpm-package
+ path: lightningbeam-ui/target/generate-rpm/*.rpm
+ if-no-files-found: error
+
+ - name: Upload AppImage
+ if: matrix.platform == 'ubuntu-22.04'
+ uses: actions/upload-artifact@v4
+ with:
+ name: appimage
+ path: lightningbeam-ui/Lightningbeam_Editor-*.AppImage
+ if-no-files-found: error
+
+ # ══════════════════════════════════════════════
+ # macOS Packaging
+ # ══════════════════════════════════════════════
+ - name: Create macOS .app bundle
+ if: startsWith(matrix.platform, 'macos')
+ shell: bash
+ run: |
+ VERSION="${{ steps.version.outputs.version }}"
+ APP="Lightningbeam Editor.app"
+ mkdir -p "$APP/Contents/MacOS"
+ mkdir -p "$APP/Contents/Resources/presets"
+
+ cp lightningbeam-ui/target/release/lightningbeam-editor "$APP/Contents/MacOS/"
+ cp src-tauri/icons/icon.icns "$APP/Contents/Resources/lightningbeam-editor.icns"
+ cp -r lightningbeam-ui/lightningbeam-editor/assets/presets/* "$APP/Contents/Resources/presets/"
+
+ cat > "$APP/Contents/Info.plist" << EOF
+
+
+
+
+ CFBundleName
+ Lightningbeam Editor
+ CFBundleDisplayName
+ Lightningbeam Editor
+ CFBundleIdentifier
+ com.lightningbeam.editor
+ CFBundleVersion
+ ${VERSION}
+ CFBundleShortVersionString
+ ${VERSION}
+ CFBundlePackageType
+ APPL
+ CFBundleExecutable
+ lightningbeam-editor
+ CFBundleIconFile
+ lightningbeam-editor
+ LSMinimumSystemVersion
+ 11.0
+ NSHighResolutionCapable
+
+
+
+ EOF
+
+ - name: Create macOS .dmg
+ if: startsWith(matrix.platform, 'macos')
+ shell: bash
+ run: |
+ VERSION="${{ steps.version.outputs.version }}"
+ ARCH="${{ matrix.target == 'x86_64-apple-darwin' && 'x86_64' || 'arm64' }}"
+ DMG_NAME="Lightningbeam_Editor-${VERSION}-macOS-${ARCH}.dmg"
+
+ create-dmg \
+ --volname "Lightningbeam Editor" \
+ --window-pos 200 120 \
+ --window-size 600 400 \
+ --icon-size 100 \
+ --icon "Lightningbeam Editor.app" 175 190 \
+ --app-drop-link 425 190 \
+ "$DMG_NAME" \
+ "Lightningbeam Editor.app" || true
+ # create-dmg returns non-zero if codesigning is skipped, but the .dmg is still valid
+
+ - name: Upload .dmg
+ if: startsWith(matrix.platform, 'macos')
+ uses: actions/upload-artifact@v4
+ with:
+ name: dmg-${{ matrix.artifact-name }}
+ path: Lightningbeam_Editor-*.dmg
+ if-no-files-found: error
+
+ # ══════════════════════════════════════════════
+ # Windows Packaging
+ # ══════════════════════════════════════════════
+ - name: Create Windows .zip
+ if: matrix.platform == 'windows-latest'
+ shell: pwsh
+ run: |
+ $VERSION = "${{ steps.version.outputs.version }}"
+ $DIST = "Lightningbeam_Editor-${VERSION}-Windows-x86_64"
+ New-Item -ItemType Directory -Force -Path $DIST
+ Copy-Item "lightningbeam-ui/target/release/lightningbeam-editor.exe" "$DIST/"
+ Copy-Item -Recurse "lightningbeam-ui/target/release/presets" "$DIST/presets"
+ # Bundle FFmpeg DLLs (shared build)
+ Copy-Item "$env:FFMPEG_DIR\bin\*.dll" "$DIST/"
+ Compress-Archive -Path $DIST -DestinationPath "${DIST}.zip"
+
+ - name: Upload .zip
+ if: matrix.platform == 'windows-latest'
+ uses: actions/upload-artifact@v4
+ with:
+ name: windows-zip
+ path: Lightningbeam_Editor-*.zip
+ if-no-files-found: error
+
+ release:
+ needs: build
+ runs-on: ubuntu-22.04
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: |
+ lightningbeam-ui/lightningbeam-editor/Cargo.toml
+ Changelog.md
+
+ - name: Extract version
+ id: version
+ run: |
+ VERSION=$(grep '^version' lightningbeam-ui/lightningbeam-editor/Cargo.toml | sed 's/.*"\(.*\)"/\1/')
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
+
+ - name: Extract release notes
+ id: notes
+ uses: sean0x42/markdown-extract@v2.1.0
+ with:
+ pattern: "${{ steps.version.outputs.version }}:"
+ file: Changelog.md
+
+ - name: Download all artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: dist
+ merge-multiple: true
+
+ - name: List artifacts
+ run: ls -lhR dist/
+
+ - name: Create draft release
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: "v${{ steps.version.outputs.version }}"
+ name: "Lightningbeam v${{ steps.version.outputs.version }}"
+ body: ${{ steps.notes.outputs.markdown }}
+ draft: true
+ prerelease: true
+ files: dist/*
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
deleted file mode 100644
index 657ee38..0000000
--- a/.github/workflows/main.yml
+++ /dev/null
@@ -1,150 +0,0 @@
-name: 'publish'
-
-on:
- workflow_dispatch:
- push:
- branches:
- - release
-
-jobs:
- extract-changelog:
- runs-on: ubuntu-22.04
- steps:
- - uses: actions/checkout@v4
-
- - name: Set version for changelog extraction
- shell: bash
- run: |
- # Read the version from src-tauri/tauri.conf.json
- VERSION=$(jq -r '.version' src-tauri/tauri.conf.json)
- # Set the version in the environment variable
- echo "VERSION=$VERSION" >> $GITHUB_ENV
-
- - name: Extract release notes from Changelog.md
- id: changelog
- uses: sean0x42/markdown-extract@v2.1.0
- with:
- pattern: "${{ env.VERSION }}:" # Look for the version header (e.g., # 0.6.15-alpha:)
- file: Changelog.md
-
- - name: Set markdown output
- id: set-markdown-output
- run: |
- echo 'RELEASE_NOTES<> $GITHUB_OUTPUT
- echo "${{ steps.changelog.outputs.markdown }}" >> $GITHUB_OUTPUT
- echo 'EOF' >> $GITHUB_OUTPUT
-
- publish-tauri:
- needs: extract-changelog
- permissions:
- contents: write
- strategy:
- fail-fast: false
- matrix:
- include:
- - platform: 'macos-latest' # for Arm based macs (M1 and above).
- args: '--target aarch64-apple-darwin'
- - platform: 'macos-latest' # for Intel based macs.
- args: '--target x86_64-apple-darwin'
- - platform: 'ubuntu-22.04'
- args: ''
- - platform: 'windows-latest'
- args: ''
-
- runs-on: ${{ matrix.platform }}
- steps:
- - uses: actions/checkout@v4
-
- - name: Debug the extracted release notes
- run: |
- echo "Extracted Release Notes: ${{ needs.extract-changelog.outputs.RELEASE_NOTES }}"
-
- - name: install dependencies (ubuntu only)
- if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above.
- run: |
- sudo apt-get update
- sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
-
- - name: Install jq on Windows
- if: matrix.platform == 'windows-latest'
- run: |
- choco install jq
-
- - name: Set version for all platforms
- shell: bash
- run: |
- # Read the version from src-tauri/tauri.conf.json
- VERSION=$(jq -r '.version' src-tauri/tauri.conf.json)
- # Set the version in the environment variable
- echo "VERSION=$VERSION" >> $GITHUB_ENV
- if: matrix.platform != 'windows-latest'
-
- - name: Set version for Windows build
- if: matrix.platform == 'windows-latest' # Only run on Windows
- shell: pwsh # Use PowerShell on Windows runners
- run: |
- # Read the version from src-tauri/tauri.conf.json
- $tauriConf = Get-Content src-tauri/tauri.conf.json | ConvertFrom-Json
- $VERSION = $tauriConf.version
-
- # Replace '-alpha' with '-0' and '-beta' with '-1' for Windows version
- if ($VERSION -match "-alpha") {
- $WINDOWS_VERSION = $VERSION -replace "-alpha", "-1"
- } elseif ($VERSION -match "-beta") {
- $WINDOWS_VERSION = $VERSION -replace "-beta", "-2"
- } else {
- $WINDOWS_VERSION = $VERSION
- }
- Copy-Item src-tauri/tauri.conf.json -Destination src-tauri/tauri.windows.conf.json
-
- # Modify the version in tauri.windows.conf.json
- (Get-Content src-tauri/tauri.windows.conf.json) | ForEach-Object {
- $_ -replace '"version": ".*"', ('"version": "' + $WINDOWS_VERSION + '"')
- } | Set-Content src-tauri/tauri.windows.conf.json
-
- echo "VERSION=$VERSION" >> $env:GITHUB_ENV
-
- - name: Print contents of tauri.windows.conf.json (Windows)
- if: matrix.platform == 'windows-latest' # Only run on Windows
- shell: pwsh
- run: |
- Write-Host "Contents of src-tauri/tauri.windows.conf.json:"
- Get-Content src-tauri/tauri.windows.conf.json
-
- - name: setup pnpm
- uses: pnpm/action-setup@v2
- with:
- version: 9.1.2
- - name: setup node
- uses: actions/setup-node@v4
- with:
- node-version: lts/*
- cache: 'pnpm' # Set this to npm, yarn or pnpm.
-
- - name: install Rust stable
- uses: dtolnay/rust-toolchain@stable # Set this to dtolnay/rust-toolchain@nightly
- with:
- # Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds.
- targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
-
- - name: Rust cache
- uses: swatinem/rust-cache@v2
- with:
- workspaces: './src-tauri -> target'
-
- - name: install frontend dependencies
- # If you don't have `beforeBuildCommand` configured you may want to build your frontend here too.
- run: pnpm install # change this to npm or pnpm depending on which one you use.
-
- - name: Create Release with Tauri Action
- uses: tauri-apps/tauri-action@v0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- RELEASE_NOTES: ${{ needs.extract-changelog.outputs.RELEASE_NOTES }}
- with:
- tagName: "app-v${{ env.VERSION }}" # Use the original version tag for the release
- releaseName: "Lightningbeam v${{ env.VERSION }}"
- releaseBody: "${{ needs.extract-changelog.outputs.RELEASE_NOTES }}"
- releaseDraft: true # Set to true if you want the release to be a draft
- prerelease: true
- args: ${{ matrix.args }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..35df03e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,43 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+# Git
+.gitignore
+
+# Build
+src-tauri/gen
+src-tauri/target
+lightningbeam-core/target
+daw-backend/target
+target/
+
+# Packaging build artifacts
+packaging/output/
+packaging/AppDir/
+packaging/squashfs-root/
+
+# Wrapper script (generated, not needed with static FFmpeg)
+lightningbeam-ui/lightningbeam-editor/debian/
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..e627048
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "vendor/NeuralAudio"]
+ path = vendor/NeuralAudio
+ url = https://github.com/mikeoliphant/NeuralAudio.git
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 0000000..7da90d8
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,538 @@
+# Lightningbeam Architecture
+
+This document provides a comprehensive overview of Lightningbeam's architecture, design decisions, and component interactions.
+
+## Table of Contents
+
+- [System Overview](#system-overview)
+- [Technology Stack](#technology-stack)
+- [Component Architecture](#component-architecture)
+- [Data Flow](#data-flow)
+- [Rendering Pipeline](#rendering-pipeline)
+- [Audio Architecture](#audio-architecture)
+- [Key Design Decisions](#key-design-decisions)
+- [Directory Structure](#directory-structure)
+
+## System Overview
+
+Lightningbeam is a 2D multimedia editor combining vector animation, audio production, and video editing. The application is built as a pure Rust desktop application using immediate-mode GUI (egui) with GPU-accelerated vector rendering (Vello).
+
+### High-Level Architecture
+
+```
+┌────────────────────────────────────────────────────────────┐
+│ Lightningbeam Editor │
+│ (egui UI) │
+├────────────────────────────────────────────────────────────┤
+│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
+│ │ Stage │ │ Timeline │ │ Asset │ │ Info │ │
+│ │ Pane │ │ Pane │ │ Library │ │ Panel │ │
+│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
+│ │
+│ ┌──────────────────────────────────────────────────────┐ │
+│ │ Lightningbeam Core (Data Model) │ │
+│ │ Document, Layers, Clips, Actions, Undo/Redo │ │
+│ └──────────────────────────────────────────────────────┘ │
+├────────────────────────────────────────────────────────────┤
+│ Rendering & Audio │
+│ ┌──────────────────┐ ┌──────────────────┐ │
+│ │ Vello + wgpu │ │ daw-backend │ │
+│ │ (GPU Rendering) │ │ (Audio Engine) │ │
+│ └──────────────────┘ └──────────────────┘ │
+└────────────────────────────────────────────────────────────┘
+ ↓ ↓
+ ┌─────────┐ ┌─────────┐
+ │ GPU │ │ cpal │
+ │ (Vulkan │ │ (Audio │
+ │ /Metal) │ │ I/O) │
+ └─────────┘ └─────────┘
+```
+
+### Migration from Tauri/JavaScript
+
+Lightningbeam is undergoing a rewrite from a Tauri/JavaScript prototype to pure Rust. The original architecture hit IPC bandwidth limitations when streaming decoded video frames. The new Rust UI eliminates this bottleneck by handling all rendering natively.
+
+**Current Status**: Active development on the `rust-ui` branch. Core UI, tools, and undo system are implemented. Audio integration in progress.
+
+## Technology Stack
+
+### UI Framework
+- **egui 0.33.3**: Immediate-mode GUI framework
+- **eframe 0.33.3**: Application framework wrapping egui
+- **winit 0.30**: Cross-platform windowing
+
+### GPU Rendering
+- **Vello (git main)**: GPU-accelerated 2D vector graphics using compute shaders
+- **wgpu 27**: Low-level GPU API (Vulkan/Metal backend)
+- **kurbo 0.12**: 2D curve and shape primitives
+- **peniko 0.5**: Color and brush definitions
+
+### Audio Engine
+- **daw-backend**: Custom real-time audio engine
+- **cpal 0.15**: Cross-platform audio I/O
+- **symphonia 0.5**: Audio decoding (MP3, FLAC, WAV, Ogg, etc.)
+- **rtrb 0.3**: Lock-free ringbuffers for audio thread communication
+- **dasp**: Audio graph processing
+
+### Video
+- **FFmpeg**: Video encoding/decoding (via ffmpeg-next)
+
+### Serialization
+- **serde**: Document serialization
+- **serde_json**: JSON format
+
+## Component Architecture
+
+### 1. Lightningbeam Core (`lightningbeam-core/`)
+
+The core crate contains the data model and business logic, independent of UI framework.
+
+**Key Types:**
+
+```rust
+Document {
+ canvas_size: (u32, u32),
+ layers: Vec,
+ undo_stack: Vec>,
+ redo_stack: Vec>,
+}
+
+Layer (enum) {
+ VectorLayer { clips: Vec, ... },
+ AudioLayer { clips: Vec, ... },
+ VideoLayer { clips: Vec, ... },
+}
+
+ClipInstance {
+ clip_id: Uuid, // Reference to clip definition
+ start_time: f64, // Timeline position
+ duration: f64,
+ trim_start: f64,
+ trim_end: f64,
+}
+```
+
+**Responsibilities:**
+- Document structure and state
+- Clip and layer management
+- Action system (undo/redo)
+- Tool definitions
+- Animation data and keyframes
+
+### 2. Lightningbeam Editor (`lightningbeam-editor/`)
+
+The editor application implements the UI and user interactions.
+
+**Main Entry Point:** `src/main.rs`
+- Initializes eframe application
+- Sets up window, GPU context, and audio system
+- Runs main event loop
+
+**Panes** (`src/panes/`):
+Each pane is a self-contained UI component:
+
+- `stage.rs` (214KB): Main canvas for drawing, transform tools, GPU rendering
+- `timeline.rs` (84KB): Multi-track timeline with clip editing
+- `asset_library.rs` (70KB): Asset browser with drag-and-drop
+- `infopanel.rs` (31KB): Context-sensitive property editor
+- `virtual_piano.rs` (31KB): MIDI keyboard input
+- `toolbar.rs` (9KB): Tool palette
+
+**Pane System:**
+```rust
+pub enum PaneInstance {
+ Stage(Stage),
+ Timeline(Timeline),
+ AssetLibrary(AssetLibrary),
+ // ... other panes
+}
+
+impl PaneInstance {
+ pub fn render(&mut self, ui: &mut Ui, shared_state: &mut SharedPaneState) {
+ match self {
+ PaneInstance::Stage(stage) => stage.render(ui, shared_state),
+ // ... dispatch to specific pane
+ }
+ }
+}
+```
+
+**SharedPaneState:**
+Facilitates communication between panes:
+```rust
+pub struct SharedPaneState {
+ pub document: Document,
+ pub selected_tool: Tool,
+ pub pending_actions: Vec>,
+ pub audio_system: AudioSystem,
+ // ... other shared state
+}
+```
+
+### 3. DAW Backend (`daw-backend/`)
+
+Standalone audio engine crate with real-time audio processing.
+
+**Architecture:**
+```
+UI Thread Audio Thread (real-time)
+ │ │
+ │ Commands (rtrb queue) │
+ ├──────────────────────────────>│
+ │ │
+ │ State Updates │
+ │<──────────────────────────────┤
+ │ │
+ ↓
+ ┌───────────────┐
+ │ Audio Engine │
+ │ process() │
+ └───────────────┘
+ ↓
+ ┌───────────────┐
+ │ Track Mix │
+ └───────────────┘
+ ↓
+ ┌───────────────┐
+ │ cpal Output │
+ └───────────────┘
+```
+
+**Key Components:**
+
+- **Engine** (`audio/engine.rs`): Main audio callback, runs on real-time thread
+- **Project** (`audio/project.rs`): Top-level audio state
+- **Track** (`audio/track.rs`): Individual audio tracks with effects chains
+- **Effects**: Reverb, delay, EQ, compressor, distortion, etc.
+- **Synthesizers**: Oscillator, FM synth, wavetable, sampler
+
+**Lock-Free Design:**
+The audio thread never blocks. UI sends commands via lock-free ringbuffers (rtrb), audio thread processes them between buffer callbacks.
+
+## Data Flow
+
+### Document Editing Flow
+
+```
+User Input (mouse/keyboard)
+ ↓
+egui Event Handlers (in pane.render())
+ ↓
+Create Action (implements Action trait)
+ ↓
+Add to SharedPaneState.pending_actions
+ ↓
+After all panes render: execute actions
+ ↓
+Action.apply(&mut document)
+ ↓
+Push to undo_stack
+ ↓
+UI re-renders with updated document
+```
+
+### Audio Playback Flow
+
+```
+UI: User clicks Play
+ ↓
+Send PlayCommand to audio engine (via rtrb queue)
+ ↓
+Audio thread: Receive command
+ ↓
+Audio thread: Start playback, increment playhead
+ ↓
+Audio callback (every ~5ms): Engine::process()
+ ↓
+Mix tracks, apply effects, output samples
+ ↓
+Send playhead position back to UI
+ ↓
+UI: Update timeline playhead position
+```
+
+### GPU Rendering Flow
+
+```
+egui layout phase
+ ↓
+Stage pane requests wgpu callback
+ ↓
+Vello renders vector shapes to GPU texture
+ ↓
+Custom wgpu integration composites:
+ - Vello output (vector graphics)
+ - Waveform textures (GPU-rendered audio)
+ - egui UI overlay
+ ↓
+Present to screen
+```
+
+## Rendering Pipeline
+
+### Stage Rendering
+
+The Stage pane uses a custom wgpu callback to render directly to GPU:
+
+```rust
+ui.painter().add(egui_wgpu::Callback::new_paint_callback(
+ rect,
+ StageCallback { /* render data */ }
+));
+```
+
+**Vello Integration:**
+1. Create Vello `Scene` from document shapes
+2. Render scene to GPU texture using compute shaders
+3. Composite with UI elements
+
+**Waveform Rendering:**
+- Audio waveforms rendered on GPU using custom WGSL shaders
+- Mipmaps generated via compute shader for level-of-detail
+- Uniform buffers store view parameters (zoom, offset, tint color)
+
+**WGSL Alignment Requirements:**
+WGSL has strict alignment rules. `vec4` requires 16-byte alignment:
+
+```rust
+#[repr(C)]
+#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
+struct WaveformParams {
+ view_matrix: [f32; 16], // 64 bytes
+ viewport_size: [f32; 2], // 8 bytes
+ zoom: f32, // 4 bytes
+ _pad1: f32, // 4 bytes padding
+ tint_color: [f32; 4], // 16 bytes (requires 16-byte alignment)
+}
+// Total: 96 bytes
+```
+
+## Audio Architecture
+
+### Real-Time Constraints
+
+Audio callbacks run on a dedicated real-time thread with strict timing requirements:
+- Buffer size: 256 frames default (~5.8ms at 44.1kHz)
+- ALSA may provide smaller buffers (64-75 frames, ~1.5ms)
+- **No blocking operations allowed**: No locks, no allocations, no syscalls
+
+### Lock-Free Communication
+
+UI and audio thread communicate via lock-free ringbuffers (rtrb):
+
+```rust
+// UI Thread
+command_sender.push(AudioCommand::Play).ok();
+
+// Audio Thread (in process callback)
+while let Ok(command) = command_receiver.pop() {
+ match command {
+ AudioCommand::Play => self.playing = true,
+ // ... handle other commands
+ }
+}
+```
+
+### Audio Processing Pipeline
+
+```
+Audio Callback Invoked (every ~5ms)
+ ↓
+Process queued commands
+ ↓
+For each track:
+ - Read audio samples at playhead position
+ - Apply effects chain
+ - Mix to master output
+ ↓
+Write samples to output buffer
+ ↓
+Return from callback (must complete in <5ms)
+```
+
+### Optimized Debug Builds
+
+Audio code is optimized even in debug builds to meet real-time deadlines:
+
+```toml
+[profile.dev.package.daw-backend]
+opt-level = 2
+
+[profile.dev.package.symphonia]
+opt-level = 2
+# ... other audio libraries
+```
+
+## Key Design Decisions
+
+### Layer & Clip System
+
+**Type-Specific Layers:**
+Each layer type supports only its matching clip type:
+- `VectorLayer` → `VectorClip`
+- `AudioLayer` → `AudioClip`
+- `VideoLayer` → `VideoClip`
+
+**Recursive Nesting:**
+Vector clips can contain internal layers of any type, enabling complex nested compositions.
+
+**Clip vs ClipInstance:**
+- **Clip**: Template/definition in asset library (the "master")
+- **ClipInstance**: Placed on timeline with instance-specific properties (position, duration, trim points)
+- Multiple instances can reference the same clip
+- "Make Unique" operation duplicates the underlying clip
+
+### Undo/Redo System
+
+**Action Trait:**
+```rust
+pub trait Action: Send {
+ fn apply(&mut self, document: &mut Document);
+ fn undo(&mut self, document: &mut Document);
+ fn redo(&mut self, document: &mut Document);
+}
+```
+
+All operations (drawing, editing, clip manipulation) implement this trait.
+
+**Continuous Operations:**
+Dragging sliders or scrubbing creates only one undo action when complete, not one per frame.
+
+### Two-Phase Dispatch Pattern
+
+Panes cannot directly mutate shared state during rendering (borrowing rules). Instead:
+
+1. **Phase 1 (Render)**: Panes register actions
+ ```rust
+ shared_state.register_action(Box::new(MyAction { ... }));
+ ```
+
+2. **Phase 2 (Execute)**: After all panes rendered, execute actions
+ ```rust
+ for action in shared_state.pending_actions.drain(..) {
+ action.apply(&mut document);
+ undo_stack.push(action);
+ }
+ ```
+
+### Pane ID Salting
+
+egui uses IDs to track widget state. Multiple instances of the same pane would collide without unique IDs.
+
+**Solution**: Salt all IDs with the pane's node path:
+```rust
+ui.horizontal(|ui| {
+ ui.label("My Widget");
+}).id.with(&node_path);
+```
+
+### Selection & Clipboard
+
+- **Selection scope**: Limited to current clip/layer
+- **Type-aware paste**: Content must match target type
+- **Clip instance copying**: Creates reference to same underlying clip
+- **Make unique**: Duplicates underlying clip for independent editing
+
+## Directory Structure
+
+```
+lightningbeam-2/
+├── lightningbeam-ui/ # Rust UI workspace
+│ ├── Cargo.toml # Workspace manifest
+│ ├── lightningbeam-editor/ # Main application crate
+│ │ ├── Cargo.toml
+│ │ └── src/
+│ │ ├── main.rs # Entry point, event loop
+│ │ ├── app.rs # Application state
+│ │ ├── panes/
+│ │ │ ├── mod.rs # Pane system dispatch
+│ │ │ ├── stage.rs # Main canvas
+│ │ │ ├── timeline.rs # Timeline editor
+│ │ │ ├── asset_library.rs
+│ │ │ └── ...
+│ │ ├── tools/ # Drawing and editing tools
+│ │ ├── rendering/
+│ │ │ ├── vello_integration.rs
+│ │ │ ├── waveform_gpu.rs
+│ │ │ └── shaders/
+│ │ │ ├── waveform.wgsl
+│ │ │ └── waveform_mipgen.wgsl
+│ │ └── export/ # Export functionality
+│ └── lightningbeam-core/ # Core data model crate
+│ ├── Cargo.toml
+│ └── src/
+│ ├── lib.rs
+│ ├── document.rs # Document structure
+│ ├── layer.rs # Layer types
+│ ├── clip.rs # Clip types and instances
+│ ├── shape.rs # Shape definitions
+│ ├── action.rs # Action trait and undo/redo
+│ ├── animation.rs # Keyframe animation
+│ └── tools.rs # Tool definitions
+│
+├── daw-backend/ # Audio engine (standalone)
+│ ├── Cargo.toml
+│ └── src/
+│ ├── lib.rs # Audio system initialization
+│ ├── audio/
+│ │ ├── engine.rs # Main audio callback
+│ │ ├── track.rs # Track management
+│ │ ├── project.rs # Project state
+│ │ └── buffer.rs # Audio buffer utilities
+│ ├── effects/ # Audio effects
+│ │ ├── reverb.rs
+│ │ ├── delay.rs
+│ │ └── ...
+│ ├── synth/ # Synthesizers
+│ └── midi/ # MIDI handling
+│
+├── src-tauri/ # Legacy Tauri backend
+├── src/ # Legacy JavaScript frontend
+├── CONTRIBUTING.md # Contributor guide
+├── ARCHITECTURE.md # This file
+├── README.md # Project overview
+└── docs/ # Additional documentation
+ ├── AUDIO_SYSTEM.md
+ ├── UI_SYSTEM.md
+ └── ...
+```
+
+## Performance Considerations
+
+### GPU Rendering
+- Vello uses compute shaders for efficient 2D rendering
+- Waveforms pre-rendered on GPU with mipmaps for smooth zooming
+- Custom wgpu integration minimizes CPU↔GPU data transfer
+
+### Audio Processing
+- Lock-free design: No blocking in audio thread
+- Optimized even in debug builds (`opt-level = 2`)
+- Memory-mapped file I/O for large audio files
+- Zero-copy audio buffers where possible
+
+### Memory Management
+- Audio buffers pre-allocated, no allocations in audio thread
+- Vello manages GPU memory automatically
+- Document structure uses `Rc`/`Arc` for shared clip references
+
+## Future Considerations
+
+### Video Integration
+Video decoding has been ported from the legacy Tauri backend. Video soundtracks become audio tracks in daw-backend, enabling full effects processing.
+
+### File Format
+The .beam file format is not yet finalized. Considerations:
+- Single JSON file vs container format (e.g., ZIP)
+- Embedded media vs external references
+- Forward/backward compatibility strategy
+
+### Node Editor
+Primary use: Audio effects chains and modular synthesizers. Future expansion to visual effects and procedural generation is possible.
+
+## Related Documentation
+
+- [CONTRIBUTING.md](CONTRIBUTING.md) - Development setup and workflow
+- [docs/AUDIO_SYSTEM.md](docs/AUDIO_SYSTEM.md) - Detailed audio engine documentation
+- [docs/UI_SYSTEM.md](docs/UI_SYSTEM.md) - UI pane system details
+- [docs/RENDERING.md](docs/RENDERING.md) - GPU rendering pipeline
+- [Claude.md](Claude.md) - Comprehensive architectural reference for AI assistants
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..12a96ec
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,278 @@
+# Contributing to Lightningbeam
+
+Thank you for your interest in contributing to Lightningbeam! This document provides guidelines and instructions for setting up your development environment and contributing to the project.
+
+## Table of Contents
+
+- [Development Setup](#development-setup)
+- [Building the Project](#building-the-project)
+- [Project Structure](#project-structure)
+- [Making Changes](#making-changes)
+- [Code Style](#code-style)
+- [Testing](#testing)
+- [Submitting Changes](#submitting-changes)
+- [Getting Help](#getting-help)
+
+## Development Setup
+
+### Prerequisites
+
+- **Rust**: Install via [rustup](https://rustup.rs/) (stable toolchain)
+- **System dependencies** (Linux):
+ - ALSA development files: `libasound2-dev`
+ - For Ubuntu/Debian: `sudo apt install libasound2-dev pkg-config`
+ - For Arch/Manjaro: `sudo pacman -S alsa-lib`
+- **FFmpeg**: Required for video encoding/decoding
+ - Ubuntu/Debian: `sudo apt install ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev pkg-config clang`
+ - Arch/Manjaro: `sudo pacman -S ffmpeg`
+
+### Clone and Build
+
+```bash
+# Clone the repository (GitHub)
+git clone https://github.com/skykooler/lightningbeam.git
+# Or from Gitea
+git clone https://git.skyler.io/skyler/lightningbeam.git
+
+cd lightningbeam
+
+# Build the Rust UI editor (current focus)
+cd lightningbeam-ui
+cargo build
+
+# Run the editor
+cargo run
+```
+
+**Note**: The project is hosted on both GitHub and Gitea (git.skyler.io). You can use either for cloning and submitting pull requests.
+
+## Building the Project
+
+### Workspace Structure
+
+The project consists of multiple Rust workspaces:
+
+1. **lightningbeam-ui** (current focus) - Pure Rust UI application
+ - `lightningbeam-editor/` - Main editor application
+ - `lightningbeam-core/` - Core data models and business logic
+
+2. **daw-backend** - Audio engine (standalone crate)
+
+3. **Root workspace** (legacy) - Contains Tauri backend and benchmarks
+
+### Build Commands
+
+```bash
+# Build the editor (from lightningbeam-ui/)
+cargo build
+
+# Build with optimizations (faster runtime)
+cargo build --release
+
+# Check just the audio backend
+cargo check -p daw-backend
+
+# Build the audio backend separately
+cd ../daw-backend
+cargo build
+```
+
+### Debug Builds and Audio Performance
+
+The audio engine runs on a real-time thread with strict timing constraints (~5.8ms at 44.1kHz). To maintain performance in debug builds, the audio backend is compiled with optimizations even in debug mode:
+
+```toml
+# In lightningbeam-ui/Cargo.toml
+[profile.dev.package.daw-backend]
+opt-level = 2
+```
+
+This is already configured—no action needed.
+
+### Debug Flags
+
+Enable audio diagnostics with:
+```bash
+DAW_AUDIO_DEBUG=1 cargo run
+```
+
+This prints timing information, buffer sizes, and overrun warnings to help debug audio issues.
+
+## Project Structure
+
+```
+lightningbeam-2/
+├── lightningbeam-ui/ # Rust UI workspace (current)
+│ ├── lightningbeam-editor/ # Main application
+│ │ └── src/
+│ │ ├── main.rs # Entry point
+│ │ ├── panes/ # UI panes (stage, timeline, etc.)
+│ │ └── tools/ # Drawing and editing tools
+│ └── lightningbeam-core/ # Core data model
+│ └── src/
+│ ├── document.rs # Document structure
+│ ├── clip.rs # Clips and instances
+│ ├── action.rs # Undo/redo system
+│ └── tools.rs # Tool system
+├── daw-backend/ # Audio engine
+│ └── src/
+│ ├── lib.rs # Audio system setup
+│ ├── audio/
+│ │ ├── engine.rs # Audio callback
+│ │ ├── track.rs # Track management
+│ │ └── project.rs # Project state
+│ └── effects/ # Audio effects
+├── src-tauri/ # Legacy Tauri backend
+└── src/ # Legacy JavaScript frontend
+```
+
+## Making Changes
+
+### Branching Strategy
+
+- `main` - Stable branch
+- `rust-ui` - Active development branch for Rust UI rewrite
+- Feature branches - Create from `rust-ui` for new features
+
+### Before You Start
+
+1. Check existing issues or create a new one to discuss your change
+2. Make sure you're on the latest `rust-ui` branch:
+ ```bash
+ git checkout rust-ui
+ git pull origin rust-ui
+ ```
+3. Create a feature branch:
+ ```bash
+ git checkout -b feature/your-feature-name
+ ```
+
+## Code Style
+
+### Rust Style
+
+- Follow standard Rust formatting: `cargo fmt`
+- Check for common issues: `cargo clippy`
+- Use meaningful variable names
+- Add comments for non-obvious code
+- Keep functions focused and reasonably sized
+
+### Key Patterns
+
+#### Pane ID Salting
+When implementing new panes, **always salt egui IDs** with the node path to avoid collisions when users add multiple instances of the same pane:
+
+```rust
+ui.horizontal(|ui| {
+ ui.label("My Widget");
+}).id.with(&node_path); // Salt with node path
+```
+
+#### Splitting Borrows with `std::mem::take`
+When you need to split borrows from a struct, use `std::mem::take`:
+
+```rust
+let mut clips = std::mem::take(&mut self.clips);
+// Now you can borrow other fields while processing clips
+```
+
+#### Two-Phase Dispatch
+Panes register handlers during render, execution happens after:
+
+```rust
+// During render
+shared_state.register_action(Box::new(MyAction { ... }));
+
+// After all panes rendered
+for action in shared_state.pending_actions.drain(..) {
+ action.execute(&mut document);
+}
+```
+
+## Testing
+
+### Running Tests
+
+```bash
+# Run all tests
+cargo test
+
+# Test specific package
+cargo test -p lightningbeam-core
+cargo test -p daw-backend
+
+# Run with output
+cargo test -- --nocapture
+```
+
+### Audio Testing
+
+Test audio functionality:
+```bash
+# Run with audio debug output
+DAW_AUDIO_DEBUG=1 cargo run
+
+# Check for audio dropouts or timing issues in the console output
+```
+
+## Submitting Changes
+
+### Before Submitting
+
+1. **Format your code**: `cargo fmt --all`
+2. **Run clippy**: `cargo clippy --all-targets --all-features`
+3. **Run tests**: `cargo test --all`
+4. **Test manually**: Build and run the application to verify your changes work
+5. **Write clear commit messages**: Describe what and why, not just what
+
+### Commit Message Format
+
+```
+Short summary (50 chars or less)
+
+More detailed explanation if needed. Wrap at 72 characters.
+Explain the problem this commit solves and why you chose
+this solution.
+
+- Bullet points are fine
+- Use present tense: "Add feature" not "Added feature"
+```
+
+### Pull Request Process
+
+1. Push your branch to GitHub or Gitea
+2. Open a pull request against `rust-ui` branch
+ - GitHub: https://github.com/skykooler/lightningbeam
+ - Gitea: https://git.skyler.io/skyler/lightningbeam
+3. Provide a clear description of:
+ - What problem does this solve?
+ - How does it work?
+ - Any testing you've done
+ - Screenshots/videos if applicable (especially for UI changes)
+4. Address review feedback
+5. Once approved, a maintainer will merge your PR
+
+### PR Checklist
+
+- [ ] Code follows project style (`cargo fmt`, `cargo clippy`)
+- [ ] Tests pass (`cargo test`)
+- [ ] New code has appropriate tests (if applicable)
+- [ ] Documentation updated (if needed)
+- [ ] Commit messages are clear
+- [ ] PR description explains the change
+
+## Getting Help
+
+- **Issues**: Check issues on [GitHub](https://github.com/skykooler/lightningbeam/issues) or [Gitea](https://git.skyler.io/skyler/lightningbeam/issues) for existing discussions
+- **Documentation**: See `ARCHITECTURE.md` and `docs/` folder for technical details
+- **Questions**: Open a discussion or issue with the "question" label on either platform
+
+## Additional Resources
+
+- [ARCHITECTURE.md](ARCHITECTURE.md) - System architecture overview
+- [docs/AUDIO_SYSTEM.md](docs/AUDIO_SYSTEM.md) - Audio engine details
+- [docs/UI_SYSTEM.md](docs/UI_SYSTEM.md) - UI and pane system
+
+## License
+
+By contributing, you agree that your contributions will be licensed under the same license as the project.
diff --git a/Changelog.md b/Changelog.md
index af0e374..6e89aad 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,73 @@
+# 1.0.3-alpha:
+Changes:
+- Add gradient support to vector graphics
+- Add "frames" timeline mode
+- Reduce CPU usage at idle
+- Allow group tracks' audio node graphs to be edited
+
+Bugfixes:
+- Support Vello CPU fallback on systems with older GPUs
+
+# 1.0.2-alpha:
+Changes:
+- All vector shapes on a layer go into a unified shape rather than separate shapes
+- Keyboard shortcuts are now user-configurable
+- Added webcam support in video editor
+- Background can now be transparent
+- Video thumbnails are now displayed on the clip
+- Virtual keyboard, piano roll and node editor now have a quick switcher
+- Add electric guitar preset
+- Layers can now be grouped
+- Layers can be reordered by dragging
+- Added VU meters to audio layers and mix
+- Added raster image editing
+- Added brush, airbrush, dodge/burn, sponge, pattern stamp, healing brush, clone stamp, blur/sharpen, magic wand and quick select tools
+- Added support for MyPaint .myb brushes
+- UI now uses CSS styling to support future user styles
+- Added image export
+
+Bugfixes:
+- Toolbar now only shows tools that can be used on the current layer
+- Fix NAM model loading
+- Fix menu width and mouse following
+- Export dialog now remembers the previous export filename
+
+# 1.0.1-alpha:
+Changes:
+- Added real-time amp simulation via NAM
+- Added beat mode to the timeline
+- Changed shape drawing from making separate shapes to making shapes in the layer using a DCEL graph
+- Licensed under GPLv3
+- Added snapping for vector editing
+- Added organ instrument and vibrato node
+
+Bugfixes:
+- Fix preset loading not updating node graph editor
+- Fix stroke intersections not splitting strokes
+- Fix paint bucket fill not attaching to existing strokes
+
+# 1.0.0-alpha:
+Changes:
+- New native GUI built with egui + wgpu (replaces Tauri/web frontend)
+- GPU-accelerated canvas with vello rendering
+- MIDI input and node-based audio graph improvements
+- Factory instrument presets
+- Video import and high performance playback
+
+# 0.8.1-alpha:
+Changes:
+- Rewrite timeline UI
+- Add start screen
+- Move audio engine to backend
+- Add node editor for audio synthesis
+- Add factory presets for instruments
+- Add MIDI input support
+- Add BPM handling and time signature
+- Add metronome
+- Add preset layouts for different tasks
+- Add video import
+- Add animation curves for object properties
+
# 0.7.14-alpha:
Changes:
- Moving frames can now be undone
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/README.md b/README.md
index 36d8496..cf9afb3 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,127 @@
-# Lightningbeam 2
+# Lightningbeam
-This README needs content. This is Lightningbeam rewritten with Tauri.
+A free and open-source 2D multimedia editor combining vector animation, audio production, and video editing in a single application.
-To test:
+## Screenshots
-`pnpm tauri dev`
\ No newline at end of file
+
+
+
+
+
+
+## Features
+
+**Vector Animation**
+- GPU-accelerated vector rendering with Vello
+- Draw and animate vector shapes with keyframe-based timeline
+- Non-destructive editing workflow
+- Paint bucket tool for automatic fill detection
+
+**Audio Production**
+- Real-time multi-track audio recording and playback
+- Node graph-based effects processing
+- MIDI sequencing with synthesizers and samplers
+- Comprehensive effects library (reverb, delay, EQ, compression, distortion, etc.)
+- Custom audio engine with lock-free design for glitch-free playback
+
+**Video Editing**
+- Video timeline and editing with FFmpeg-based decoding
+- GPU-accelerated waveform rendering with mipmaps
+- Audio integration from video soundtracks
+
+## Technical Stack
+
+**Current Implementation (Rust UI)**
+- **UI Framework:** egui (immediate-mode GUI)
+- **GPU Rendering:** Vello + wgpu (Vulkan/Metal/DirectX 12)
+- **Audio Engine:** Custom real-time engine (`daw-backend`)
+ - cpal for cross-platform audio I/O
+ - symphonia for audio decoding
+ - dasp for node graph processing
+- **Video:** FFmpeg 8 for encode/decode
+- **Platform:** Cross-platform (Linux, macOS, Windows)
+
+**Legacy Implementation (Deprecated)**
+- Frontend: Vanilla JavaScript
+- Backend: Rust (Tauri framework)
+
+## Project Status
+
+Lightningbeam is under active development on the `rust-ui` branch. The project has been rewritten from a Tauri/JavaScript prototype to a pure Rust application to eliminate IPC bottlenecks and achieve better performance for real-time video and audio processing.
+
+**Current Status:**
+- ✅ Core UI panes (Stage, Timeline, Asset Library, Info Panel, Toolbar)
+- ✅ Drawing tools (Select, Draw, Rectangle, Ellipse, Paint Bucket, Transform)
+- ✅ Undo/redo system
+- ✅ GPU-accelerated vector rendering
+- ✅ Audio engine with node graph processing
+- ✅ GPU waveform rendering with mipmaps
+- ✅ Video decoding integration
+- 🚧 Export system (in progress)
+- 🚧 Node editor UI (planned)
+- 🚧 Piano roll editor (planned)
+
+## Getting Started
+
+### Prerequisites
+
+- Rust (stable toolchain via [rustup](https://rustup.rs/))
+- System dependencies:
+ - **Linux:** ALSA development files, FFmpeg 8
+ - **macOS:** FFmpeg (via Homebrew)
+ - **Windows:** FFmpeg 8, Visual Studio with C++ tools
+
+See [docs/BUILDING.md](docs/BUILDING.md) for detailed setup instructions.
+
+### Building and Running
+
+```bash
+# Clone the repository
+git clone https://github.com/skykooler/lightningbeam.git
+# Or from Gitea
+git clone https://git.skyler.io/skyler/lightningbeam.git
+
+cd lightningbeam/lightningbeam-ui
+
+# Build and run
+cargo run
+
+# Or build optimized release version
+cargo build --release
+```
+
+### Documentation
+
+- **[CONTRIBUTING.md](CONTRIBUTING.md)** - Development setup and contribution guidelines
+- **[ARCHITECTURE.md](ARCHITECTURE.md)** - System architecture overview
+- **[docs/BUILDING.md](docs/BUILDING.md)** - Detailed build instructions and troubleshooting
+- **[docs/AUDIO_SYSTEM.md](docs/AUDIO_SYSTEM.md)** - Audio engine architecture and development
+- **[docs/UI_SYSTEM.md](docs/UI_SYSTEM.md)** - UI pane system and tool development
+- **[docs/RENDERING.md](docs/RENDERING.md)** - GPU rendering pipeline and shaders
+
+## Project History
+
+Lightningbeam evolved from earlier multimedia editing projects I've worked on since 2010, including the FreeJam DAW. The JavaScript/Tauri prototype began in November 2023, and the Rust UI rewrite started in late 2024 to eliminate performance bottlenecks and provide a more integrated native experience.
+
+## Goals
+
+Create a comprehensive FOSS alternative for 2D-focused multimedia work, integrating animation, audio, and video editing in a unified workflow. Lightningbeam aims to be:
+
+- **Fast:** GPU-accelerated rendering and real-time audio processing
+- **Flexible:** Node graph-based audio routing and modular synthesis
+- **Integrated:** Seamless workflow across animation, audio, and video
+- **Open:** Free and open-source, built on open standards
+
+## Contributing
+
+Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
+
+## License
+
+[License information to be added]
+
+## Links
+
+- **GitHub:** https://github.com/skykooler/lightningbeam
+- **Gitea:** https://git.skyler.io/skyler/lightningbeam
diff --git a/daw-backend/C2.mp3 b/daw-backend/C2.mp3
new file mode 100644
index 0000000..3fca8d0
Binary files /dev/null and b/daw-backend/C2.mp3 differ
diff --git a/daw-backend/Cargo.lock b/daw-backend/Cargo.lock
new file mode 100644
index 0000000..6399b8d
--- /dev/null
+++ b/daw-backend/Cargo.lock
@@ -0,0 +1,2484 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "alsa"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2562ad8dcf0f789f65c6fdaad8a8a9708ed6b488e649da28c01656ad66b8b47"
+dependencies = [
+ "alsa-sys",
+ "bitflags 1.3.2",
+ "libc",
+ "nix",
+]
+
+[[package]]
+name = "alsa"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c88dbbce13b232b26250e1e2e6ac18b6a891a646b8148285036ebce260ac5c3"
+dependencies = [
+ "alsa-sys",
+ "bitflags 2.9.4",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "alsa-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64ct"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
+
+[[package]]
+name = "beamdsp"
+version = "0.1.0"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.72.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
+dependencies = [
+ "bitflags 2.9.4",
+ "cexpr",
+ "clang-sys",
+ "itertools 0.13.0",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
+dependencies = [
+ "objc2",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+
+[[package]]
+name = "bytemuck"
+version = "1.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[package]]
+name = "bzip2"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
+dependencies = [
+ "bzip2-sys",
+ "libc",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.13+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "castaway"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cesu8"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "compact_str"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
+dependencies = [
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "ryu",
+ "static_assertions",
+]
+
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "coreaudio-rs"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aae284fbaf7d27aa0e292f7677dfbe26503b0d555026f702940805a630eac17"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+ "objc2-audio-toolbox",
+ "objc2-core-audio",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "coremidi"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a7847ca018a67204508b77cb9e6de670125075f7464fff5f673023378fa34f5"
+dependencies = [
+ "core-foundation",
+ "core-foundation-sys",
+ "coremidi-sys",
+]
+
+[[package]]
+name = "coremidi-sys"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc9504310988d938e49fff1b5f1e56e3dafe39bb1bae580c19660b58b83a191e"
+dependencies = [
+ "core-foundation-sys",
+]
+
+[[package]]
+name = "cpal"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b1f9c7312f19fc2fa12fd7acaf38de54e8320ba10d1a02dcbe21038def51ccb"
+dependencies = [
+ "alsa 0.10.0",
+ "coreaudio-rs",
+ "dasp_sample",
+ "jni",
+ "js-sys",
+ "libc",
+ "mach2",
+ "ndk",
+ "ndk-context",
+ "num-derive",
+ "num-traits",
+ "objc2",
+ "objc2-audio-toolbox",
+ "objc2-avf-audio",
+ "objc2-core-audio",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows 0.62.2",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crossterm"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
+dependencies = [
+ "bitflags 2.9.4",
+ "crossterm_winapi",
+ "libc",
+ "mio",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "dasp_envelope"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ec617ce7016f101a87fe85ed44180839744265fae73bb4aa43e7ece1b7668b6"
+dependencies = [
+ "dasp_frame",
+ "dasp_peak",
+ "dasp_ring_buffer",
+ "dasp_rms",
+ "dasp_sample",
+]
+
+[[package]]
+name = "dasp_frame"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a3937f5fe2135702897535c8d4a5553f8b116f76c1529088797f2eee7c5cd6"
+dependencies = [
+ "dasp_sample",
+]
+
+[[package]]
+name = "dasp_graph"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39b17b071a1fa4c78054730085620c3bb22dc5fded00483312557a3fdf26d7c4"
+dependencies = [
+ "dasp_frame",
+ "dasp_ring_buffer",
+ "dasp_signal",
+ "dasp_slice",
+ "petgraph 0.5.1",
+]
+
+[[package]]
+name = "dasp_interpolate"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc975a6563bb7ca7ec0a6c784ead49983a21c24835b0bc96eea11ee407c7486"
+dependencies = [
+ "dasp_frame",
+ "dasp_ring_buffer",
+ "dasp_sample",
+]
+
+[[package]]
+name = "dasp_peak"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cf88559d79c21f3d8523d91250c397f9a15b5fc72fbb3f87fdb0a37b79915bf"
+dependencies = [
+ "dasp_frame",
+ "dasp_sample",
+]
+
+[[package]]
+name = "dasp_ring_buffer"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07d79e19b89618a543c4adec9c5a347fe378a19041699b3278e616e387511ea1"
+
+[[package]]
+name = "dasp_rms"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6c5dcb30b7e5014486e2822537ea2beae50b19722ffe2ed7549ab03774575aa"
+dependencies = [
+ "dasp_frame",
+ "dasp_ring_buffer",
+ "dasp_sample",
+]
+
+[[package]]
+name = "dasp_sample"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
+
+[[package]]
+name = "dasp_signal"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa1ab7d01689c6ed4eae3d38fe1cea08cba761573fbd2d592528d55b421077e7"
+dependencies = [
+ "dasp_envelope",
+ "dasp_frame",
+ "dasp_interpolate",
+ "dasp_peak",
+ "dasp_ring_buffer",
+ "dasp_rms",
+ "dasp_sample",
+ "dasp_window",
+]
+
+[[package]]
+name = "dasp_slice"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e1c7335d58e7baedafa516cb361360ff38d6f4d3f9d9d5ee2a2fc8e27178fa1"
+dependencies = [
+ "dasp_frame",
+ "dasp_sample",
+]
+
+[[package]]
+name = "dasp_window"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99ded7b88821d2ce4e8b842c9f1c86ac911891ab89443cc1de750cae764c5076"
+dependencies = [
+ "dasp_sample",
+]
+
+[[package]]
+name = "daw-backend"
+version = "0.1.0"
+dependencies = [
+ "base64",
+ "beamdsp",
+ "cpal",
+ "crossterm",
+ "dasp_envelope",
+ "dasp_graph",
+ "dasp_interpolate",
+ "dasp_peak",
+ "dasp_ring_buffer",
+ "dasp_rms",
+ "dasp_sample",
+ "dasp_signal",
+ "ffmpeg-next",
+ "hound",
+ "memmap2",
+ "midir",
+ "midly",
+ "nam-ffi",
+ "pathdiff",
+ "petgraph 0.6.5",
+ "rand",
+ "ratatui",
+ "rayon",
+ "rtrb",
+ "serde",
+ "serde_json",
+ "symphonia",
+ "zip",
+]
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "dispatch2"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
+dependencies = [
+ "bitflags 2.9.4",
+ "objc2",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "extended"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
+
+[[package]]
+name = "ffmpeg-next"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d658424d233cbd993a972dd73a66ca733acd12a494c68995c9ac32ae1fe65b40"
+dependencies = [
+ "bitflags 2.9.4",
+ "ffmpeg-sys-next",
+ "libc",
+]
+
+[[package]]
+name = "ffmpeg-sys-next"
+version = "8.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bca20aa4ee774fe384c2490096c122b0b23cf524a9910add0686691003d797b"
+dependencies = [
+ "bindgen",
+ "cc",
+ "libc",
+ "num_cpus",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
+
+[[package]]
+name = "fixedbitset"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
+
+[[package]]
+name = "fixedbitset"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
+
+[[package]]
+name = "flate2"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "hound"
+version = "3.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.16.0",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "jni"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
+dependencies = [
+ "cesu8",
+ "cfg-if",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror",
+ "walkdir",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.81"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.177"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+
+[[package]]
+name = "lru"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
+dependencies = [
+ "hashbrown 0.15.5",
+]
+
+[[package]]
+name = "mach2"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a1b95cd5421ec55b445b5ae102f5ea0e768de1f82bd3001e11f426c269c3aea"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
+name = "memmap2"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "midir"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a456444d83e7ead06ae6a5c0a215ed70282947ff3897fb45fcb052b757284731"
+dependencies = [
+ "alsa 0.7.1",
+ "bitflags 1.3.2",
+ "coremidi",
+ "js-sys",
+ "libc",
+ "wasm-bindgen",
+ "web-sys",
+ "windows 0.43.0",
+]
+
+[[package]]
+name = "midly"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "207d755f4cb882d20c4da58d707ca9130a0c9bc5061f657a4f299b8e36362b7a"
+dependencies = [
+ "rayon",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+ "simd-adler32",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "nam-ffi"
+version = "0.1.0"
+dependencies = [
+ "cmake",
+]
+
+[[package]]
+name = "ndk"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
+dependencies = [
+ "bitflags 2.9.4",
+ "jni-sys",
+ "log",
+ "ndk-sys",
+ "num_enum",
+ "thiserror",
+]
+
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
+[[package]]
+name = "ndk-sys"
+version = "0.6.0+11769913"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "nix"
+version = "0.24.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
+dependencies = [
+ "bitflags 1.3.2",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
+dependencies = [
+ "num_enum_derive",
+ "rustversion",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "objc2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-audio-toolbox"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08"
+dependencies = [
+ "bitflags 2.9.4",
+ "libc",
+ "objc2",
+ "objc2-core-audio",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-avf-audio"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-audio"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2"
+dependencies = [
+ "dispatch2",
+ "objc2",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-audio-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c"
+dependencies = [
+ "bitflags 2.9.4",
+ "objc2",
+]
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
+dependencies = [
+ "bitflags 2.9.4",
+ "block2",
+ "dispatch2",
+ "libc",
+ "objc2",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
+
+[[package]]
+name = "objc2-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
+dependencies = [
+ "bitflags 2.9.4",
+ "block2",
+ "libc",
+ "objc2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
+dependencies = [
+ "base64ct",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pathdiff"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+
+[[package]]
+name = "pbkdf2"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
+dependencies = [
+ "digest",
+ "hmac",
+ "password-hash",
+ "sha2",
+]
+
+[[package]]
+name = "petgraph"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+dependencies = [
+ "fixedbitset 0.2.0",
+ "indexmap 1.9.3",
+]
+
+[[package]]
+name = "petgraph"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
+dependencies = [
+ "fixedbitset 0.4.2",
+ "indexmap 2.11.4",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.16",
+]
+
+[[package]]
+name = "ratatui"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef"
+dependencies = [
+ "bitflags 2.9.4",
+ "cassowary",
+ "compact_str",
+ "crossterm",
+ "itertools 0.12.1",
+ "lru",
+ "paste",
+ "stability",
+ "strum",
+ "unicode-segmentation",
+ "unicode-truncate",
+ "unicode-width",
+]
+
+[[package]]
+name = "rayon"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags 2.9.4",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
+
+[[package]]
+name = "rtrb"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad8388ea1a9e0ea807e442e8263a699e7edcb320ecbcd21b4fa8ff859acce3ba"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.145"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signal-hook"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "stability"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "symphonia"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5773a4c030a19d9bfaa090f49746ff35c75dfddfa700df7a5939d5e076a57039"
+dependencies = [
+ "lazy_static",
+ "symphonia-bundle-flac",
+ "symphonia-bundle-mp3",
+ "symphonia-codec-aac",
+ "symphonia-codec-adpcm",
+ "symphonia-codec-alac",
+ "symphonia-codec-pcm",
+ "symphonia-codec-vorbis",
+ "symphonia-core",
+ "symphonia-format-caf",
+ "symphonia-format-isomp4",
+ "symphonia-format-mkv",
+ "symphonia-format-ogg",
+ "symphonia-format-riff",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-bundle-flac"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c91565e180aea25d9b80a910c546802526ffd0072d0b8974e3ebe59b686c9976"
+dependencies = [
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-bundle-mp3"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4872dd6bb56bf5eac799e3e957aa1981086c3e613b27e0ac23b176054f7c57ed"
+dependencies = [
+ "lazy_static",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-codec-aac"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c263845aa86881416849c1729a54c7f55164f8b96111dba59de46849e73a790"
+dependencies = [
+ "lazy_static",
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-adpcm"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dddc50e2bbea4cfe027441eece77c46b9f319748605ab8f3443350129ddd07f"
+dependencies = [
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-alac"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8413fa754942ac16a73634c9dfd1500ed5c61430956b33728567f667fdd393ab"
+dependencies = [
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-pcm"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e89d716c01541ad3ebe7c91ce4c8d38a7cf266a3f7b2f090b108fb0cb031d95"
+dependencies = [
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-vorbis"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f025837c309cd69ffef572750b4a2257b59552c5399a5e49707cc5b1b85d1c73"
+dependencies = [
+ "log",
+ "symphonia-core",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-core"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea00cc4f79b7f6bb7ff87eddc065a1066f3a43fe1875979056672c9ef948c2af"
+dependencies = [
+ "arrayvec",
+ "bitflags 1.3.2",
+ "bytemuck",
+ "lazy_static",
+ "log",
+]
+
+[[package]]
+name = "symphonia-format-caf"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8faf379316b6b6e6bbc274d00e7a592e0d63ff1a7e182ce8ba25e24edd3d096"
+dependencies = [
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-format-isomp4"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "243739585d11f81daf8dac8d9f3d18cc7898f6c09a259675fc364b382c30e0a5"
+dependencies = [
+ "encoding_rs",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-format-mkv"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "122d786d2c43a49beb6f397551b4a050d8229eaa54c7ddf9ee4b98899b8742d0"
+dependencies = [
+ "lazy_static",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-format-ogg"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b4955c67c1ed3aa8ae8428d04ca8397fbef6a19b2b051e73b5da8b1435639cb"
+dependencies = [
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-format-riff"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2d7c3df0e7d94efb68401d81906eae73c02b40d5ec1a141962c592d0f11a96f"
+dependencies = [
+ "extended",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-metadata"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36306ff42b9ffe6e5afc99d49e121e0bd62fe79b9db7b9681d48e29fa19e6b16"
+dependencies = [
+ "encoding_rs",
+ "lazy_static",
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-utils-xiph"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee27c85ab799a338446b68eec77abf42e1a6f1bb490656e121c6e27bfbab9f16"
+dependencies = [
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "time"
+version = "0.3.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
+dependencies = [
+ "deranged",
+ "num-conv",
+ "powerfmt",
+ "serde_core",
+ "time-core",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
+
+[[package]]
+name = "toml_datetime"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.23.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d"
+dependencies = [
+ "indexmap 2.11.4",
+ "toml_datetime",
+ "toml_parser",
+ "winnow",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "typenum"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "unicode-truncate"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
+dependencies = [
+ "itertools 0.13.0",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.2+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.81"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.43.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
+dependencies = [
+ "windows-collections",
+ "windows-core",
+ "windows-future",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
+dependencies = [
+ "windows-core",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
+dependencies = [
+ "windows-core",
+ "windows-link",
+ "windows-threading",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-numerics"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
+dependencies = [
+ "windows-core",
+ "windows-link",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-threading"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "winnow"
+version = "0.7.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zip"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
+dependencies = [
+ "aes",
+ "byteorder",
+ "bzip2",
+ "constant_time_eq",
+ "crc32fast",
+ "crossbeam-utils",
+ "flate2",
+ "hmac",
+ "pbkdf2",
+ "sha1",
+ "time",
+ "zstd",
+]
+
+[[package]]
+name = "zstd"
+version = "0.11.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "5.0.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
+dependencies = [
+ "libc",
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.16+zstd.1.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
diff --git a/daw-backend/Cargo.toml b/daw-backend/Cargo.toml
new file mode 100644
index 0000000..1878591
--- /dev/null
+++ b/daw-backend/Cargo.toml
@@ -0,0 +1,53 @@
+[package]
+name = "daw-backend"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+cpal = "0.17"
+symphonia = { version = "0.5", features = ["all"] }
+rtrb = "0.3"
+midly = "0.5"
+midir = "0.9"
+serde = { version = "1.0", features = ["derive"] }
+ratatui = "0.26"
+crossterm = "0.27"
+rand = "0.8"
+base64 = "0.22"
+pathdiff = "0.2"
+rayon = "1.10"
+
+# Memory-mapped I/O for audio files
+memmap2 = "0.9"
+
+# Audio export
+hound = "3.5"
+ffmpeg-next = "8.0" # For MP3/AAC encoding
+
+# Node-based audio graph dependencies
+dasp_graph = "0.11"
+dasp_signal = "0.11"
+dasp_sample = "0.11"
+dasp_interpolate = "0.11"
+dasp_envelope = "0.11"
+dasp_ring_buffer = "0.11"
+dasp_peak = "0.11"
+dasp_rms = "0.11"
+petgraph = "0.6"
+serde_json = "1.0"
+zip = "0.6"
+
+# BeamDSP scripting engine
+beamdsp = { path = "../lightningbeam-ui/beamdsp" }
+
+# Neural Amp Modeler FFI
+nam-ffi = { path = "../nam-ffi" }
+
+[dev-dependencies]
+
+[profile.release]
+opt-level = 3
+lto = true
+
+[profile.dev]
+opt-level = 1 # Faster compile times while still reasonable performance
diff --git a/daw-backend/darude-sandstorm.mid b/daw-backend/darude-sandstorm.mid
new file mode 100644
index 0000000..f9a99b0
Binary files /dev/null and b/daw-backend/darude-sandstorm.mid differ
diff --git a/daw-backend/daw_architecture_doc.md b/daw-backend/daw_architecture_doc.md
new file mode 100644
index 0000000..f921f12
--- /dev/null
+++ b/daw-backend/daw_architecture_doc.md
@@ -0,0 +1,1807 @@
+# DAW Backend Architecture & Implementation Roadmap
+
+**Version:** 1.0
+**Date:** October 2025
+**Language:** Rust
+**Audio I/O:** cpal
+
+---
+
+## Table of Contents
+
+1. [Architecture Overview](#architecture-overview)
+2. [Core Components](#core-components)
+3. [Metatracks Architecture](#metatracks-architecture)
+4. [Implementation Roadmap](#implementation-roadmap)
+5. [Technical Specifications](#technical-specifications)
+6. [Testing Strategy](#testing-strategy)
+
+---
+
+## Architecture Overview
+
+### High-Level Design
+
+The DAW follows a **multi-threaded, message-passing architecture** that separates real-time audio processing from UI and control logic:
+
+```
+┌─────────────┐ Commands ┌─────────────┐ Commands ┌─────────────┐
+│ UI Thread │ ←──────────────→ │Control Thread│ ←──────────────→ │ Audio Thread│
+└─────────────┘ Events └─────────────┘ Lock-free └─────────────┘
+ │ Queues │
+ ↓ │
+ ┌─────────────┐ │
+ │Project State│←────────────────────────┘
+ │(Triple-buf) │ Atomic reads
+ └─────────────┘
+```
+
+### Design Principles
+
+1. **Real-time Safety**: Audio thread is lock-free and allocation-free
+2. **Hierarchical Composition**: Tracks can contain other tracks (metatracks)
+3. **Message-Based Communication**: All cross-thread communication via lock-free queues
+4. **Incremental Complexity**: Architecture supports simple flat tracks initially, scales to nested metatracks
+5. **Separation of Concerns**: Audio processing, state management, and UI are decoupled
+
+---
+
+## Core Components
+
+### 1. Audio Engine (Real-time Thread)
+
+**Responsibilities:**
+- Process audio graph in response to cpal callbacks
+- Execute commands from control thread
+- Maintain playback position and transport state
+- Send events back to control thread
+
+**Constraints:**
+- No memory allocations
+- No blocking operations (mutex, I/O)
+- No unbounded loops
+- Pre-allocated buffers only
+
+**Key Structures:**
+
+```rust
+struct AudioEngine {
+ tracks: Vec,
+ playhead: u64, // Sample position
+ playing: bool,
+ sample_rate: u32,
+
+ // Communication
+ command_rx: rtrb::Consumer,
+ event_tx: rtrb::Producer,
+
+ // Pre-allocated resources
+ mix_buffer: Vec,
+ buffer_pool: BufferPool,
+}
+
+enum Command {
+ Play,
+ Stop,
+ Seek(f64),
+ SetTempo(f32),
+ UpdateTrackVolume(TrackId, f32),
+ UpdateTrackMute(TrackId, bool),
+ AddEffect(TrackId, EffectType),
+ // ... more commands
+}
+
+enum AudioEvent {
+ PlaybackPosition(f64),
+ PeakLevel(TrackId, f32),
+ BufferUnderrun,
+ // ... more events
+}
+```
+
+### 2. Track Hierarchy
+
+**Track Node Types:**
+
+```rust
+enum TrackNode {
+ Audio(AudioTrack),
+ Midi(MidiTrack),
+ Metatrack(Metatrack),
+ Bus(BusTrack),
+}
+
+struct AudioTrack {
+ id: TrackId,
+ name: String,
+ clips: Vec,
+ effects: Vec>,
+ volume: f32,
+ pan: f32,
+ muted: bool,
+ solo: bool,
+ parent: Option,
+}
+
+struct MidiTrack {
+ id: TrackId,
+ name: String,
+ clips: Vec,
+ instrument: Box, // Virtual instrument
+ effects: Vec>,
+ volume: f32,
+ pan: f32,
+ muted: bool,
+ solo: bool,
+ parent: Option,
+}
+
+struct Metatrack {
+ id: TrackId,
+ name: String,
+ children: Vec,
+ effects: Vec>,
+
+ // Metatrack-specific features
+ time_stretch: f32, // Speed multiplier (0.5 = half speed)
+ pitch_shift: f32, // Semitones
+ offset: f64, // Time offset in seconds
+
+ volume: f32,
+ pan: f32,
+ muted: bool,
+ solo: bool,
+ parent: Option,
+
+ // UI hints
+ collapsed: bool,
+ color: Color,
+}
+
+struct BusTrack {
+ id: TrackId,
+ name: String,
+ inputs: Vec, // Which tracks send to this bus
+ effects: Vec>,
+ volume: f32,
+ pan: f32,
+}
+```
+
+### 3. Clips and Regions
+
+```rust
+struct Clip {
+ id: ClipId,
+ content: ClipContent,
+ start_time: f64, // Position in parent track (seconds)
+ duration: f64, // Clip duration (seconds)
+ offset: f64, // Offset into content (seconds)
+
+ // Clip-level processing
+ gain: f32,
+ fade_in: f64,
+ fade_out: f64,
+ reversed: bool,
+}
+
+enum ClipContent {
+ AudioFile {
+ pool_index: usize, // Index into AudioPool
+ },
+ MidiData {
+ events: Vec,
+ },
+ MetatrackReference {
+ track_id: TrackId,
+ },
+}
+
+struct MidiEvent {
+ timestamp: u64, // Sample offset within clip
+ status: u8,
+ data1: u8,
+ data2: u8,
+}
+```
+
+### 4. Audio Pool
+
+Shared audio file storage:
+
+```rust
+struct AudioPool {
+ files: Vec,
+ cache: LruCache>,
+}
+
+struct AudioFile {
+ id: FileId,
+ path: PathBuf,
+ data: Vec, // Interleaved samples
+ channels: u32,
+ sample_rate: u32,
+ frames: u64,
+}
+```
+
+### 5. Effect System
+
+```rust
+trait Effect: Send {
+ fn process(&mut self, buffer: &mut [f32], channels: usize, sample_rate: u32);
+ fn set_parameter(&mut self, id: u32, value: f32);
+ fn get_parameter(&self, id: u32) -> f32;
+ fn reset(&mut self);
+}
+
+// Example implementations
+struct GainEffect {
+ gain_db: f32,
+}
+
+struct SimpleEQ {
+ low_gain: f32,
+ mid_gain: f32,
+ high_gain: f32,
+ filters: [BiquadFilter; 3],
+}
+
+struct SimpleSynth {
+ oscillators: Vec,
+ adsr: AdsrEnvelope,
+}
+```
+
+### 6. Render Context
+
+Carries time and tempo information through the track hierarchy:
+
+```rust
+struct RenderContext {
+ global_position: u64, // Absolute sample position
+ local_position: u64, // Position within current scope
+ sample_rate: u32,
+ tempo: f32,
+ time_signature: (u32, u32),
+ time_stretch: f32, // Accumulated stretch factor
+}
+
+impl Metatrack {
+ fn transform_context(&self, ctx: RenderContext) -> RenderContext {
+ let offset_samples = (self.offset * ctx.sample_rate as f64) as u64;
+ let local_pos = ((ctx.local_position.saturating_sub(offset_samples)) as f64
+ / self.time_stretch as f64) as u64;
+
+ RenderContext {
+ global_position: ctx.global_position,
+ local_position: local_pos,
+ sample_rate: ctx.sample_rate,
+ tempo: ctx.tempo * self.time_stretch,
+ time_signature: ctx.time_signature,
+ time_stretch: ctx.time_stretch * self.time_stretch,
+ }
+ }
+}
+```
+
+### 7. Project State
+
+```rust
+struct Project {
+ tracks: HashMap,
+ root_tracks: Vec,
+ audio_pool: AudioPool,
+
+ // Global settings
+ sample_rate: u32,
+ tempo: f32,
+ time_signature: (u32, u32),
+
+ // Metadata
+ name: String,
+ created: SystemTime,
+ modified: SystemTime,
+}
+
+impl Project {
+ fn get_processing_order(&self) -> Vec {
+ // Depth-first traversal for correct rendering order
+ let mut order = Vec::new();
+ for root_id in &self.root_tracks {
+ self.collect_depth_first(*root_id, &mut order);
+ }
+ order
+ }
+
+ fn collect_depth_first(&self, id: TrackId, order: &mut Vec) {
+ if let Some(TrackNode::Metatrack(meta)) = self.tracks.get(&id) {
+ for child_id in &meta.children {
+ self.collect_depth_first(*child_id, order);
+ }
+ }
+ order.push(id);
+ }
+}
+```
+
+### 8. Buffer Management
+
+```rust
+struct BufferPool {
+ buffers: Vec>,
+ available: Vec,
+ buffer_size: usize,
+}
+
+impl BufferPool {
+ fn acquire(&mut self) -> Vec {
+ if let Some(idx) = self.available.pop() {
+ let mut buf = std::mem::take(&mut self.buffers[idx]);
+ buf.fill(0.0);
+ buf
+ } else {
+ vec![0.0; self.buffer_size]
+ }
+ }
+
+ fn release(&mut self, buffer: Vec) {
+ let idx = self.buffers.len();
+ self.buffers.push(buffer);
+ self.available.push(idx);
+ }
+}
+```
+
+---
+
+## Metatracks Architecture
+
+### Processing Model
+
+Metatracks use a **pre-mix** model:
+
+1. Mix all children into a temporary buffer
+2. Apply metatrack's effects to the mixed buffer
+3. Mix result into parent's output
+
+```rust
+fn process_metatrack(
+ meta: &Metatrack,
+ project: &Project,
+ output: &mut [f32],
+ context: RenderContext,
+ buffer_pool: &mut BufferPool,
+) {
+ // Transform context for children
+ let child_context = meta.transform_context(context);
+
+ // Acquire scratch buffer
+ let mut submix = buffer_pool.acquire();
+ submix.resize(output.len(), 0.0);
+
+ // Process all children into submix
+ for child_id in &meta.children {
+ if let Some(child) = project.tracks.get(child_id) {
+ process_track_node(
+ child,
+ project,
+ &mut submix,
+ child_context,
+ buffer_pool
+ );
+ }
+ }
+
+ // Apply metatrack's effects
+ for effect in &mut meta.effects {
+ effect.process(&mut submix, 2, context.sample_rate);
+ }
+
+ // Mix into output with volume
+ for (out, sub) in output.iter_mut().zip(submix.iter()) {
+ *out += sub * meta.volume;
+ }
+
+ // Return buffer to pool
+ buffer_pool.release(submix);
+}
+```
+
+### Time Transformation
+
+Metatracks can manipulate time for all children:
+
+- **Time Stretch**: Speed up or slow down playback
+- **Offset**: Shift content in time
+- **Pitch Shift**: Transpose content (future feature, requires pitch-preserving time stretch)
+
+### Metatrack Operations
+
+```rust
+enum MetatrackOperation {
+ // Creation
+ CreateFromSelection(Vec),
+ CreateEmpty,
+
+ // Hierarchy manipulation
+ AddToMetatrack(TrackId, Vec),
+ RemoveFromMetatrack(TrackId, Vec),
+ MoveToMetatrack { track: TrackId, new_parent: TrackId },
+ Ungroup(TrackId),
+ Flatten(TrackId),
+
+ // Transformation
+ SetTimeStretch(TrackId, f32),
+ SetOffset(TrackId, f64),
+
+ // Rendering
+ BounceToAudio(TrackId),
+ Freeze(TrackId),
+ Unfreeze(TrackId),
+}
+```
+
+### Nesting Limits
+
+- **Recommended maximum depth**: 10 levels
+- **Reason**: Performance and UI complexity
+- **Implementation**: Check depth during metatrack creation
+
+---
+
+## Implementation Roadmap
+
+### Phase 1: Single Audio File Playback (Week 1-2)
+
+**Goal**: Play one audio file through speakers
+
+**Deliverables:**
+- Basic cpal integration
+- Load audio file with symphonia
+- Simple playback loop
+- Press spacebar to play/pause
+
+**Core Implementation:**
+
+```rust
+struct SimpleEngine {
+ audio_data: Vec,
+ playhead: usize,
+ sample_rate: u32,
+ playing: Arc,
+}
+
+// Main audio callback
+fn audio_callback(data: &mut [f32], engine: &mut SimpleEngine) {
+ if engine.playing.load(Ordering::Relaxed) {
+ let end = (engine.playhead + data.len()).min(engine.audio_data.len());
+ let available = end - engine.playhead;
+
+ data[..available].copy_from_slice(
+ &engine.audio_data[engine.playhead..end]
+ );
+
+ engine.playhead = end;
+ } else {
+ data.fill(0.0);
+ }
+}
+```
+
+**Dependencies:**
+- `cpal = "0.15"`
+- `symphonia = "0.5"`
+
+**Success Criteria:**
+- Audio plays without clicks or pops
+- Can start/stop playback
+- No audio thread panics
+
+---
+
+### Phase 2: Transport Control + UI Communication (Week 2-3)
+
+**Goal**: Start/stop/seek from a basic UI
+
+**Deliverables:**
+- Lock-free command queue
+- Atomic playhead position
+- Basic UI (terminal or simple window)
+- Play/pause/seek controls
+
+**Core Implementation:**
+
+```rust
+enum Command {
+ Play,
+ Stop,
+ Seek(f64),
+}
+
+struct Engine {
+ audio_data: Vec,
+ playhead: Arc,
+ command_rx: rtrb::Consumer,
+ playing: bool,
+ sample_rate: u32,
+}
+
+fn audio_callback(data: &mut [f32], engine: &mut Engine) {
+ // Process all pending commands
+ while let Ok(cmd) = engine.command_rx.pop() {
+ match cmd {
+ Command::Play => engine.playing = true,
+ Command::Stop => {
+ engine.playing = false;
+ engine.playhead.store(0, Ordering::Relaxed);
+ }
+ Command::Seek(seconds) => {
+ let samples = (seconds * engine.sample_rate as f64) as u64;
+ engine.playhead.store(samples, Ordering::Relaxed);
+ }
+ }
+ }
+
+ // Render audio...
+}
+```
+
+**New Dependencies:**
+- `rtrb = "0.3"` (lock-free ringbuffer)
+
+**Success Criteria:**
+- Commands execute within 1 buffer period
+- No audio glitches during seek
+- Playhead position updates smoothly
+
+---
+
+### Phase 3: Multiple Audio Tracks (Week 3-4)
+
+**Goal**: Play multiple audio files simultaneously
+
+**Deliverables:**
+- Track data structure
+- Per-track volume control
+- Mute/solo functionality
+- Mix multiple tracks
+
+**Core Implementation:**
+
+```rust
+struct Track {
+ id: u32,
+ audio_data: Vec,
+ volume: f32,
+ muted: bool,
+ solo: bool,
+}
+
+struct Engine {
+ tracks: Vec