Skip to content

danielraffel/JUCE-Plugin-Starter

Repository files navigation

JUCE Plugin Starter

ℹ️ Overview

This is a JUCE plugin starter template using CMake and environment-based configuration for folks new to audio plugin development on macOS. It allows you to create standalone apps and audio plugins (AU/VST3) for macOS using Xcode. It’s designed for quick setup, ease of customization, and modern JUCE development workflows.


How to Just Give This a Try (Without Reading the Full README)

This is the fastest way to test-drive the JUCE Plugin Starter. It assumes you have Xcode installed and will:

  • βœ… Install all required dependencies (doesn't assume you have git)
  • βœ… Clone this repo and set up your environment
  • βœ… Run a guided script to create your new plugin repo and push it to GitHub
  • βœ… Download JUCE and generate an Xcode project

Heads up: This command runs several scripts and installs multiple components. To avoid surprises, it’s a good idea to read through the full README before running it in your terminal. And, to watch the output in the event you're asked to take manual actions.

Setup Instructions: Paste the entire section below directly into your terminal.

# Install required tools (Xcode CLT, Homebrew, CMake, PluginVal, etc.)
bash <(curl -fsSL https://raw.githubusercontent.com/danielraffel/JUCE-Plugin-Starter/main/dependencies.sh)

# The commands above install software like Homebrew.
# During installation, you may be prompted to add Homebrew to your PATH manually:
# echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bash_profile
# eval "$(/opt/homebrew/bin/brew shellenv)"

# Clone the starter project and set up environment
git clone https://github.com/danielraffel/JUCE-Plugin-Starter.git
cd JUCE-Plugin-Starter
cp .env.example .env

# Run the first-time setup to configure your plugin project
chmod +x ./init_plugin_project.sh
./init_plugin_project.sh

# Generate and open the Xcode project (downloads JUCE on first run)
chmod +x ./generate_and_open_xcode.sh
./generate_and_open_xcode.sh
  • πŸ‘¨β€πŸ’» You can now open your project folder in your favorite IDE (Xcode, VS Code, Cursor, Windsurf, etc) and start building your JUCE plugin.

  • βœ… Once setup is complete, run this command whenever you need to manually rebuild your project and reopen it in Xcode during development. If you’re collaborating with an AI developer tool, here are some common ways to automate executing this script.

./generate_and_open_xcode.sh .

βœ… Note: This setup gives you a fully working plugin on your local machine for development and testing.
🧳 To share or distribute your plugin to others, you'll need to configure code signing and notarization β€” when ready see πŸ“¦ How to Distribute Your Plugin for full instructions.

πŸ“– Skip to Full Quick Start β†’


πŸ“‘ Table of Contents


🧰 Prerequisites

To build and develop plugins with this template, you’ll need:

System Requirements


Additional Dependencies

Before building the project, you need to install several development tools.

You can choose one of the following setup methods:


Automated Dependency Setup

Use the included dependencies.sh script. It checks for each required tool and installs it automatically if missing. This is typically needed only for a first-time setup.

bash <(curl -fsSL https://raw.githubusercontent.com/danielraffel/JUCE-Plugin-Starter/main/dependencies.sh)

The script handles:

  • βœ… Xcode Command Line Tools
  • βœ… Homebrew
  • βœ… CMake
  • βœ… PluginVal

It also includes optional installs, commented out by default:

  • Faust – DSP prototyping compiler
  • GoogleTest – C++ unit testing
  • Python 3, pip3, and behave – for behavior-driven development (BDD)

✏️ When you run dependencies.sh software like Homebrew may ask you to do additonal configurations to complete your setup:

# During installation, you may be prompted to add Homebrew to your PATH manually:
# echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bash_profile
# eval "$(/opt/homebrew/bin/brew shellenv)"

✏️ To enable optional tools, simply uncomment the relevant lines in the script.


Manual Dependency Setup

If you prefer, you can install all required tools manually:

Tool Purpose Manual Install Command
Xcode Command Line Tools Xcode compiler & tools xcode-select --install
CMake Build system configuration brew install cmake
Homebrew macOS package manager /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
PluginVal Plugin validation & testing brew install --cask pluginval
Faust (optional) DSP prototyping compiler brew install faust
GoogleTest or Catch2 (optional) C++ unit testing brew install googletest or brew install catch2
Python 3 + behave (optional) Natural language test automation brew install python && pip3 install behave
JUCE Audio plugin framework (AU/VST3) Automatically downloaded by CMake/FetchContent

πŸš€ Quick Start

1. Clone the JUCE Plugin Starter Template

πŸ’‘ This setup will β€œjust work” if you clone this repo into your home folder (i.e., run cd in Terminal before cloning).

git clone https://github.com/danielraffel/JUCE-Plugin-Starter.git
cd JUCE-Plugin-Starter
cp .env.example .env

Update your .env file to reflect:

PROJECT_NAME=MyCoolPlugin
PROJECT_BUNDLE_ID=com.myname.mycoolplugin
PROJECT_PATH=~/JUCE-Plugin-Starter
COMPANY_NAME="Your Company Name"
JUCE_REPO=https://github.com/juce-framework/JUCE.git
JUCE_TAG=8.0.7
GITHUB_USERNAME=danielraffel
BASE_PROJECT_VERSION="1.0."

# --- Apple Notarization ---
# You only need to edit the fields below when you're ready to distribute your plugin.
# Until then, feel free to leave these default placeholder values as-is.
APPLE_ID=your@email.com
APP_SPECIFIC_PASSWORD=your-app-password
APP_CERT="Developer ID Application: Your Name (TEAM_ID)"
INSTALLER_CERT="Developer ID Installer: Your Name (TEAM_ID)"
TEAM_ID=YOUR_TEAM_ID

After cloning and configuring .env, remember:

  • PROJECT_NAME is used as the name of your plugin. This will appear in DAWs like Logic, so name it accordingly.
  • COMPANY_NAME sets the developer name displayed in the plugin browser.

πŸ’‘ On macOS, .env files are hidden by default in Finder. Press Cmd + Shift + . to show or hide hidden files. You can also edit the file in Terminal using:

nano .env

2. Initialize Your Plugin Project with Git Using a Setup Script

If you're planning to use this template to build your own plugin and eventually publish it to GitHub, this script is designed to help you do that quickly and cleanly. The script is smart and will:

  • πŸ” Auto-detect if you're working in a JUCE project directory that doesn't match your .env settings
  • 🏷️ Automatically suggest renaming your project folder to match your plugin name
  • πŸ“„ Create basic plugin source files if they don't exist (ready-to-build template)
  • πŸ›‘οΈ Confirm everything before making changes so you stay in control

Just run the interactive setup script (it will help you configure everything):

chmod +x ./init_plugin_project.sh
./init_plugin_project.sh

What the script does:

  • πŸ” Smart path detection - notices if you're in a different directory than your .env expects and offers to fix it
  • 🧠 Load and validate your .env settings
  • ✏️ Interactive editing of project name, GitHub username, and project path
  • πŸ“ Intelligent folder renaming - suggests renaming to match your plugin name (e.g., JUCE-Plugin-Starter β†’ DelayR)
  • πŸ”§ Script setup - makes build scripts executable (post_build.sh, generate_and_open_xcode.sh)
  • πŸ“„ Template source file creation - generates PluginProcessor.cpp/.h and PluginEditor.cpp/.h if missing
  • πŸ”’ Repository visibility choice - asks if you want public or private
  • βœ… Clear confirmation - shows exactly what will be created before proceeding
  • 🧹 Clean slate - removes the template's Git history
  • πŸ™ GitHub integration - creates your new repository using the GitHub CLI (gh)
  • πŸš€ First commit - pushes your initial code and provides next steps

Example flow:

  • πŸ” PATH MISMATCH DETECTED - Updates .env to match your current location
  • πŸ” Edit PROJECT_NAME? β†’ "DelayR"
  • πŸ” Rename folder to match project name? β†’ JUCE-Plugin-Starter becomes DelayR
  • πŸ”§ Setting up build scripts... β†’ Makes scripts executable for immediate use
  • πŸ“„ Checking for basic plugin source files... β†’ Creates template files if missing
  • πŸ”’ Make this a private repository? β†’ Choose public or private
  • βœ… Proceed with project creation? β†’ Final confirmation
  • πŸŽ‰ Success! Ready to start coding your plugin

πŸ’‘ Highly recommended for first-time users β€” the script handles all the setup automatically (including creating working plugin template files) while keeping you informed every step of the way. After running this script, you'll have a complete, buildable JUCE plugin ready to customize!


3. Generate the Xcode Project

πŸ’‘ First time setup: When you first run ./generate_and_open_xcode.sh, CMake will automatically download JUCE to build/_deps/juce-src/ inside your project directory. This may take a few minutes on the first run. JUCE will be reused for subsequent builds and cleaned up when you delete the build/ directory.

Before running the script for the first time:

chmod +x ./generate_and_open_xcode.sh

Then generate your project:

./generate_and_open_xcode.sh

βœ… No need to run cmake manually β€” it's handled for you.


🧱 Build Targets

Once the project is open in Xcode, you can build:

  • βœ… Standalone App
  • βœ… AudioUnit Plugin (AU) – for Logic Pro, GarageBand
  • βœ… VST3 Plugin – for Reaper, Ableton Live, etc.

Switch targets using the Xcode scheme selector.

image

Make sure the FORMATS AU VST3 Standalone line is present in CMakeLists.txt.


Where Files Are Generated (Plugins + App)

Where Plugin Files Are Installed

When you build your plugin from Xcode, the following file types are generated and installed in the standard macOS plugin locations:

  • Audio Unit (AU) Component:
~/Library/Audio/Plug-Ins/Components/YourPlugin.component
  • VST3 Plugin:
~/Library/Audio/Plug-Ins/VST3/YourPlugin.vst3
  • Standalone App:
Found inside your build folder in your `PROJECT_NAME_artefacts` debug or release folder.

These paths are standard for macOS plugin development and are used by DAWs like Logic Pro, Ableton Live, Reaper, etc.


Auto-Versioning Plugin Builds in Logic Pro

This template includes a post-build script (scripts/post_build.sh) that automatically versions your plugin bundle after each build, ensuring Logic Pro correctly reloads the updated component.

How Versioning Works:

  • The base version is set in your .env file with BASE_PROJECT_VERSION. By default, it's:

    BASE_PROJECT_VERSION="1.0."
    

    You can edit this value to manage your major/minor version. The script will always append a build timestamp to ensure each build is unique.

  • After each build, the script:

    • Reads BASE_PROJECT_VERSION from .env (or uses a default if not found).
    • Appends a timestamp to generate a unique version (e.g., 1.0.2505302321).
    • Updates your plugin’s Info.plist with:
      • CFBundleShortVersionString = base version (e.g., 1.0.)
      • CFBundleVersion = base version + timestamp (e.g., 1.0.2505302321)
    • Only the full (timestamped) version is visible in the Info.plist, not in the plugin UI.
  • The script is triggered from your CMake build with:

    add_custom_command(TARGET ${PROJECT_NAME}_AU
        POST_BUILD
        COMMAND "${CMAKE_SOURCE_DIR}/scripts/post_build.sh" "$<TARGET_BUNDLE_DIR:${PROJECT_NAME}_AU>"
        COMMENT "Updating Info.plist version for ${PROJECT_NAME}_AU"
        VERBATIM
    )

What This Solves:

  • Ensures Logic Pro re-recognizes your Audio Unit after every build
  • Prevents stale cache/version issues
  • Keeps development iterative and frustration-free

How to Manage Versions:

  • Edit .env and change BASE_PROJECT_VERSION (e.g., bump from 1.0. to 1.1. for a new feature).
  • The timestamp is always unique per build, so you don't have to manage patch versions manually.
  • The timestamped build version is only visible in the plugin's Info.plist, not in the UI.

Customization:

  • You can modify scripts/post_build.sh to change how versions are generated or update which fields are set in Info.plist.

πŸ“ Customize Your Plugin

Edit the files in Source/:

  • PluginProcessor.cpp / .h – DSP and audio engine
  • PluginEditor.cpp / .h – UI layout and interaction

Add more .cpp/.h files as needed for a modular architecture.


πŸ› οΈ How to Edit CMakeLists.txt

Your CMakeLists.txt is where the plugin’s structure and build config live. Open it with any code editor.

All CMake configuration is centralized in the top-level CMakeLists.txt file. If you need to:

  • Add source files
  • Link dependencies
  • Define feature flags
  • Toggle plugin modes
  • Set test builds

Then this is where to do it.

πŸ•’ Tip: If you only modified non-CMake files and want a quicker build, you can skip regeneration using:

SKIP_CMAKE_REGEN=1 ./generate_and_open_xcode.sh

Otherwise, always use:

./generate_and_open_xcode.sh

If you're developing using an agent like Claude Code it will determine which build approach is best using instructions in the CLAUDE.md in this repository.

πŸ”§ Common Edits

βœ… Add Source Files

target_sources(${PROJECT_NAME} PRIVATE
    Source/PluginProcessor.cpp
    Source/PluginEditor.cpp
    Source/MyFilter.cpp
    Source/MyFilter.h
)

βœ… Add JUCE Modules

target_link_libraries(${PROJECT_NAME} PRIVATE
    juce::juce_audio_utils
    juce::juce_graphics
    juce::juce_osc       # <-- newly added module
)

βœ… Change Output Formats

FORMATS AU VST3 Standalone

To skip AU, just remove it:

FORMATS VST3 Standalone

βœ… Add Preprocessor Macros

target_compile_definitions(${PROJECT_NAME} PRIVATE
    USE_MY_DSP_ENGINE=1
)

βœ… Set Minimum macOS Deployment Target

To ensure your project builds against a specific minimum macOS version, set the CMAKE_OSX_DEPLOYMENT_TARGET before defining the project in your CMakeLists.txt.

# Set minimum macOS version before defining the project
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "Minimum macOS version")

After making changes, just re-run:

./generate_and_open_xcode.sh

πŸ“¦ Project File Structure

JUCE-Plugin-Starter/
β”œβ”€β”€ .env.example                   ← Template for your environment variables
β”œβ”€β”€ CLAUDE.md                      ← Project details for Claude Code
β”œβ”€β”€ CMakeLists.txt                 ← Main build config for your JUCE project
β”œβ”€β”€ init_plugin_project.sh         ← Script that will reinitialize this repo to make it yours, configure, rename and push it to GH
β”œβ”€β”€ README.md                      ← You're reading it
β”œβ”€β”€ generate_and_open_xcode.sh     ← Script that loads `.env`, runs CMake, and opens Xcode
β”œβ”€β”€ scripts/                       ← Automation / helper scripts
β”‚   └── post_build.sh              ← Auto-increments bundle version so Logic reloads builds
β”‚   └── sign_and_package_plugin.sh ← Auto-package plug-in(s) for safe, notarized distribution via PKG and DMG files
β”œβ”€β”€ Source/                        ← Your plugin source code
β”‚   β”œβ”€β”€ PluginProcessor.cpp/.h
β”‚   └── PluginEditor.cpp/.h
└── build/                         ← Generated by CMake (can be deleted anytime)
    └── YourPlugin.xcodeproj       ← Generated Xcode project

~/.juce_cache/                     ← Shared JUCE location (outside project)
└── juce-src/                      ← JUCE framework (shared across all projects)

About the JUCE cache location:

  • βœ… Shared across projects: Multiple JUCE projects use the same download
  • βœ… Survives build cleaning: rm -rf build won't delete JUCE
  • βœ… Version controlled: Different projects can use different JUCE versions via JUCE_TAG

πŸ’‘ You can safely rm -rf build without re-downloading JUCE every time.


πŸ’‘ Tips

πŸ” Building with AI Tools

Using with Cursor

The generate_and_open_xcode.sh script includes a line that automatically opens the generated Xcode project. Since Cursor doesn’t require this, I strongly recommend commenting out the following section:

# Open the generated Xcode project
if [ -d "$XCODE_PROJECT" ]; then
  open "$XCODE_PROJECT"
else
  echo "Xcode project not found: $XCODE_PROJECT"
  exit 1
fi

Using with Alex Sidebar

To use generate_and_open_xcode.sh with AlexCodes.app, I’ve found the following project prompt helpful for managing when and how the Xcode project is compiled and opened:

Whenever the Xcode project file needs to be regenerated use run_shell to execute $PROJECT_PATH/generate_and_open_xcode.sh
regenerate-xcode-alexcodes

Using with Claude Code

To use generate_and_open_xcode.sh with Claude Code, I’ve created a CLAUDE.md and added it to the root of the repo. It instructs the agent how and when to properly recreate the project file. It can help you build and run the project by invoking the proper script:

./generate_and_open_xcode.sh

Claude will determine whether a full regeneration is needed based on recent file changes or build errors.. The CLAUDE.md explains when it's best to regenerate the Xcode project and how to optionally skip regeneration for faster builds using:

SKIP_CMAKE_REGEN=1 ./generate_and_open_xcode.sh

πŸ“¦ How to Distribute Your Plugin

Once your plugin is built and tested, you can package it for safe, notarized distribution via Apple’s system using the built-in sign_and_package_plugin.sh script.

πŸ’­ Interested in more details? Check out this walkthrough on macOS audio plug-in code signing and notarization.


πŸ› οΈ Requirements

βœ… Apple Developer Program Membership

βœ… Code Signing Certificates

You’ll need two certificates installed in Keychain Access (login keychain):

  1. Developer ID Application
  2. Developer ID Installer

These allow Apple to verify your identity and authorize your software for distribution.


πŸ“₯ How to Generate and Install Certificates

  1. Go to Apple Developer Certificates Portal
  2. Click βž• β€œCreate Certificate”
  3. Choose:
    • Developer ID Application
    • Developer ID Installer
  4. Follow Apple’s steps to:
    • Create a Certificate Signing Request (CSR) using Keychain Access
    • Download the signed certificate
    • Double-click it to install into your Keychain

πŸ” How to Verify They're Installed

In Terminal, run:

security find-identity -v -p codesigning

You should see both listed, like:

  1) A1B2C3D4E5... "Developer ID Application: Your Name (TEAMID)"
  2) F6G7H8I9J0... "Developer ID Installer: Your Name (TEAMID)"

