Coder Social home page Coder Social logo

clover's Introduction

Clover

Clover is a real time graph-based signal processing framework. It was initially developed for audio but can be used for arbitrary types of discrete time signals.

This project is experimental and liable to change drastically. I am working toward a stable iteration of the library, but for now I recommend referring to specific commit hashes if you consume this library. Clover requires a compiler with C++20 support.

Clover is permissively licensed and depends on open source software. See LICENSE and THIRD_PARTY.md.

Dependencies

Clover uses find_package to look for the following dependencies

  • portaudio
  • SndFile
  • RtMidi

The include paths to these dependencies should be provided to Clover by populating the list variable CLOVER_INCLUDE_DIRECTORIES.

Graph

Clover implements a directed graph for signal routing. The graph is not inherently buffered; the base Frame concept does not require that the data field is a buffer. There may be performance tradeoffs with an unbuffered approach, but it allows for complex and phase-sensitive modulations that might otherwise be hard to achieve. There is not any technical limitation to implementing buffered frames if you should choose to do so.

Clover processes the graph in a single thread. Effort was put into exploring multithreading with the ultimate conclusion that it is not currently suitable for Clover's processing model. Future effort may be made toward SIMD optimizations for the core algorithms provided in the library; Library users may choose to leverage SIMD on their own as well.

Extensible

Abstract base:

template <FrameConcept InputType, FrameConcept OutputType>
class Node {
    OutputType tick(const InputType input) = 0;
};

Example implementation:

class AudioToRgb : public Node<AudioFrame<1>, RgbFrame> {
    float lightness;

    RgbFrame tick(const AudioFrame<1> input) {
        return RgbFrame(doMagicalDspThing(input));
    }

    void adjustLightness(float lightnessFactor) {...}
    RgbFrame doMagicalDspThing(const AudioFrame<1> input) {...}
}

Type-Level IO Matching

Clover ensures safety when connecting nodes by employing type-level IO matching. This ensures that only compatible nodes can be connected.

class Oscillator : public Node<EmptyFame,     AudioFrame<1>> {...};
class PanMono    : public Node<AudioFrame<1>, AudioFrame<2>> {...};

template <int ChannelCount>
class AudioNode
        : public Node<AudioFrame<ChannelCount>, AudioFrame<ChannelCount>> {...};
class Reverb : public AudioNode<2> {...};

Oscillator osc; 
PanMono pan;
StereoReverb reverb;

// Valid: all IOs match
osc >> pan >> reverb >> audioOutput.rootNode;

// Invalid: Output AudioFrame<1> of Osc doesn't match input AudioFrame<2> of Reverb
osc >> reverb;
// - will not compile
// - intellisense shows angry squigs

Feedback Circuits and Acyclicity

Graph cycles are broken using conditional evaluation and state substitution. Practically speaking, feedback cycles are made acyclic by using the Node's output value from the previous tick in time.

Interface audioOutput;
float bpm = 160;
int SAMPLE_RATE = 48000;
Time time(bpm, SAMPLE_RATE, &audioOutput.clock);

OscNx<3> synth;
synth.loadPatch(mySynthPatch);

Gain g1;
Filter filter;
FractionalDelayLine<2> delay(SAMPLE_RATE * 3);
Gain feedbackGain;

filter.bandPass();
filter.freq(1000);
filter.reso(0.68);

delay.delay(time.step() * 6);
feedbackGain.gain(Algorithm::db_to_linear(-10.f));

// this graph has a synth with a 3/4 beat dub style band passed echo 
synth >> g1 >> audioOutput.rootNode;
g1 >> filter >> delay >> feedbackGain >> g1;

Non-Audio Nodes

It is possible to implement side effect focused nodes such as step sequencers. There is an abstract base step sequencer that is fairly easy to extend:

struct Rgb {
    uint R;
    uint G;
    uint B;
};

struct RgbCallable {
  virtual void setRgb();
};

void RbgFacilitator(
        const TriggerState &data,
        std::vector<RgbCallable *> &targets) {

    for (RgbCallable *target : targets)
        target->setRgb(data);
}

struct STSQ_Rgb
    : STSQ<Rgb, RgbCallable, RbgFacilitator> {};

MyRgbNode rgbNodeStage1;
MyRgbNode rgbNodeStage2;
STSQ_Rgb rgbStepSequencer;

rgbStepSequencer.targets.emplace_back(&rgbNodeStage1);
rgbStepSequencer.targets.emplace_back(&rgbNodeStage2);

rgbStepSequencer.addPattern(blueStrobe);
rgbStepSequencer.addPattern(purpleWave);
rgbStepSequencer.addPattern(redWhitePulse);

There are semi-baked step sequencers implemented in the project. These may be either further refined or removed in the future.

STSQ_Pitchable stsq_pitch;
stsq_pitch.targets.emplace_back(&synth);
stsq_pitch.addPattern(someMidiNotePattern);

STSQ_Triggerable stsq_trigger;
stsq_trigger.targets.emplace_back(&synth);
stsq_trigger.addPattern(someMelody);

Sample Clock Callback

This callback can be used however you see fit.

interface.clock.registerTickCallback([&](int currentTime) -> void {
    if (isNewQuarterNote()) {
        kick.note(someMidiNote);
        kick.triggerOn(); // key on ADSR etc
    } else if (hasSixteenthNoteElapsed()) {
        kick.triggerOff(); // key off ADSR etc
    }

    // crunch some operations every clock increment
    // without needing to implement a Node
});

Building

Clover uses CMake for the builds and vcpkg for dependency management. Refer to CMakeLists.txt and vcpkg documentation.

clover's People

Contributors

robertalbus avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.