DaisySP Documentation

repository·master·Indexed 22 days ago

https://github.com/electro-smith/daisysp

An open-source C++ Digital Signal Processing (DSP) library providing modular components for audio software development. Designed for embedded hardware (Daisy Audio Platform), audio plugins (VST, AU, JUCE), mobile apps, and VCV Rack modules. Features include control signal generators, drum synthesis, dynamics and effects processors, filters, noise generators, physical modeling synthesis, and sampling engines.

Tokens
1.4K
Snippets
4
Records
8
Agent score
29%

What's inside DaisySP

  1. Overview of DaisySP features and modules

    master

    DaisySP is a modular C++ DSP library containing various component categories:

    • Control Signal Generators: AD/ADSR Envelopes, Phasor
    • Drum Synthesis: Analog/Synth Bass/Snare Drum Models, HiHat
    • Dynamics Processors: Crossfade, Limiter
    • Effects Processors: Phaser, Wavefolder, Decimate, Overdrive
    • Filters: One pole Lowpass and Highpass, FIR, SOAP
    • Noise Generators: Clocked Noise, Dust, Fractal Noise, Particle Noise, Whitenoise
    • Physical Modeling Synthesis: Karplus Strong, Resonators, Modal Synthesis
    • Sampling Engines: Granular Player
    • Synthesis Methods: Subtractive, Physical Modeling, FM
    • Utilities: Math Functions, Signal Conditioning, Aleatoric Generators, Looper, DCBlocker
  2. Follow the DaisySP C++ Naming Conventions

    master

    When contributing to or writing modules for DaisySP, follow these naming rules to maintain consistency:

    • Type Names: Use PascalCase (e.g., ModuleName, CallbackId).
    • Function Names: Use PascalCase (e.g., Process, Init).
    • Variable Names: Use snake_case with all lowercase letters (e.g., input_level).
    • Private Member Variables: Use snake_case with a trailing underscore to avoid clashes with function arguments (e.g., param_).
    • Constant Names: Prefix with k and use PascalCase (e.g., kConstantName).
    • Enums: Currently, enums are defined outside classes with a MODULENAME_ prefix. They use trailing commas and include a MODULENAME_ENUM_LAST entry to represent the count of values.
  3. Format code using Allman braces and 4-space tabs

    master

    DaisySP uses the Allman bracing style and a specific tab configuration:

    • Braces: Place opening braces on a new line following the function or control statement.
    • Tabs: Use 4 spaces per indentation level.
    // Allman style:
    void do_something()
    {
        foo = bar;
    }
    
    // Instead of:
    void do_something() {
        foo = bar;
    }
  4. Generate documentation using inline markdown comments

    master

    Header files are parsed by a Python script to generate reference documentation. To control the output, use specific comment syntax:

    • Sections/Newlines: Use a blank comment line (// ) to force a line break in the generated markdown. Consecutive lines without a blank line will be merged into a single line.
    • Code Blocks: Wrap code you wish to export in ~~~~ markers.

    Example:

    // # Section Title
    // Description text
    // 
    // This text will be on a new line because of the blank line above.
    // ~~~~
    void some_function();
    // ~~~~
  5. Prevent circular dependencies with header guards

    master

    All header files must use both #pragma once and traditional header guards to prevent circular includes.

    Header Guard Naming Convention: Use the format DSY_MODULENAME_H, where MODULENAME is the file or class name.

    Example:

    #pragma once
    #ifndef DSY_MODULENAME_H
    #define DSY_MODULENAME_H
    
    // ... content ...
    
    #endif // DSY_MODULENAME_H
  6. Implement a standard DaisySP module

    master

    When creating a new module, follow this structure for the header and implementation files. Note the use of the daisysp namespace, Allman braces, trailing underscores for private members, and the specific enum pattern.

    Header Template (modulename.h):

    // # Markdown Title
    // Description
    //
    // Details
    
    #pragma once
    #ifndef DSY_MODULENAME_H
    #define DSY_MODULENAME_H
    
    namespace daisysp
    {
    
    enum
    {
        MODULENAME_STATE_A,
        MODULENAME_STATE_B,
        MODULENAME_LAST,
    };
    
    class ModuleName
    {
        public:
        ModuleName () {}
        ~ModuleName {}
    
        void Init();
    
        float Process(const float &in);
    
        inline void SetParam(const float &param) { param_ = param; }
    
        void SetComplexParam(const float &complex_param);
    
        private:
    
        float param_;
        float foo_bar_;
        float a_, b_;
    };
    
    } // namespace daisysp
    
    #endif // DSY_MODULENAME_H

    Implementation Template (modulename.cpp):

    #include <system_include.h>
    #include "modulename.h"
    
    using namespace daisysp;
    
    void ModuleName::Init()
    {
        param_ = 0.0f;
        a_ = 0.0f;
        b_ = 1.0f;
    }
    
    float ModuleName::Process(const float &in)
    {
        return (in * param_) + a_ - b_;
    }
    
    void ModuleName::SetComplexParam(const float &complex_param)
    {
        a_ = complex_param;
        b_ = 1.0f - complex_param;
    }
    // See the full template in the content section.
  7. Basic usage example with Oscillator and Filter

    master

    The following example demonstrates a common DSP pattern: using an LFO to modulate the frequency of a One-Pole filter, which processes a sawtooth wave from an oscillator.

    Key steps in the processing loop:

    1. Call .Process() on oscillators/LFOs to get the next sample.
    2. Use .SetFrequency() to update filter parameters.
    3. Call .Process(input) on filters to apply the effect to an input signal.
    #include "daisysp.h"
    
    static daisysp::OnePole flt;
    static daisysp::Oscillator osc, lfo;
    float saw, freq, output;
    
    for(size_t i = 0; i < size; i++)
    {
      freq = lfo.Process();
      saw = osc.Process();
    
      flt.SetFrequency(freq);
      output = flt.Process(saw);
    
      out[i] = output;
    }