Creating and Scheduling MIDI Notes

In this example we will make a simple drum beat by scheduling MIDI notes on an LV2 sampler.

Audio Setup

The first step is to create the sampler, in this case we have chosen the Fabla sampler from OpenAV Productions. The plugin URI alone is enough to create any LV2 plugin with its default configuration but we can also optionally specify a plugin preset at creation time, which is a configuration that has been predefined by the plugin creators.

In this case we will use the "fabla808" preset which loads fabla with a set of classic 808-sounding samples:



local sampler = Lv2.Plugin("http://www.openavproductions.com/fabla", "fabla808")


Now we connect the sampler to the system outputs:



local output = Audio.StereoOutput("main", "system:playback_1", "system:playback_2")
output.connect(sampler)


Now we have a sampler, samples loaded, connected directly to the system playback channels. This configuration is a simpler than that in the basic connections example, for instance we have not connected any sort of input.

With no inputs we cannot play the sampler with a keyboard or other controller. How can we play it? We can create MIDI notes and send them to the sampler programmatically, from within the script.

Creating Notes

When we create a MIDI note we specify the following values:

Here's how we create the notes that we need:



local kickNote = Midi.Note(37, 127, 1, 4)
local clapNote = Midi.Note(38, 127, 1, 4)
local maracasNote = Midi.Note(47, 127, 1, 4)


In this case we have created three new variables and assigned them to three new notes, all of which have a velocity of 127 and a length of one quarter note. The notes differ in pitch value, e.g. the "clap" sound is note number 38 in the fabla808 kit.

Scheduling Notes

Now in order to play these notes we use the schedule method of the LV2 plugin. As the name implies we are not playing the notes in real time but rather scheduling them to play at a particular time in the transport.

We want to play the same notes for several measures so we make an outer for loop to count the measures and then schedule the notes for each measure within this loop. Similarly we make an inner for loop to count the beats within each measure and schedule notes on each beat.



for(local measure = 1; measure <= 16; measure++) {
    // clap on 2nd and 4th beat
    sampler.schedule(clapNote, measure, 1, 4)
    sampler.schedule(clapNote, measure, 3, 4)
    // kick on each beat, maracas on each offbeat
    for(local b = 0; b < 4; b++) {
        sampler.schedule(kickNote, measure, b, 4)
        sampler.schedule(maracasNote, measure, (b * 2) + 1, 8)
    }
}


Playing the Script

Now if we were to play the script at the command line, what we hear depends on the current state of the transport:

So at this point we can control the script by starting any application that is able to act as a transport master, typically a DAW or drum machine appliation (on Linux that includes Ardour, Qtractor, Hydrogen, etc.). The script will play the scheduled notes on measures 1-16 and then stop playing.

We can also use the transport controls of the transport master application to control the script's playing, for instance setting the transport to a particular location, pausing, restarting etc. We can even set loop points and loop part of the script, if this is supported by the external application.

Alternatively we can have the script play itself - we do that by making the script itself the transport master:



Transport.Master(123)


If the above line executes sucessfully the script is now the transport master, set to a tempo of 123 bpm.

Now to start the transport:



Transport.start()



Complete Script

local sampler = Lv2.Plugin("http://www.openavproductions.com/fabla", "fabla808")

local output = Audio.StereoOutput("main", "system:playback_1", "system:playback_2")
output.connect(sampler)

local kickNote = Midi.Note(37, 127, 1, 4)
local clapNote = Midi.Note(38, 127, 1, 4)
local maracasNote = Midi.Note(47, 127, 1, 4)

for(local measure = 1; measure <= 16; measure++) {
    // clap on 2nd and 4th beat
    sampler.schedule(clapNote, measure, 1, 4)
    sampler.schedule(clapNote, measure, 3, 4)
    // kick on each beat, maracas on each offbeat
    for(local b = 0; b < 4; b++) {
        sampler.schedule(kickNote, measure, b, 4)
        sampler.schedule(maracasNote, measure, (b * 2) + 1, 8)
    }
}

Transport.Master(123)

Transport.start()


Tutorial IndexList of All Examples


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