Project Structure

Follow these guidelines to ensure your plugin repository works smoothly with BeatConnect’s build system.

your-plugin/
├── CMakeLists.txt              # Root CMake configuration
├── CMakePresets.json           # Build presets (optional)
├── .gitmodules                 # Git submodule definitions
├── README.md                   # Project documentation
├── LICENSE                     # Your license file
│
├── external/                   # Third-party dependencies
│   ├── JUCE/                   # JUCE as submodule
│   └── other-lib/              # Any other dependencies
│
├── Source/                     # Your plugin source code
│   ├── PluginProcessor.h
│   ├── PluginProcessor.cpp
│   ├── PluginEditor.h
│   ├── PluginEditor.cpp
│   └── DSP/                    # DSP-specific code
│       ├── Filter.h
│       ├── Filter.cpp
│       ├── Oscillator.h
│       └── Oscillator.cpp
│
├── Resources/                  # Binary resources
│   ├── Logo.png
│   ├── Background.jpg
│   └── Presets/
│       ├── Default.xml
│       └── Factory/
│
├── Tests/                      # Unit tests (optional)
│   ├── CMakeLists.txt
│   └── PluginTests.cpp
│
└── .github/                    # GitHub configuration
    └── workflows/              # Your own CI (optional)

Required Files

CMakeLists.txt

The root CMakeLists.txt is required. At minimum:

cmake_minimum_required(VERSION 3.22)
project(YourPlugin VERSION 1.0.0)
 
add_subdirectory(external/JUCE)
 
juce_add_plugin(YourPlugin
    PLUGIN_MANUFACTURER_CODE Xxxx
    PLUGIN_CODE Yyyy
    FORMATS VST3 AU
    PRODUCT_NAME "Your Plugin"
)
 
target_sources(YourPlugin PRIVATE
    Source/PluginProcessor.cpp
    Source/PluginEditor.cpp
)
 
target_link_libraries(YourPlugin PRIVATE
    juce::juce_audio_basics
    juce::juce_audio_processors
    juce::juce_gui_basics
)

.gitmodules

If using JUCE as a submodule:

[submodule "external/JUCE"]
	path = external/JUCE
	url = https://github.com/juce-framework/JUCE.git

Source File Organization

Simple Plugin (< 5 files)

Source/
├── PluginProcessor.h
├── PluginProcessor.cpp
├── PluginEditor.h
└── PluginEditor.cpp

Medium Plugin (5-20 files)

Source/
├── PluginProcessor.h
├── PluginProcessor.cpp
├── PluginEditor.h
├── PluginEditor.cpp
├── Parameters.h              # Parameter definitions
├── DSP/
│   ├── Filter.h
│   ├── Filter.cpp
│   ├── Delay.h
│   └── Delay.cpp
└── UI/
    ├── CustomLookAndFeel.h
    ├── CustomLookAndFeel.cpp
    ├── MainComponent.h
    └── MainComponent.cpp

Large Plugin (20+ files)

Source/
├── Core/
│   ├── PluginProcessor.h
│   ├── PluginProcessor.cpp
│   ├── Parameters.h
│   └── Parameters.cpp
├── DSP/
│   ├── Effects/
│   │   ├── Filter.h
│   │   ├── Delay.h
│   │   └── Reverb.h
│   ├── Synthesis/
│   │   ├── Oscillator.h
│   │   └── Envelope.h
│   └── Utils/
│       ├── SmoothValue.h
│       └── RingBuffer.h
├── UI/
│   ├── PluginEditor.h
│   ├── PluginEditor.cpp
│   ├── Components/
│   │   ├── CustomSlider.h
│   │   ├── XYPad.h
│   │   └── Visualizer.h
│   └── LookAndFeel/
│       └── CustomLookAndFeel.h
└── Presets/
    ├── PresetManager.h
    └── PresetManager.cpp

CMake Source Inclusion

Simple (few files)

target_sources(YourPlugin PRIVATE
    Source/PluginProcessor.cpp
    Source/PluginEditor.cpp
)

With file globbing (many files)

file(GLOB_RECURSE PLUGIN_SOURCES
    "${CMAKE_CURRENT_SOURCE_DIR}/Source/*.cpp"
    "${CMAKE_CURRENT_SOURCE_DIR}/Source/*.h"
)
 
target_sources(YourPlugin PRIVATE ${PLUGIN_SOURCES})

Note: GLOB_RECURSE requires CMake reconfiguration when adding new files. Some prefer explicit listing for this reason.

With source groups (IDE organization)

# Organize files in IDE (Xcode, Visual Studio)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/Source"
             PREFIX "Source"
             FILES ${PLUGIN_SOURCES})

Resources

Binary Resources

Include images, fonts, and data files:

juce_add_binary_data(YourPluginResources
    NAMESPACE Resources
    SOURCES
        Resources/Logo.png
        Resources/Background.jpg
        Resources/CustomFont.ttf
)
 
