This script implements a piano playing a comping rhythm. It uses a random number generator combined with a predefined set of weights to create unique patterns for each measure.
The script makes use of the Calf FluidSynth LV2 plugin, the configuration for this plugin is defined in a separate class included here via the dofile directive:
dofile("fluidsynth.bip")
Define the class and member data:
class CompPiano {
piano = FluidSynth(0)
weights = [30, 0, 30, 30, 0, 50,
30, 0, 30, 30, 0, 50]
rand = Math.Random()
Start a method to schedule the comping for a particular measure, with three arguments:
function schedule(measure, power, chord) {
Objects are passed by reference so make a local copy ("clone") of the chord, this allows local modifications without any side effects to the caller:
local ch = clone chord
Now with the random number generator, choose a random chord inversion up to the size of the chord, zero equals "don't invert at all":
local level = rand.integer(ch.size())
if(level) { ch.invert(level) }
Calculate a velocity level based on the incoming power level, play the chord harder when the power is high and softer for lower power values:
ch.velocity(30 + power / 2)
Loop over each quarter note triplet:
for(local i = 0; i < 12; i++) {
Adjust the weight for this triplet by the incoming power value, higher power values will mean more chance of firing a chord for this note:
local chance = weights[i] * power / 100
Call the random number generator for an integer in the range 1-100, if it is under the weight for this note then schedule the chord to play:
local pick = rand.integer(100) + 1
if(pick <= chance) {
piano.schedule(ch, measure + i/12.0)
}
}
}
Define a simple method for an audio output as this class itself is not of type Audio.Source and so cannot be connected directly to e.g. a system output or audio mixer. The piano variable holds a FluidSynth Object which is of type Audio.Source:
function output() { return piano }
End of the class. See the main script for an example of using this class.
}
dofile("fluidsynth.bip")
class CompPiano {
piano = FluidSynth(0)
weights = [30, 0, 30, 30, 0, 50,
30, 0, 30, 30, 0, 50]
rand = Math.Random()
function schedule(measure, power, chord) {
local ch = clone chord
local level = rand.integer(ch.size())
if(level) { ch.invert(level) }
ch.velocity(30 + power / 2)
for(local i = 0; i < 12; i++) {
local chance = weights[i] * power / 100
local pick = rand.integer(100) + 1
if(pick <= chance) {
piano.schedule(ch, measure + i/12.0)
}
}
}
function output() { return piano }
}
This work is licensed under a
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.