Comp Piano

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()

Scheduling

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)
      }
    }
  }

Audio Output

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.


}



Complete Script

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)
      }
    }
  }

  function output() { return piano }

}


Tutorial IndexList of All Examples


Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.