New to Plugin Development

Never built an audio plugin before? No problem. BeatConnect provides everything you need to go from zero to a professional, signed plugin.

What is an Audio Plugin?

Audio plugins are software that processes or generates audio within a DAW (Digital Audio Workstation) like:

  • Ableton Live
  • FL Studio
  • Logic Pro
  • Pro Tools
  • Reaper

Plugins come in various formats:

FormatPlatformNotes
VST3Windows, macOSMost universal format
AU (Audio Units)macOS onlyRequired for Logic Pro
AAXWindows, macOSPro Tools only

Learning Path

Week 1: Setup & First Build

  1. Check requirements
  2. Connect GitHub
  3. Clone the starter template
  4. Build your first (unchanged) plugin
  5. Install and test in your DAW

Week 2: Understanding the Code

  1. Explore the template structure
  2. Modify a parameter (gain, frequency)
  3. Rebuild and test changes
  4. Learn the audio processing basics

Week 3: Adding Features

  1. Add a new parameter
  2. Create a simple effect (tremolo, filter)
  3. Design a basic UI
  4. Build and distribute to friends

Week 4+: Going Professional

  1. Add license activation
  2. Create product listing
  3. Set up marketing
  4. Launch and sell!

Using the Starter Template

Clone the Template

# Clone the BeatConnect plugin template
git clone https://github.com/beatconnect/plugin-template my-first-plugin
cd my-first-plugin
 
# Remove the template's git history
rm -rf .git
 
# Initialize your own repo
git init
git add .
git commit -m "Initial commit from BeatConnect template"
 
# Push to your GitHub
gh repo create my-first-plugin --private --source=. --push

Template Structure

my-first-plugin/
├── CMakeLists.txt          # Build configuration
├── src/
│   ├── PluginProcessor.h   # Audio processing logic
│   ├── PluginProcessor.cpp
│   ├── PluginEditor.h      # UI/interface
│   └── PluginEditor.cpp
├── external/
│   └── JUCE/               # JUCE framework (submodule)
├── resources/
│   └── logo.png            # Plugin icon
└── README.md

Key Files Explained

PluginProcessor.cpp

This is where the magic happens. The processBlock function receives audio and processes it:

void MyPluginAudioProcessor::processBlock(AudioBuffer<float>& buffer,
                                          MidiBuffer& midiMessages)
{
    // Get the gain parameter value
    float gain = *parameters.getRawParameterValue("gain");
 
    // Apply gain to all samples
    for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
    {
        float* channelData = buffer.getWritePointer(channel);
        for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
        {
            channelData[sample] *= gain;
        }
    }
}

PluginEditor.cpp

This creates the user interface:

MyPluginAudioProcessorEditor::MyPluginAudioProcessorEditor(MyPluginAudioProcessor& p)
    : AudioProcessorEditor(&p), processor(p)
{
    // Create a slider for the gain parameter
    gainSlider.setSliderStyle(Slider::RotaryVerticalDrag);
    gainSlider.setTextBoxStyle(Slider::TextBoxBelow, false, 80, 20);
    addAndMakeVisible(gainSlider);
 
    // Connect the slider to the parameter
    gainAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(
        processor.apvts, "gain", gainSlider);
 
    setSize(400, 300);
}

AI-Assisted Development

BeatConnect integrates AI tools to help you learn and build faster.

Code Generation

Use AI to scaffold new features:

"Add a low-pass filter with cutoff and resonance parameters"

// AI generates:
// - Parameter definitions
// - DSP processing code
// - UI components
// - CMake configuration updates

Code Explanation

Understand existing code:

"Explain what this processBlock function does"

// AI explains:
// - What each line does
// - Why it's structured this way
// - Common modifications

Debugging Help

Fix issues faster:

"My plugin crackles at high sample rates"

// AI suggests:
// - Buffer size checks
// - Denormal prevention
// - Processing optimization

Important: AI is a tool, not a replacement for learning. Use it to accelerate understanding, not to blindly copy code you don’t understand.

Essential Concepts

Parameters

Parameters are values the user can adjust:

