ChoroBox by Carlos Eduardo Mello (2012) ChoroBox is an Arduino-based project that implements an automated machine for "choro" music, which can be used by musicians to practice melodic lines with an interactive accompaniment, when connected to a Mac OS X system. Dependencies This project is based on the ardacc and Peduino projects. For software download and details on how to build a Peduino Box, please refer to http://www.msu.edu/~mellocar/. ChoroBox works by sending MIDI data to a synthesizer, which is expected to produce acoustic guitar sounds (nylon) on channel 1. The data can be routed directly from ardacc's source endpoint (CoreMIDI), or indirectly by connecting the synthesizer to OS X's IAC (Inter Application) MIDI driver. Development Status This project is currently under development and being tested with a prototype version of the Peduino device. The current version provides a basic accompaniment pattern based on a simple, repeated, rhythmic pattern. Development plans for the future include: - bass line improvisation - rhythmic variations in the accompaniment - alternate rendering for songs with ternary (waltzes) and other metrics Rendering Harmonic Changes The data model used in this project reflects a very simplified model for rendering harmony changes in choro music, with the classical guitar (nylon strings). This is based on a syncopated rhythmic pattern, which is very typical of Brazilian music:
Most of this music is in 2/4. The down beats are assigned to the bass, played by the thumb on one of the lower 3 three strings (E, A, D). The remaining strings (G, B, E) are typically struck together for the "up" parts of the beat. Harmony changes in choro are fairly fast, often entailing a different chord for each beat. Real performances of this kind of music are a lot more elaborate than represented here. Both melody and accompaniment undergo constant rhythmic variations. In addition to the traditional guitar accompaniment, an obligatory 7-string guitar ("sete cordas") is usually responsible for a fast moving, improvised bass line, which provides a constant counterpoint to the main melodic line. However, for the scope of this implementation, these features are prohibitively complex and will be left for future development. Chords in ChoroBox are defined as array indexes. Each index retrieves a pitch from each of the five synchronized arrays in the code. Pitches are given in MIDI note number. Value '60' corresponds to 'middle C'. Each unit increment changes the pitch by a half step. The two bass arrays alternate for beats with the same chord. The other string arrays correspond to the 3 highest strings on the guitar. This version of ChoroBox plays them always together. Song Data With the scheme above, substituting song data for performing different pieces is quite straightforward. As long as none of the code is modified, it is just a matter of saving the 'chorobox.ino' sketch with a different name (preserving the name extension) and replacing the chord/song data as outlined bellow (instructions and example). The project can then be quickly recompiled with the Arduino Environment and loaded into the device for performance. Replacing Song Data: 1. Locate the section marked [USER CODE: SONG] in the sketch; 2. Under CHORD PITCHES, look at the lines that start with "byte bass1 ", "byte bass2 ", etc. Each line represents a string in the guitar; 3. Each chord has a number entry in each string line inside the curly braces {55,54,52, } on the corresponding string line. 4. In order to replace the chords, you need to: (a) Figure out which chord needs to be played - this is usually shown on the music sheet as a chord change above the solo notes... (b) Decide how the fingers should stop the frets for each chord and identify the exact pitch/octave each string will produce;
(c) Convert each note to its MIDI equivalent (see table bellow); (d) Insert the appropriate note number in the corresponding string/chord slot -- note that: the notes inside the curly braces for each string are separated by commas; a commented line above the string arrays indicates the index number for each chord; notes in different strings but with the same index make up a given chord (see example bellow); (e) Be careful not to forget the commas between notes, leave extra commas, or otherwise modify the code in any way other than what is instructed here -- doing so will make it impossible to execute the sketches code. (f) When all the chords have been inserted, update the chord count in the following line: const byte NUMBER_OF_CHORDS = 25; As you can see in the code, array indexes start with 0, so in order to be correct; NUMBER_OF_CHORDS should be one unit greater than the index of the last chord. (g) Once the chords are all represented in the code, you need to indicate what chord is played in each beat of the music; this is done by simply inserting a chord index in the appropriate space in the song array; as with the chord arrays, the number of beats for the song needs to be replaced: const int NUMBER_OF_BEATS = 102; int song[number_of_beats] = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 4, 5,... }; Example: Suppose you want to insert a G major chord as the first item in your chord array. There are many ways of playing a G major chord on the guitar, so let's choose one:
With the fingers places like this we have G and D for the bass notes and B, D, G for the upper strings. The MIDI protocol uses integers to represent pitches. We want to send notes as MIDI data, so each pitch needs to be converted to the MIDI format. MIDI spec says that a middle C should be coded as number '60'. The other notes can be deduced from this reference point by adding or subtracting one unit for each half-step. Thus, the notes in our chord can be noted as MIDI note numbers as follows: bass1 = 55, bass2 = 62, string1 = 71, string2 = 74, string3 = 79 Now we need to place these numbers in the appropriate position in each string array, like this: // Song Definitions // CHORD PITCHES const byte NUMBER_OF_CHORDS = 25; // ============== CHORD INDEXES: 0 1 2 byte bass1[number_of_chords] = {55,60,62}; byte bass2[number_of_chords] = {62,64,57}; byte string1[number_of_chords] = {71,67,69}; byte string2[number_of_chords] = {74,72,72}; byte string3[number_of_chords] = {79,76,78}; Note that the numbers we converted above are now occupying the first slot in each array, corresponding to index 0. Following the same procedure, we can represent other chords like for example C and D7 and place the corresponding numbers in slots 1 and 2. In order to make this code usable, we need to change the number of chords to 3:
const byte NUMBER_OF_CHORDS = 3; Now our chord collection contains the data necessary for a basic I-IV-V-I chord progression, and we can reuse these chords in the song accompaniment as many times as necessary, just by referring to the corresponding index number like this: // CHORD CHANGES // each index inside this array is a reference to one of the chords above const int NUMBER_OF_BEATS = 8; int song[number_of_beats] = { 0, 1, 3, 0, 1, 3, 3, 0 }; Before compiling and executing the sketch on the Peduino, remember to change the number of beats to reflect the number of entries in your song array. Here too, commas separate the numbers and any mistakes in the syntax will make the program "crash and burn".