My audio/midi sequencer of choice is Ableton Live. It has several features to keep me busy but one of its most useful and unique features is the session view. In it, you can create little "clips" that contain audio or midi and launch them programmatically using follow-actions. I'm not going to explain the inner workings of Ableton's session view but just know that it allows you to compose non-linearly, by allowing you to play discrete chunks of audio/midi for pre-determined amounts of time, followed by another pre-determined (or randomly selected) clip. This behavior was the inspiration for the mobo sequencer.
The mobo sequencer exploits the well known DotNet method System.Beep(frequency, duration). This is more commonly known as the obnoxious sound that comes off of your x86 motherboard whenever you make a huge mistake (I hear it often). The sound doesn't have to be entirely obnoxious though. By recording the sequenced output and applying eq, compression and/or various other effects, the sound is more than useable in many forms of electronic music.
So we have a sound that's asking for a frequency and duration. All we need in order to make a musically relevant sequencer for this sound is a way to come up with the frequency values of the 12-note chromatic scale based on note value and the time values for common music notes (whole notes, half notes, quarter notes, sixteenth notes, etc...). The frequency parameter is expressed in Hz and the duration parameter is expressed in milliseconds. This sequencer doesn’t require the rock solid performance of a full featured daw or any type of clock precision. As a matter of fact, the “sequencer” portion is just a 2D array of points that will be sequentially fed into the System.Beep method.
In Western music, the frequency intervals we use are mostly the result of simple harmonic ratios of physical structures (and compromise to allow for easy transposition). There are fascinating articles about the evolution of what we call music all over the internet. However, for the purposes of this article (and any other discussion about Western music for that matter), just know this:
(A) Western music is based on a scale that says A4 is 440 Hz.
(B) The intra-note relationship follows the formula: (Freq = myFreq * 2N/12) where myFreq is the starting note frequency and N is the number of musical half steps away that you are from myFreq. N can be positive, negative or zero. So if A4 is 440 Hz and I wanted to know the frequency of G4 (10 positive half steps away from A4) then (Freq = 440 * 210/12) or G4 = 784. If I was at G4 and I wanted to know the freq of E4 (3 negative half steps away from G4) then (Freq = 784 * 2-3/12) or E4 = 659.28.
Here is the function in VB (formula normalized to the lowest note on the interface to take advantage of the convenient selected index value of the ddl note box… Reverse function just return steps from lowest note based on selected index).
Function GetFreq(ByVal intNote As Integer) As Double
If intNote = -1 Then
Dim dbLowestNote As Double = 38.89
Return dbLowestNote * (2 ^ (Reverse(intNote) / 12))
Audio programs usually express the overall tempo for a session in beats per minute (bpm). Musical notation is usually expressed in notes, ie.. whole note, half note, quarter note, etc...) What we need is a formula that can take any given bpm input and return the number of milliseconds in a note. From that note, we can derive the number of milliseconds in any other note. As it turns out, a very elegant formula exists that returns the number of milliseconds in a quarter note given any bpm: (QuarterNote = 60000/bpm).
Here is the function in VB (I’m feeding the function the note length and tempo off the interface):
Function GetTime(ByVal strNoteLength As String) As Double
If strNoteLength = "" Then
Dim dbQNote As Double = 60000 / CDbl(txtBPM.Text)
Select Case strNoteLength
Return dbQNote * 8
Return dbQNote * 4
Return dbQNote * 2
Return dbQNote * (1 / 2)
Return dbQNote * (1 / 4)
Return dbQNote * (1 / 8)
Mobo sequencer allows you to sequence discrete chunks of notes and tie them together by selecting a play behavior. Each pattern can be made to play any number of times, then after the looping completes, the next pattern plays, a random pattern plays or the loop can terminate. The interface allows for each pattern to be individually created and tested before kicking off the Global Playback Loop. The Global Playback loop plays loop 1 first.
There are several things that could be done to improve this app like threading the playback for example so it can stop after starting a sequence, a shuffle or millisecond offset of individual notes, more patterns, the ability to save and load patterns… just to name a few. Also interface elements should probably be their own reusable user controls. In other words, I wouldn’t look at this project as a shining example of good programming practices, rather a fun, quick and dirty little project.
Download, unzip and have fun!