// Define parameters
parameters.createAndAddParameter(
    "gain",           // ID
    "Gain",           // Name
    "",               // Label
    NormalisableRange<float>(0.0f, 2.0f, 0.01f),  // Range
    1.0f,             // Default
    nullptr,          // Value to text
    nullptr           // Text to value
);

Audio Buffers

Audio comes in buffers (arrays of samples):

// Buffer info
int numChannels = buffer.getNumChannels();  // Usually 2 (stereo)
int numSamples = buffer.getNumSamples();    // Usually 64-512
 
// Access samples
float sample = buffer.getSample(channel, sampleIndex);

Sample Rate

The number of samples per second:

  • 44,100 Hz — CD quality
  • 48,000 Hz — Video standard
  • 96,000 Hz — High resolution

Your code must work at any sample rate:

void prepareToPlay(double sampleRate, int samplesPerBlock)
{
    // Store sample rate for calculations
    this->sampleRate = sampleRate;
 
    // Calculate time-based values
    float delaySeconds = 0.5f;
    int delaySamples = (int)(delaySeconds * sampleRate);
}

Common Beginner Mistakes

1. Dividing by Zero

// BAD
float normalized = value / maxValue;  // Crashes if maxValue is 0
 
// GOOD
float normalized = maxValue > 0 ? value / maxValue : 0.0f;

2. Forgetting to Handle Stereo

// BAD - Only processes first channel
buffer.getWritePointer(0);
 
// GOOD - Process all channels
for (int ch = 0; ch < buffer.getNumChannels(); ++ch)
{
    float* channelData = buffer.getWritePointer(ch);
    // Process...
}

3. Denormal Numbers

Very small numbers can cause CPU spikes:

// Add to processBlock
for (int ch = 0; ch < numChannels; ++ch)
{
    FloatVectorOperations::add(buffer.getWritePointer(ch),
                               1.0e-15f,  // Tiny DC offset
                               numSamples);
}

4. Not Saving State

Your parameters should persist when the DAW project is saved:

// Override these methods
void getStateInformation(MemoryBlock& destData)
{
    auto state = parameters.copyState();
    std::unique_ptr<XmlElement> xml(state.createXml());
    copyXmlToBinary(*xml, destData);
}
 
void setStateInformation(const void* data, int sizeInBytes)
{
    std::unique_ptr<XmlElement> xml(getXmlFromBinary(data, sizeInBytes));
    if (xml.get() != nullptr)
        parameters.replaceState(ValueTree::fromXml(*xml));
}

Resources for Learning

Official Documentation

YouTube Channels

  • The Audio Programmer — Beginner-friendly JUCE tutorials
  • ADC (Audio Developer Conference) — Deep technical talks
  • Akash Murthy — DSP and plugin development

Communities

Books

  • Designing Audio Effect Plugins in C++ — Will Pirkle
  • DAFX: Digital Audio Effects — Udo Zölzer
  • The Audio Programming Book — Richard Boulanger

Your First Real Effect: Tremolo

Let’s build a simple tremolo effect (volume modulation):

class TremoloProcessor : public AudioProcessor
{
private:
    float phase = 0.0f;
    float rate = 5.0f;    // Hz
    float depth = 0.5f;   // 0-1
 
public:
    void processBlock(AudioBuffer<float>& buffer, MidiBuffer&)
    {
        float phaseIncrement = rate / getSampleRate();
 
        for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
        {
            // Calculate LFO value (sine wave)
            float lfo = 0.5f + 0.5f * std::sin(2.0f * MathConstants<float>::pi * phase);
 
            // Apply depth
            float modulation = 1.0f - depth + (depth * lfo);
 
            // Apply to all channels
            for (int ch = 0; ch < buffer.getNumChannels(); ++ch)
            {
                buffer.getWritePointer(ch)[sample] *= modulation;
            }
 
            // Advance phase
            phase += phaseIncrement;
            if (phase >= 1.0f) phase -= 1.0f;
        }
    }
};

Next Steps

  1. Build your first plugin
  2. Experiment with the template
  3. Join the Discord community for help
  4. Share your creations!

Remember: Every professional plugin developer started exactly where you are now. The key is to start simple, build consistently, and never stop learning.