/** * chordComposer.java * * Implementation of abstract equalTemperCcomposer class. * Composes a midi sequence of one or more sets of random chords * derived from equal tempered scales with user specified number * of division to the octave, each set produced by a bentPlayer * object. Also user-configurable are the pitch range, number * of notes in the chord, dynamic range, and general MIDI patch * Writes the sequernce to a standard midi file. * * This module is part of Karl Brown's MIDI programming project. * */ package MidiApps; import java.io.*; import java.util.*; import javax.sound.midi.*; /** * * @author Karl Brown * @version 1.0 * last updated 2/16/2003 */ class playerGroup { int isOn; int minStep; int maxStep; int minNumPitches; int maxNumPitches; int minNoteLength; int maxNoteLength; int percentChanceRest; byte patch; byte minVelOn; byte minVelOff; byte maxVelOn; byte maxVelOff; } class drumGroup { int isDrumOn; int minNumDrums; int maxNumDrums; int minDrumLength; int maxDrumLength; int percentChanceRest; byte minVelOn; byte maxVelOn; } public class chordComposer extends equalTemperComposer { static long TOTAL_TICKS = 24000; int channelsUsed = 0; int numGroups; int numDrumGroups; player p; playerGroup group[] = new playerGroup[15]; drumGroup drums[] = new drumGroup[15]; int groupIndex = 0; int drumGroupIndex = 0; Random myRan; //****** GLOBAL SETS & GETS********** public void setRandom(Random r) { if (r != null) { myRan = r; } } public Random getRandom() { if (myRan != null) { return myRan; } else { return null; } } public void setBentScale(bentScale bs) { if (bs != null) { myBentScale = bs; } } public void setNumGroups(int num) { if (num >= 0 && num <= 15) { numGroups = num; // tr.trace("initializing groups.."); for (int i = 0; i < num; i++) { if (group[i] == null) { group[i] = new playerGroup(); // tr.trace("initialized group: " + i); } } } } public void setNumDrumGroups(int num) { if (num >= 0 && num <= 15) { numDrumGroups = num; // tr.trace("initializing drum groups.."); for (int i = 0; i < num; i++) { if (drums[i] == null) { drums[i] = new drumGroup(); // tr.trace("initialized drum group: " + i); } } } } //** PLAYER GROUP SETS ** public void setPatch(byte patchIn, int index) { // tr.trace("setPatch - patchIn = " + patchIn + " index = " + index); if (group[index] == null) { tr.trace("group[index] is null "); } if (index < 15 && group[index] != null) { group[index].patch = patchIn; // tr.trace("setPatch successful "); } } public void setIsOn(int isOnIn, int index) { // tr.trace("setPatch - patchIn = " + patchIn + " index = " + index); if (group[index] == null) { tr.trace("group[index] is null "); } if (index < 15 && group[index] != null) { group[index].isOn = isOnIn; // tr.trace("setPatch successful "); } } public void setMinVelOn (byte velIn, int index) { if (index < 15 && group[index] != null) { group[index].minVelOn = velIn; } } public void setMaxVelOn (byte velIn, int index) { if (index < 15 && group[index] != null) { group[index].maxVelOn = velIn; } } public void setMinVelOff (byte velIn, int index) { if (index < 15 && group[index] != null) { group[index].minVelOff = velIn; } } public void setMaxVelOff (byte velIn, int index) { if (index < 15 && group[index] != null) { group[index].maxVelOff = velIn; } } public void setMinStep(int stepIn, int index) { if (index < 15 && group[index] != null) { group[index].minStep = stepIn; } } public void setMaxStep(int stepIn, int index) { if (index < 15 && group[index] != null) { group[index].maxStep = stepIn; } } public void setMinOctave(int octIn, int index) { if (index < 15 && group[index] != null) { group[index].minStep = octIn * getNumDivisions(); } } public void setMaxOctave(int octIn, int index) { if (index < 15 && group[index] != null) { group[index].maxStep = octIn * getNumDivisions(); } } public void setMinNumPitches(int num, int index) { if (index < 15 && group[index] != null) { group[index].minNumPitches = num; } } public void setMaxNumPitches(int num, int index) { if (index < 15 && group[index] != null) { group[index].maxNumPitches = num; } } public void setMinNoteLength(int len, int index) { if (index < 15 && group[index] != null) { group[index].minNoteLength = len; } } public void setMaxNoteLength(int len, int index) { if (index < 15 && group[index] != null) { group[index].maxNoteLength = len; } } public void setPercentChanceRest(int num, int index) { if (index < 15 && group[index] != null) { group[index].percentChanceRest = num; } } //** DRUM GROUP SETS ** public void setMinDrumVelOn (byte velIn, int index) { if (index < 15 && drums[index] != null) { drums[index].minVelOn = velIn; } } public void setMaxDrumVelOn (byte velIn, int index) { if (index < 15 && drums[index] != null) { drums[index].maxVelOn = velIn; } } public void setMinNumDrums(int num, int index) { if (index < 15 && drums[index] != null) { drums[index].minNumDrums = num; } } public void setMaxNumDrums(int num, int index) { if (index < 15 && drums[index] != null) { drums[index].maxNumDrums = num; } } public void setMinDrumLength(int len, int index) { if (index < 15 && drums[index] != null) { drums[index].minDrumLength = len; } } public void setMaxDrumLength(int len, int index) { if (index < 15 && drums[index] != null) { drums[index].maxDrumLength = len; } } public void setPercentChanceDrumRest(int num, int index) { // tr.trace("setPercentChanceDrumRest invoked num is " + num + "index is " + index); if (index < 15 && group[index] != null) { drums[index].percentChanceRest = num; } } //****** GETS ********** //****** GLOBAL GETS ********** public int getNumGroups() { return numGroups; } public int getNumDrumGroups() { return numDrumGroups; } //** PLAYER GROUP GETS ** public int getIsOn(int index) { return group[index].isOn; } public byte getPatch(int index) { // tr.trace("getPatch - index = " + index); // tr.trace("group[index].patch = " + group[index].patch); return group[index].patch; } public byte getMinVelOn(int index) { return group[index].minVelOn; } public byte getMaxVelOn(int index) { return group[index].maxVelOn; } public byte getMinVelOff(int index) { return group[index].minVelOff; } public byte getMaxVelOff(int index) { return group[index].maxVelOff; } public int getMinStep(int index) { return group[index].minStep; } public int getMaxStep(int index) { return group[index].maxStep; } public int getMinNumPitches(int index) { return group[index].minNumPitches; } public int getMaxNumPitches(int index) { return group[index].maxNumPitches; } public int getMinNoteLength(int index) { return group[index].minNoteLength; } public int getMaxNoteLength(int index) { return group[index].maxNoteLength; } public int getPercentChanceRest(int index) { return group[index].percentChanceRest; } //** DRUM GROUP GETS ** public int getIsDrumOn(int index) { return drums[index].isDrumOn; } public byte getMinDrumVelOn(int index) { return drums[index].minVelOn; } public byte getMaxDrumVelOn(int index) { return drums[index].maxVelOn; } public int getMinNumDrums(int index) { return drums[index].minNumDrums; } public int getMaxNumDrums(int index) { return drums[index].maxNumDrums; } public int getMinDrumLength(int index) { return drums[index].minDrumLength; } public int getMaxDrumLength(int index) { return drums[index].maxDrumLength; } public int getPercentChanceDrumRest(int index) { return drums[index].percentChanceRest; } //******END OF PLAYER / DRUM GROUP SETS AND GETS ****** public int getNextChannel() { int result; if (channelsUsed >= 15) { tr.trace("maximum number of channels exceeded "); return -1; } else if ( channelsUsed >= 9 ) // channel 10 is always drums { result = channelsUsed + 1; channelsUsed++; } else { result = channelsUsed; channelsUsed++; } return result; } public void setGroupIndex(int num) { if (num >= 0 && num < 15) { groupIndex = num; } } public void setDrumGroupIndex(int num) { if (num >= 0 && num < 15) { drumGroupIndex = num; } } public int getGroupIndex() { return groupIndex; } public int getDrumGroupIndex() { return drumGroupIndex; } // ************* BEGIN PLAY GROUP **************** /** * * Creates a MIDI track of random chords from * a specified equal tempered scale. * Allocates a MIDI channel for each note up to the * specified maximum number of notes per chord. * Generates chords from random values within * specified ranges. * */ public void playGroup() { try { if (getIsOn(getGroupIndex()) == 0) { return; } Random ran = getRandom(); bentPitch bh; // tr.trace("playing Group - getGroupIndex() is " + getGroupIndex()); bentPlayer bp; bp = new bentPlayer(); bentScale bs; bs = getBentScale(); player p; p = (player)(bp); Track t; t = s.createTrack(); p.setTracer(tr); p.setTrack(t); p.setTick(0); p.setTrackName("random track " + t); int randomNum; int tempchan; // tr.trace("getPatch(getGroupIndex() " + getPatch(getGroupIndex())); for (int j = 0; j < getMaxNumPitches(getGroupIndex()); j++) { tempchan = getNextChannel(); // tr.trace("tempchan set by getNextChannel() is " + tempchan); if (tempchan >=0 && tempchan != 9 && tempchan <=15) { p.addChannel(tempchan); p.setPatch(getPatch(getGroupIndex()),tempchan); } } p.omniOff(); p.polyOff(); p.setPatch(getPatch(getGroupIndex())); while (p.getTickCount() < TOTAL_TICKS ) { // tr.trace("getGroupIndex() = " + getGroupIndex()); // tr.trace("p.getTickCount() = " + p.getTickCount()); randomNum = (short)(ran.nextInt(100)); // tr.trace("random chanceRest = " + randomNum); if (randomNum > getPercentChanceRest(getGroupIndex()) ) { // tr.trace("getMaxVelOn(getGroupIndex()) = " + getMaxVelOn(getGroupIndex())); // tr.trace("getMinVelOn(getGroupIndex()) = " + getMinVelOn(getGroupIndex())); randomNum = (short)(ran.nextInt(getMaxVelOn(getGroupIndex()) - getMinVelOn(getGroupIndex()) + 1)); // tr.trace("random Velocity On offset = " + randomNum); p.setVelOn((byte)(getMinVelOn(0) + randomNum)); // tr.trace("getMaxVelOff(getGroupIndex()) = " + getMaxVelOff(getGroupIndex())); // tr.trace("getMinVelOff(getGroupIndex()) = " + getMinVelOff(getGroupIndex())); randomNum = (short)(ran.nextInt(getMaxVelOff(getGroupIndex()) - getMinVelOff(getGroupIndex()) + 1)); // tr.trace("random Velocity Off offset = " + randomNum); p.setVelOff((byte)(getMinVelOff(getGroupIndex()) + randomNum)); // tr.trace("getMaxNoteLength(getGroupIndex()) = " + getMaxNoteLength(getGroupIndex())); // tr.trace("getMinNoteLength(getGroupIndex()) = " + getMinNoteLength(getGroupIndex())); randomNum = (short)(ran.nextInt(getMaxNoteLength(getGroupIndex()) - getMinNoteLength(getGroupIndex()) + 1)); // tr.trace("random Duration offset = " + randomNum); p.setDur((long)(getBeatLength() * (getMinNoteLength(getGroupIndex()) + randomNum) )); // tr.trace("raresetting bent pitches..."); bp.resetBentPitches(); // tr.trace("getMaxNumPitches(getGroupIndex()) = " + getMaxNumPitches(getGroupIndex())); // tr.trace("getMinNumPitches(getGroupIndex()) = " + getMinNumPitches(getGroupIndex())); randomNum = (short)(ran.nextInt(getMaxNumPitches(getGroupIndex()) - getMinNumPitches(getGroupIndex()) + 1)); // tr.trace("random Number of Pitches offset = " + randomNum); // tr.trace("getMinNumPitches() = " + getMinNumPitches(getGroupIndex())); int numPitches = getMinNumPitches(getGroupIndex()) + randomNum; for (int k = 0; k < numPitches; k++) { randomNum = (short)(ran.nextInt(getMaxStep(getGroupIndex()) - getMinStep(getGroupIndex()) + 1)); // tr.trace("K = " + k + " random Step offset = " + randomNum); bh = (bentPitch)(bs.elementAt(getMinStep(getGroupIndex()) + randomNum)); bp.addBentPitch(bh); } bp.play(); } else { randomNum = (short)(ran.nextInt(getMaxNoteLength(getGroupIndex()) - getMinNoteLength(getGroupIndex()) + 1)); // tr.trace("random rest Duration offset = " + randomNum); p.setDur((long)(getBeatLength() * (getMinNoteLength(getGroupIndex()) + randomNum) )); bp.playRest(); } } p.endOfTrack(); System.gc(); } //try catch(Exception e) { tr.trace("chordComposer::playGroup: Exception caught:"); tr.trace(e.toString()); System.gc(); } //catch } public void playGroup(int ndx) { setGroupIndex(ndx); playGroup(); } // ************* END PLAY GROUP **************** // ************* BEGIN PLAY DRUM GROUP **************** /** * * Creates a MIDI drum track on a MIDI channel 10. * Generates drum events from random values within * specified ranges. * */ public void playDrumGroup() { try { // tr.trace("playDrumGroup..."); if (getIsDrumOn(getDrumGroupIndex()) == 0) { return; } Track t; t = s.createTrack(); // tr.trace("created track"); simplePlayer sp; Random ran = getRandom(); int randomNum; sp = new simplePlayer(); p = (player)(sp); // tr.trace("created player"); p.setTracer(tr); p.setTrack(t); p.setTick(0); p.setTrackName("random drum track"); p.addChannel(9); //drums are always "channel 10" p.omniOff(); p.polyOff(); // tr.trace("initizilized player to drums"); while (p.getTickCount() < TOTAL_TICKS ) { // tr.trace("entered while loop - ticks: " + p.getTickCount() ); randomNum = (short)(ran.nextInt(100)); // tr.trace("chance drum rest: " + randomNum); if (randomNum > getPercentChanceDrumRest(getDrumGroupIndex()) ) { randomNum = (short)(ran.nextInt(getMaxDrumVelOn(getDrumGroupIndex()) - getMinDrumVelOn(getDrumGroupIndex()) + 1)); // tr.trace("random Drum Velocity On offset = " + randomNum); p.setVelOn((byte)(getMinDrumVelOn(0) + randomNum)); randomNum = (short)(ran.nextInt(getMaxDrumLength(getDrumGroupIndex()) - getMinDrumLength(getDrumGroupIndex()) + 1)); // tr.trace("random Drum Duration offset = " + randomNum); p.setDur((long)(getBeatLength() * (getMinDrumLength(getDrumGroupIndex()) + randomNum) )); sp.resetPitch(); randomNum = (short)(ran.nextInt(getMaxNumDrums(getDrumGroupIndex()) - getMinNumDrums(getDrumGroupIndex()) + 1)); // tr.trace("random Number of Drums offset = " + randomNum); // tr.trace("getMinNumDrums() = " + getMinNumDrums(getGroupIndex())); int numDrums = getMinNumDrums(getDrumGroupIndex()) + randomNum; for (int k = 0; k < numDrums; k++) { randomNum = (short)(ran.nextInt(37)+35); // tr.trace("K = " + k + " random Drum Step offset = " + randomNum); sp.addMidiPitch(randomNum); } sp.play(); } else { randomNum = (short)(ran.nextInt(getMaxNoteLength(getGroupIndex()) - getMinNoteLength(getGroupIndex()) + 1)); // tr.trace("random drum rest Duration offset = " + randomNum); p.setDur((long)(getBeatLength() * (getMinNoteLength(getGroupIndex()) + randomNum) )); sp.playRest(); } } p.endOfTrack(); System.gc(); } //try catch(Exception e) { tr.trace("chordComposer::play drums: Exception caught:"); tr.trace(e.toString()); System.gc(); } //catch } public void playDrumGroup(int ndx) { setDrumGroupIndex(ndx); playDrumGroup(); } // ************* END PLAY DRUM GROUP **************** //** MAIN COMPOSE ROUTINE ** /** * * Creates an empty MIDI sequence and initializes it. * Creates an equal temered scale of bent pitches. * Invokes the playGroup method to create random * chords and drum events.. * */ public void compose() { try { if (s == null) { createSequence(); } // tr.trace("sequence created..."); setRandom(new Random()); // // String TrackName; // Track t; bentPlayer bp; simplePlayer sp; bentPitch bh; // tr.trace("creating scale..."); equalTemperedBentPitchFactory fact = new equalTemperedBentPitchFactory(); fact.setTracer(tr); // fact.setBaseMidiPitch((byte)C_DOWN_3); fact.setBaseMidiPitch((byte)getBaseMidiPitch()); fact.setDivisions((short)getNumDivisions()); fact.setStepPosition((short)0); bentScale bs; equalTemperedScale ets = new equalTemperedScale(); bs = (bentScale)ets; bs.setTracer(tr); setBentScale(bs); int numNotes = getNumOctaves() * getNumDivisions() + 1; for (short i = 0; i <= numNotes; i++) { fact.setStepPosition(i); fact.calculateBendAmount(); fact.calculateBendBytes(); bh = fact.getBentPitch(); bs.addBentPitch(bh); } // tr.trace("creating randomizer..."); // short randomNum; //track 0 - control - for meta event & sysex // tr.trace("creating track 0..."); Track t; t = s.createTrack(); controlPlayer cp = new controlPlayer(); cp.setTrack(t); cp.setTrackName("Control track 0"); cp.generalMidiOn(); cp.setTempo((byte)0x02, (byte)0xA1, (byte)0x20); cp.endOfTrack(); // tr.trace("getNumGroups() is " + getNumGroups()); for (int x = 0; x < getNumGroups(); x++) { // tr.trace("x is " + x); playGroup(x); } // tr.trace("getNumDrumGroups() is " + getNumDrumGroups()); for (int y = 0; y < getNumDrumGroups(); y++) { // tr.trace("y is " + y); setDrumGroupIndex(y); playDrumGroup(y); } } //try catch(Exception e) { tr.trace("chordComposer::compose: Exception caught:"); tr.trace(e.toString()); } //catch } }