Make note of the exact names β€” you'll reference these in your .env file.


βœ… App-Specific Password for Notarization

  1. Go to appleid.apple.com
  2. Under Sign-In and Security, click App-Specific Passwords
  3. Click βž• "Generate App-Specific Password" and consider using your project name as the identifier
  4. Make sure to store this password safely β€” it’s required for every notarization and must be added to your .env

βš™οΈ Distribution-Specific Environment Variables

Add these values to your main .env file:

# Notarization credentials
APPLE_ID=your@email.com
APP_SPECIFIC_PASSWORD=abcd-efgh-ijkl-mnop
APP_CERT="Developer ID Application: Your Name (TEAM_ID)"
INSTALLER_CERT="Developer ID Installer: Your Name (TEAM_ID)"
TEAM_ID=YOUR_TEAM_ID

πŸ’‘ Always make sure your .env file is listed in .gitignore to avoid exposing credentials.


πŸŽ›οΈ What Gets Packaged

sign_and_package_plugin.sh will automatically detect and package the following plugin formats if they exist:

Format Extension Path
AU .component ~/Library/Audio/Plug-Ins/Components/
VST3 .vst3 ~/Library/Audio/Plug-Ins/VST3/
AAX .aaxplugin /Library/Application Support/Avid/Audio/Plug-Ins/
  • The script signs, notarizes, and staples each format (if found)
  • All formats are bundled into a single .pkg installer
  • The .pkg is signed and notarized
  • Finally, the .pkg is included in a ready-to-share .dmg

πŸ’‘ Missing formats are skipped, but the script will print a warning if none are found and exit gracefully.


πŸš€ Run the Distribution Script

From your project root:

cd scripts
chmod +x sign_and_package_plugin.sh
./sign_and_package_plugin.sh

This script will:

  • βœ… Sign and notarize your .component
  • βœ… Create a signed .pkg installer and notarize it
  • βœ… Bundle it into a distributable .dmg

πŸ“‚ Output files (.zip, .pkg, .dmg) will be saved to your Desktop for easy sharing.


πŸ“š Resources

About

Start Developing Audio Plugins on macOS!

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published