target_link_libraries(YourPlugin PRIVATE YourPluginResources)

Access in code:

#include "BinaryData.h"
 
// Use in your code
auto logoImage = ImageCache::getFromMemory(
    Resources::Logo_png,
    Resources::Logo_pngSize
);

Presets

For factory presets:

juce_add_binary_data(YourPluginPresets
    NAMESPACE Presets
    SOURCES
        Resources/Presets/Default.xml
        Resources/Presets/Warm.xml
        Resources/Presets/Bright.xml
)

Dependencies

git submodule add https://github.com/juce-framework/JUCE.git external/JUCE
git submodule update --init

Pin to specific version:

cd external/JUCE
git checkout 7.0.9
cd ../..
git add external/JUCE
git commit -m "Pin JUCE to 7.0.9"

Using FetchContent

include(FetchContent)
 
FetchContent_Declare(
    juce
    GIT_REPOSITORY https://github.com/juce-framework/JUCE.git
    GIT_TAG 7.0.9
)
 
FetchContent_MakeAvailable(juce)

Other Dependencies

Header-only libraries

# Add include directory
target_include_directories(YourPlugin PRIVATE external/header-only-lib/include)

Compiled libraries

add_subdirectory(external/other-lib)
target_link_libraries(YourPlugin PRIVATE other-lib)

Version Control

.gitignore

# Build directories
build/
cmake-build-*/
 
# IDE files
.idea/
*.xcodeproj/
*.xcworkspace/
 
# Generated files
Builds/
JuceLibraryCode/
 
# OS files
.DS_Store
Thumbs.db
 
# Dependencies (if not using submodules)
# external/JUCE/

Submodule Initialization

Ensure builds initialize submodules:

# BeatConnect does this automatically, but for local builds:
git submodule update --init --recursive

Multi-Plugin Repositories

Shared code structure

my-plugins/
├── CMakeLists.txt           # Root configuration
├── external/
│   └── JUCE/
├── shared/                   # Shared code
│   ├── DSP/
│   │   ├── Filter.h
│   │   └── Filter.cpp
│   └── UI/
│       └── CommonLookAndFeel.h
├── PluginA/
│   ├── CMakeLists.txt
│   └── Source/
├── PluginB/
│   ├── CMakeLists.txt
│   └── Source/
└── PluginC/
    ├── CMakeLists.txt
    └── Source/

Root CMakeLists.txt:

cmake_minimum_required(VERSION 3.22)
project(MyPlugins)
 
add_subdirectory(external/JUCE)
 
# Shared library
add_library(SharedCode STATIC
    shared/DSP/Filter.cpp
    shared/UI/CommonLookAndFeel.cpp
)
target_include_directories(SharedCode PUBLIC shared/)
 
# Plugins
add_subdirectory(PluginA)
add_subdirectory(PluginB)
add_subdirectory(PluginC)

Plugin CMakeLists.txt:

juce_add_plugin(PluginA
    PLUGIN_CODE PlgA
    ...
)
 
target_link_libraries(PluginA PRIVATE
    SharedCode
    juce::juce_audio_processors
)

Build Configuration

CMakePresets.json

{
  "version": 6,
  "configurePresets": [
    {
      "name": "default",
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    },
    {
      "name": "debug",
      "inherits": "default",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    },
    {
      "name": "macos-release",
      "inherits": "default",
      "generator": "Xcode",
      "cacheVariables": {
        "CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
        "CMAKE_OSX_DEPLOYMENT_TARGET": "10.13"
      }
    },
    {
      "name": "windows-release",
      "inherits": "default",
      "generator": "Visual Studio 17 2022",
      "architecture": "x64"
    }
  ],
  "buildPresets": [
    {
      "name": "release",
      "configurePreset": "default",
      "configuration": "Release"
    }
  ]
}

Testing Your Structure

Local Verification

# Clean clone test
cd /tmp
git clone --recursive YOUR_REPO_URL test-clone
cd test-clone
 
# CMake configuration test
cmake -B build -DCMAKE_BUILD_TYPE=Release
 
# Build test
cmake --build build --config Release
 
# Check output
ls build/YourPlugin_artefacts/Release/

Checklist

  • Repository clones with all dependencies
  • CMake configures without errors
  • Build completes for Release configuration
  • Plugin binaries are in expected location
  • All resources are embedded

Common Structure Issues

Missing Submodules

Error:

CMake Error: add_subdirectory given source "external/JUCE" which is not a directory.

Fix:

git submodule update --init --recursive

Wrong File Paths

Error:

CMake Error: Cannot find source file: Source/PluginProcessor.cpp

Fix: Verify paths in target_sources() match actual file locations.

Missing Resources

Error:

error: 'BinaryData.h' file not found

Fix: Ensure juce_add_binary_data() is called and linked:

juce_add_binary_data(Resources SOURCES ...)
target_link_libraries(YourPlugin PRIVATE Resources)

Next Steps