Euclidean Rhythm Generator

Euclidean Rhythm Generator is a VST plugin made with JUCE for use in DAWs, made for an university subject called Musical Computing.

Tools used

JUCE is a open-source framework that allows us to develop audio apps for Windows, macOS, Linux, iOS and Android; and plugins in VST, VST3, AU, AUv3, AAX and LV2; in C++. To learn JUCE, I used The Audio Programmer's channel and the official Juce API documentation. These are the most helpful tutorials for me in this project.

HY-RPE2 is a MIDI sequencer plugin, with 2 sequencing modes: grid and euclidean. I'm interested in analyzing euclidean sequencing, which is represented in this window: 

The most striking elements are the concentric circles representing each euclidean rhythms, specified by their matching row. It acts as a clock, and HY-RPE2 sends a MIDI event when the division of the tick is colored. I aim to reproduce each these parameters in my plugin.

Development of the plugin

JUCE provides several project templates. I chose the Basic Plug-In template. It automatically creates .h and .cpp for PluginProcessor and PluginEditor classes.

The PluginEditor class is the one that arranges and draws the graphical elements in the window. I want it to divide each euclidean rhythm by rows, as HY-RPE2 does. I created the EuclideanRhythm class that inherits from the juce::Component class.

#define ROWS_NUMBER 4

EuclideanRhythm euclideanRhythm[ROWS_NUMBER];

This way, despite the number of rows is not a variable, the plugin can support any number of rows.

In the screenshots we can see each one of the EuclideanRhythm class' parameters. The type of the MIDI event can be one of these 4: 

The PluginProcessor class processes the audio and MIDI chunks and has to generate MIDI events in the right tempo. The problem breaks down in:

The first problem is solved with the Bressenham algorithm. It's the same that the algorithm that draws an straight line in pixels: simply increment a float and truncate its value.

vector<bool> EuclideanRhythm::bresenhamAlgorithm(int steps, int pulses)

{

    float slope = (float) pulses / steps;

    vector<bool> rhythm;

    int previous = -1;

    for (int i = 0; i < steps; i++) {

          int current = floorf(i * slope);

          rhythm.push_back(previous != current);

          previous = current;

    }

    return rhythm;

}

The second problems is solved by updating the variables every tick of the plugin (60Hz) and generate a new MIDI message with the corresponding pitch in the processing chunk function (48kHz).

void EuclideanRhythm::processMIDI(MidiBuffer& incomingMidiMessages, MidiBuffer& generatedBuffer) {

if (!enabled || soloedRhythms > 0 && !solo || mute)

     return;

 

if (currentBeat != previousBeat) {

     previousBeat = currentBeat;

 

     if (randomGenerator.nextFloat() * 100 < probability && 

         getBeat(currentBeat % (int) stepsSlider.getValue())) {

         int newPitch = pitch;

 

         switch (midiType) {

         case RELATIVE:

             newPitch = referencePitch + relativePitch;

             break;

         case RANDOM:

             newPitch = randomGenerator.nextInt(randomMaxPitch – randomMinPitch + 1) + randomMinPitch;

             break;

         }

 

         MidiMessage newMessage = MidiMessage::noteOn(channel, newPitch, velocity);

                

         generatedBuffer.addEvent(newMessage, 0);

        }

     }

}

Now, we can test the plugin in a real DAW. I used Reaper, and found out that the plugin only runs when the window exists. This is because I create the EuclideanRhythm classes in the editor. I could fix it by moving them to the processor. That way, the plugin continues to send MIDI events even when the window is closed, and its values are kept when we reopen the editor.

The plugin should use the tempo of the DAW automatically. It must play only when we are press play and always the same. Now, the plugin sends messages independently. My solution is that my beat variable would be controlled by the DAW. Now I don't need a BPM variable.

void PluginProcessor::getCurrentDAWBeat()

{

    //Acceder al tiempo del DAW

AudioPlayHead* playHead = getPlayHead();

if (playHead != nullptr) {

     auto playPosition = playHead->getPosition();

 

     if (playPosition != nullopt) {

         auto playPositionInQuarterNotes =

             playPosition->getPpqPosition();

 

         if (playPositionInQuarterNotes != nullopt)

             beat = *playPositionInQuarterNotes;

        }

    }

}

The only thing the plugin lack to be a real app is to save and load the plugin state between sessions. This can be done creating JUCE parameters with the class AudioProcessorValueTreeState. I refactorized all variables with these parameters and then linked them to their corresponding dial, following this example. Automatically, we can save and load their values, undo actions and even automate their values from the DAW.

Resultados

My plugin is fully functional in Reper, with all planned features except for the incoming MIDI type. It supports n euclidean rhythm rows, but this value can't be dynamically changed. I think this would bring some UI problems and save state problems, because each row occupy a place in the save file and the DAW uses them. A simple solution would be to establish a maximum limit to the number of rows, and reserve a fixed size in the save file for that number of rows, but only showing and playing the n first ones.

To test the features of the plugin, I arranged this piece.

I'm proud of being capable to integrate the plugin with the DAW, because during the development I found problems I took for granted, but are essential for a right performance of a plugin - to make it work only when we are playing with the global tempo. Store the values and keep it working when the window is closed, and of course to keep them also between sessions! In fact, all of this is already dealt with by JUCE. Using it has been a good experience due to the great amount of work it provides, the facility to use and learn it and the great online community it has that have answered lots of my doubts.

Possible improvements would be to dynamically change the amount of rows, but I would try to do it with an implementation that doesn't force you to always store the maximum number of rows. Other one would be the Incoming MIDI mode, which would be possible with more practice catching MIDI messages.

HY-RPE2 has lots of more parameters. We could investigate other windows to complete the plugin. The concentric circles are the most important elements, because they give a visual representation of the sound very easely. Implementing it wouldn't suppose extra calculations as the information to construct it already exists in my implementation, but we would have to generate the graphics at runtime and I lack the knowledge to do that at the time.

The last mistake my plugin has is that only sends MIDI messages in crotchets, so no events can be sent faster than one a beat. To fake semiquavers, we would have to use a very fast tempo. This is because we only know which beat is at any moment. Knowing the size of the bar, we could normalize the divisions to match the bar no problem.