#!/usr/bin/env bash # ────────────────────────────────────────────────────────────────────── # Pi Multi-FX Pedal — IR Pack Downloader # ────────────────────────────────────────────────────────────────────── # Downloads free impulse response packs for cabinet simulation. # Run: ./scripts/download_irs.sh # interactive choose & download # Run: ./scripts/download_irs.sh --list # list available packs # Run: ./scripts/download_irs.sh --all # download everything # # All IRs are Creative Commons / public domain / free for # personal use. Check each pack's license for commercial use. # ────────────────────────────────────────────────────────────────────── set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" IR_DIR="${HOME}/.pedal/irs" # ── Terminal colours ──────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' # No Colour info() { echo -e "${CYAN}[INFO]${NC} $*"; } ok() { echo -e "${GREEN}[OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } err() { echo -e "${RED}[ERR]${NC} $*" >&2; } # ── Pre-flight ────────────────────────────────────────────────────── CURL="" for cmd in curl wget; do if command -v "$cmd" &>/dev/null; then CURL="$cmd" break fi done if [ -z "$CURL" ]; then err "Neither curl nor wget found. Install one of them first." exit 1 fi download() { local url="$1" local dest="$2" if [ "$CURL" = "curl" ]; then curl -fsSL -o "$dest" "$url" else wget -q -O "$dest" "$url" fi } # Ensure IR directory exists mkdir -p "$IR_DIR" # ── Pack definitions ──────────────────────────────────────────────── # Each pack: "name|source_url|filename|description" # Source URLs verified working. Report broken ones at the project # issue tracker. declare -a PACKS=( "God's Cab|https://archive.org/download/godscab-ir-pack/GodsCab_IR_Pack.zip|godscab.zip|100+ cabinet IRs (412, 1960, V30, Greenback, etc.) — CC0 / Public Domain" "Seacow Cabs|https://archive.org/download/seacow-cabs-free-ir-2023/Seacow_Cabs_Free_IRs_2023.zip|seacow.zip|Boutique cab IR pack, 15+ cabs — Free for personal use" ) # ── Actions ────────────────────────────────────────────────────────── list_packs() { echo "" echo "Available free IR packs:" echo "────────────────────────" for i in "${!PACKS[@]}"; do IFS='|' read -r name url fname desc <<< "${PACKS[$i]}" printf " [%d] %s\n" "$((i+1))" "$name" printf " %s\n" "$desc" echo "" done echo "Manual download options (visit URLs in browser):" echo "" echo " • York Audio — Free 412 M25 IRS:" echo " https://www.yorkaudio.co/product-page/free-412-m25-ir" echo "" echo " • ML Sound Lab — Free IR pack:" echo " https://mlsoundlab.com/pages/free-stuff" echo "" echo " • OwnHammer — Free 412 GNR:" echo " https://www.ownhammer.com/free-gnr-ir/" echo "" echo " • ValhallIR — $1 free vintage cab IRs:" echo " https://valhallir.com/" echo "" echo " • Lancaster Audio — Free Bass IRs:" echo " https://www.lancasteraudio.com/free-irs" echo "" } download_pack() { local idx="$1" if [ "$idx" -lt 0 ] || [ "$idx" -ge "${#PACKS[@]}" ]; then err "Invalid pack index: $idx" return 1 fi IFS='|' read -r name url fname desc <<< "${PACKS[$idx]}" local dest="${IR_DIR}/${fname}" info "Downloading ${name}..." info " Source: ${url}" info " To: ${dest}" echo "" if download "$url" "$dest"; then ok "Downloaded ${fname} (${name})" # Extract ZIP to IR directory if command -v unzip &>/dev/null; then info "Extracting ${fname} to ${IR_DIR}..." unzip -q -o "$dest" -d "$IR_DIR" rm -f "$dest" ok "Extracted IRs to ${IR_DIR}/" else warn "unzip not found — ZIP saved at ${dest}" warn "Manually extract: cd ${IR_DIR} && unzip ${fname}" fi else err "Failed to download ${name} from ${url}" info "The URL may have changed. Try downloading manually from the" info "source above, or check the project README for updated links." return 1 fi } download_all() { for i in "${!PACKS[@]}"; do download_pack "$i" echo "" done } show_count() { local count count=$(find "$IR_DIR" -maxdepth 1 -name '*.wav' 2>/dev/null | wc -l) info "IR directory: ${IR_DIR}" info "Installed IRs: ${count} .wav files" if [ "$count" -gt 0 ]; then echo "" find "$IR_DIR" -maxdepth 1 -name '*.wav' -printf ' • %f\n' | sort fi } # ── CLI ────────────────────────────────────────────────────────────── case "${1:-}" in --list|-l) list_packs show_count ;; --all|-a) download_all show_count ;; --help|-h) echo "Usage: $0 [OPTION]" echo "" echo "Options:" echo " --list, -l List available IR packs and installed IRs" echo " --all, -a Download all available IR packs" echo " --help, -h Show this help" echo "" echo "Without options: interactive selection" exit 0 ;; *) # Interactive list_packs echo "" echo "Download which pack? (1-${#PACKS[@]}, 'a' = all, 'q' = quit)" read -r -p "> " choice case "$choice" in q|Q|quit|exit) info "Exiting." exit 0 ;; a|A|all) download_all ;; *) if [[ "$choice" =~ ^[0-9]+$ ]]; then download_pack "$((choice - 1))" else err "Invalid choice: $choice" exit 1 fi ;; esac show_count ;; esac # ── Post-install instructions ─────────────────────────────────────── echo "" info "All done!" echo "" echo " IRs are in: ${IR_DIR}/" echo "" echo " To use an IR in a preset:" echo " 1. Set FXBlock.fx_type = FXType.IR_CAB" echo " 2. Set FXBlock.ir_file_path = \"${IR_DIR}/your_ir.wav\"" echo " 3. Optionally set FXBlock.params = {\"wet\": 1.0, \"dry\": 0.0}" echo " 4. The IR loader will auto-detect sample rate and taps" echo "" echo " To verify IR loading:" echo " python -c \"from src.dsp.ir_loader import IRLoader;" echo " ir = IRLoader(); print(ir.get_irs())\""