Jazz
Combo (Beginners!)
This program is a set of classes which produce
a simple bass, drums, and guitar backing to an awkward solo line.
The solo has constrained stochastic pitches while the rhythm section is
largely deterministic.
A final MIDI file can sound like this:
Click here to view source.
The single source file contains several classes.
Jazz Combo - the main class. JazzDrums, JazzGuitar, JazzBass, and JazzSax.
Lets have a closer look.
import jm.JMC; import jm.music.data.*; import jm.music.tools.* import jm.util.*;
public class JazzCombo implements JMC{ public static void main(String[] args){ new JazzCombo(); } public JazzCombo() { Score s = new Score("CPhrase class example", 120); Part guitarPart = new Part("Guitar",JAZZ_GUITAR, 0); Part bassPart = new Part("Bass", ACOUSTIC_BASS, 1); Part ridePart = new Part("Drums", 0, 9); Part snarePart = new Part("Drums 2", 0, 9); Part saxPart = new Part("Sax", SAXOPHONE, 2); Phrase bassPhrase = new Phrase(); System.out.println("Creating chord progression . . ."); int rootPitch = c4; //set start pitch to C for (int i=0;i<6;i++) { for (int j=0;j<4;j++) { guitarPart.addCPhrase(JazzGuitar.triad (rootPitch)); } bassPart.addPhrase(JazzBass.bassLine(rootPitch)); ridePart.addPhrase(JazzDrums.swingTime()); snarePart.addPhrase(JazzDrums.swingAccents()); saxPart.addPhrase(JazzSax.melody(rootPitch)); rootPitch -= 7; for (int k=0;k<4;k++) { guitarPart.addCPhrase(JazzGuitar.domSeventh (rootPitch)); } bassPart.addPhrase(JazzBass.bassLine2(rootPitch)); ridePart.addPhrase(JazzDrums.swingTime()); snarePart.addPhrase(JazzDrums.swingAccents()); saxPart.addPhrase(JazzSax.melody(rootPitch)); rootPitch += 5; } s.addPart(guitarPart); s.addPart(bassPart); s.addPart(ridePart); s.addPart(snarePart); s.addPart(saxPart); View.show(s); Write.midi(s,"JazzCombo.mid"); } } |
The class above calls on the classes below.
The main() method class calls the JazzCombo constructor which gets Phrases
or CPhrases from each of the support classes.
It then then adds these Phrases/CPhrases to a score, displays it and
saves it as a MIDI file.
Notice that this structure allows you to write new classes for any of the
parts (drums, bass, etc.) without upsetting any of the others.
The use of individual classes also eases maintenance.
In the source code all the classes are in the one file.
By doing this they share the import statements, but if these are copied
then each class can easily be in its own java file.
Notice weather or not the classes are in the same java file they appear
as independent class files when compiled.
class JazzGuitar implements JMC{ public static CPhrase triad(int rootPitch) { int[] pitchArray = new int[3]; pitchArray[0] = rootPitch; pitchArray[1] = rootPitch + 4; pitchArray[2] = rootPitch + 7; CPhrase chord = new CPhrase(); chord.addChord(pitchArray, C, 50); return chord; } public static CPhrase domSeventh(int rootPitch) { int[] pitchArray = new int[4]; pitchArray[0] = rootPitch; pitchArray[1] = rootPitch + 4; pitchArray[2] = rootPitch - 2; pitchArray[3] = rootPitch - 5; CPhrase chord = new CPhrase(); chord.addChord(pitchArray, C, 50); return chord; } } class JazzBass implements JMC{ public static Phrase bassLine(int rootPitch) { Phrase phr = new Phrase(); phr.addNote(new Note(rootPitch, C)); phr.addNote(new Note(rootPitch - 2, C)); phr.addNote(new Note(rootPitch - 3, C)); phr.addNote(new Note(rootPitch - 5, C)); return phr; } public static Phrase bassLine2(int rootPitch) { Phrase phr = new Phrase(); phr.addNote(new Note(rootPitch, C)); phr.addNote(new Note(rootPitch + 4, C)); phr.addNote(new Note(rootPitch + 7, C)); phr.addNote(new Note(rootPitch + 4, C)); return phr; } }
|
This bass class is quite simple. It creates a series of notes based on a
root pitch.
class JazzDrums implements JMC{ public static Phrase swingTime() { Phrase phr = new Phrase(); int ride = 51; phr.addNote(new Note(ride, C)); phr.addNote(new Note(ride, 0.67)); phr.addNote(new Note(ride, 0.33)); phr.addNote(new Note(ride, C)); phr.addNote(new Note(ride, C)); return phr; } public static Phrase swingAccents() { Phrase phr = new Phrase(); int snare = 38; for (int i=0;i<4;i++) { phr.addNote(new Note(REST, 0.67)); phr.addNote(new Note(snare, 0.33, (int)(Math.random()*60))); } return phr; } }
|
Jazz drums are charracterised by a dominance of ride cymbal, this is all
that is used here.
Accents on the snare are added with a call to the Math.random() method to
alter the dynamics.
class JazzSax implements JMC{ public static Phrase melody(int rootPitch) { double[] rhythm1 = {0.34,0.66,0.34,0.66,0.34,0.66,0.34}; double[] rhythm2 = {0.34,0.66,0.34,0.66,1.34}; double[] rhythm3 = {1.0,0.34,0.66,0.34,1.0}; double[] rhythm4 = {0.34,0.66,1.0,1.34}; int[] mode = {0,4,5,7,9}; Phrase phr = new Phrase(); int pitch = (int)Math.random()*12 + 65; int temp = 0; boolean ok = false; int rhythmNumb = (int)(Math.random() *4); int rhythmLength = 0; if (rhythmNumb == 0) rhythmLength = rhythm1.length; if (rhythmNumb == 1) rhythmLength = rhythm2.length; if (rhythmNumb == 2) rhythmLength = rhythm3.length; if (rhythmNumb == 3) rhythmLength = rhythm4.length; phr.addNote(new Note(REST, 0.66)); for(int i=0;i<rhythmLength;i++) { while (ok == false) { temp = (int)(Math.random() * 10) - 5; for(int j=0;j<mode.length;j++) { if ((pitch + temp)%12 == (mode[j] + rootPitch)%12) { pitch += temp; ok = true; break; } } } if (rhythmNumb == 0) phr.addNote( new Note(pitch, rhythm1[i])); if (rhythmNumb == 1) phr.addNote( new Note(pitch, rhythm2[i])); if (rhythmNumb == 2) phr.addNote( new Note(pitch, rhythm3[i])); if (rhythmNumb == 3) phr.addNote( new Note(pitch, rhythm4[i])); ok = false; } return phr; } }
|
Soloing is hard for humans, let alone computers!
This is a poor attempt even though it takes quite some code - compared to
our current tutorial benchmarks.
It uses a pentatonic mode and some set rhythms to constrain the melodic
choice to a half-decent but also predictable level.
I think it might be easier for me to play the solo live :) |