K-Gater, Part 4


Ok, might as well dive into the real code.
Again, I apologize for the lack of formatting.  Blame WordPress.

I’m starting out with some class definitions.

I need to point out that the Metronome and Gate Arp buttons are treated as toggles.  I tried using the Netbeans toggle button component, but I couldn’t get it to work right away and I gave up.  Instead, I use regular buttons, and I have boolean “state” variables to determine if the button is on or off.  I then change the button background color based on the state.

Click here to see the formatted class and method definitions.

**********************

metronome is used for the onscreen metronome.

bpm – Beats per Minute
tmr – Holder for the timer counter for updating beat counts
cntr – Beat counter (right now, goes from 1 to 4).
bpmTotal – bpm * 1000 ms
state – On/Off state of the Metronome button

metronome() – class constructor. Takes bpm, cntr and state for parameters.

 

portSettings is used for holding the channel numbers for the K-Pro, keyboard and default synth.

kProChannelNo – K-Pro channel number (I’m using MIDI channel 1, Java calls this channel 0).
keyboardChannelNo – Keyboard channel number.  I’ll probably use 1 when I get a keyboard.
defaultChannelNo – Starting channel for the software synth.  I’m using 12 channels, and starting at 2 by default.

portSettings() – Class constructor. Takes K-Pro, keyboard and default channel numbers.
setKProChannel() – K-Pro set method with error handling.
setKeyboardChannel() – Keyboard set method with error handling.
setDefaultSynthChannel() – Default synth starting channel number with error handling.
checkChannelConflict() – Make sure that the hardware doesn’t have overlapping channel numbers.

gateArp is used for the arpegiator. Look at the comments of the below code for variable details.
The gateArp is the heart of this program. If a keyboard is connected and the arp is turned off, we just
pass the NOTE_ON and NOTE_OFF messages to the K-Pro or the default synth.  If it’s on, we use it to arpeggiate
the key being pressed. This means we need to know how long to keep a note on and off, which note the user is
playing, and which note we play in the pattern.

gateArp() – class constructor
calc() – Calculate the timing for note on and note off times based on ratio and rate
nextNote() – Calculate the next note to play based on the pattern, bottom note and Arp note spacing.

 

patch – This is the super class that we use for storing program patches.  For my purposes, a “patch” consists
of all of the screen settings (channel numbers, instruments attached to each of the buttons, the name of the arp
patterns file, metronome settings, gate arp settings, etc.) needed to recreate whatever the user has entered.
I save the settings to an ArrayList of patches, allowing me to save them to file and read them back.  Because I
can not figure out object serialization for the life of me, I have to do file reading and writing the hard way.
There’s no constructor for this class.

gatherPatch() – Copy data from the jButton and jTextfield components to the patch object.
loadPatch() – Copy data from the patch object to the jButton and jTextField components.
makeString() – Convert all the member contents to one long string for saving to file.
parseFromFile() – Take the string from the file and parse to all of the object’s members.

———————————-

Formatted text file.

public class kproUI extends javax.swing.JFrame {

private class metronome {
int bpm;
int tmr;
int cntr;
int bpmTotal;
boolean state;

metronome(int b, int c, boolean s) {
tmr = -1;
bpm = b;
cntr = c;
state = s;
}
}

private class portSettings {
int kProChannelNo;
int keyboardChannelNo;
int defaultChannelNo;

portSettings(int kp, int kb, int ds) {
kProChannelNo = kp;
keyboardChannelNo = kb;
defaultChannelNo = ds;
}

private void setKProChannel(int i) {
if((i >= 0 && i <4) || (i >=12 && i <=15)) { // Edit K-Pro Channel No.
kProChannelNo = i;
checkChannelConflict();
} else {
jTextArea1.append(“ERROR: |” + i + “| is out of range (0-3)\n”);
}
}

private void setKeyboardChannel(int i) {
if((i >= 0 && i <4) || (i >=12 && i <=15)) { // Edit keyboard Channel No.
keyboardChannelNo = i;
checkChannelConflict();
} else {
jTextArea1.append(“ERROR: |” + i + “| is out of range (0-3)\n”);
}
}

private void setDefaultSynthChannel(int i) {
if(i < 0 || i > 3) {
jTextArea1.append(“ERROR: |” + i + “| is out of range (2-4)\n”); // Edit Default Synth Starting Channel No.
} else {
defaultChannelNo = i;
checkChannelConflict();
}
}

private void checkChannelConflict() {
if(kProChannelNo == keyboardChannelNo) {
jTextArea1.append(“CAUTION: K-Pro and Keyboard both have the same MIDI channel number.\n”);
}
if((kProChannelNo >= defaultChannelNo) && (kProChannelNo <= defaultChannelNo + 11)) {               jTextArea1.append(“CAUTION: K-Pro MIDI channel number overlaps default synth channels.\n”);            }            if((keyboardChannelNo >= defaultChannelNo) && (keyboardChannelNo <= defaultChannelNo + 11)) {
jTextArea1.append(“CAUTION: keyboard MIDI channel number overlaps default synth channels.\n”);
}
}
}

private class gateArp {
boolean state; // gateArp turned on or off
int rate; // Seconds per note
int ratio; // Ratio of note on to note off
boolean onOff; // Toggle for note on and off
int onTime; // Number of milliseconds for note on
int offTime; // Number of milliseconds for note off
int arpTime; // Contains either onTime or offTime when arpeggiator is running
int arpTmr; // Number of milliseconds since timer started
int currentNote; // Note currently being played from the arp pattern list
int calcNote; // Calculated note to play based on bottom note, pattern and step size
int patPtr; // Which note within the pattern is currently being played
int currentPat; // Which pattern is currently being played
int patLength; // Number of notes in the current pattern
int stepSize; // Size of steps to take based on the pattern contents

gateArp(int r1, int r2, int o1, int o2, int s1) {
state = false; // Default to arpeggiator off
rate = r1;
ratio = r2;
onOff = false;
onTime = o1;
offTime = o2;
patPtr = 0;
patLength = 4; // Set a default for the starting size and HOPE it matches reality
stepSize = s1;
arpTmr = -1; // Deactivate the timer so arpeggiator doesn’t play
}

private void calc(){ // Calculate the number of milliseconds for both note on and off times
onTime = (rate * ratio) / 100;
if(onTime < 1) { // Avoid setting the timer to 0ms.                onTime = 1;             }             if(onTime > rate – 1) { // No point to having an arpeggiator that has a 100% on time
onTime = rate – 1;
}
offTime = rate – onTime;
}

private void nextNote(int b) { // Calculate the next note based on the pattern and step size

if(patPtr >= arpPatternsList.get(currentPat).size()) { // Error check when switching patches with arp turned on.
patPtr = 0;
patLength = arpPatternsList.get(currentPat).size();
}

calcNote = b + ((Integer) arpPatternsList.get(currentPat).get(patPtr)) * stepSize;
if(calcNote < 0) calcNote = 0; // Keep note between 0 and 127             if(calcNote > 127) calcNote = 127;
patPtr = (patPtr < patLength – 1) ? patPtr+1 : 0;
}
}

private class patch {
String name;
int kProChannel;
int keyboardChannel;
int defaultChannel;
int [] pkProVoices = new int[8];
int [] pdefaultVoices = new int[12];
int selectedVoice;
int volume;
int bpm;
int keyboardBaseNote;
int keyboardNoteSpacing;
String arpPatternFile;
int arpRate;
int arpRatio;
int arpNoteSpacing;
int arpPattern;

private void gatherPatch() {
name = jTextField7.getText();
kProChannel = midiPorts.kProChannelNo;
keyboardChannel = midiPorts.keyboardChannelNo;
defaultChannel = midiPorts.defaultChannelNo;
selectedVoice = lastButtonSelected – 1;
System.arraycopy(kProVoices, 0, pkProVoices, 0, 8); // source, sourcePosition, dest, destPosition, length
System.arraycopy(defaultVoices, 0, pdefaultVoices, 0, 12);
volume = keyboardVolume;
bpm = met.bpm;
keyboardBaseNote = keyboardBottomNote;
keyboardNoteSpacing = keyboardSpacing;
arpPatternFile = selectedArpFile;
arpRate = jSlider2.getValue();
arpRatio = jSlider3.getValue();
arpNoteSpacing = arp.stepSize;
arpPattern = arp.currentPat;
}

private void loadPatch(){
jTextField7.setText(name);
midiPorts.kProChannelNo = kProChannel;
midiPorts.keyboardChannelNo = keyboardChannel;
midiPorts.defaultChannelNo = defaultChannel;
System.arraycopy(pkProVoices, 0, kProVoices, 0, 8);
System.arraycopy(pdefaultVoices, 0, defaultVoices, 0, 12);
if(kProDevice != null) {
for(int i=0; i<8; i++) {
kSaveTo = setVoice(pkProVoices[i], kProInstruments[pkProVoices[i]], midiPorts.kProChannelNo, 4+i, i, true);
}
}
for(int i=0; i< 12; i++) {
dSaveTo = setVoice(pdefaultVoices[i], kProInstruments[pdefaultVoices[i]], midiPorts.defaultChannelNo+i, 14+i, 0, true);
}
jSlider1.setValue(volume); // keyboardVolume = volume;
jTextField1.setText(Integer.toString(bpm)); // need to find a way to auto trigger textfield events
met.bpm = bpm;
jTextField3.setText(Integer.toString(keyboardBaseNote));
keyboardBottomNote = keyboardBaseNote;
jTextField4.setText(Integer.toString(keyboardNoteSpacing));
keyboardSpacing = keyboardNoteSpacing;
selectedArpFile = arpPatternFile;
jSlider2.setValue(arpRate); // arp.rate = arpRate;
jSlider3.setValue(arpRatio); // arp.ratio = arpRatio;
jTextField5.setText(Integer.toString(arpNoteSpacing));
arp.stepSize = arpNoteSpacing;
jComboBox2.setSelectedIndex(arpPattern); // arp.currentPat = arpPattern;
dSaveTo = false;
kSaveTo = false;
jBList.get(selectedVoice).doClick();
}

private String makeString() {
String ret = “”;
ret += name + “~”;
ret += kProChannel + “~”;
ret += keyboardChannel +”~”;
ret += defaultChannel + “~”;
for(int i=0; i<8; i++) {
ret += pkProVoices[i] + “~”;
}
for(int i=0; i<12; i++) {
ret += pdefaultVoices[i] + “~”;
}
ret += selectedVoice + “~”;
ret += volume + “~”;
ret += bpm + “~”;
ret += keyboardBaseNote + “~”;
ret += keyboardNoteSpacing + “~”;
ret += arpPatternFile + “~”;
ret += arpRate + “~”;
ret += arpRatio + “~”;
ret += arpNoteSpacing + “~”;
ret += arpPattern;
return(ret);
}

private void parseFromFile(String s) {
String [] str = s.split(“~”);

name = str[0];
kProChannel = Integer.parseInt(str[1]);
keyboardChannel = Integer.parseInt(str[2]);
defaultChannel = Integer.parseInt(str[3]);
for(int i = 0; i<8; i++) {
pkProVoices[i] = Integer.parseInt(str[4 + i]);
}
for(int i = 0; i<12; i++) {
pdefaultVoices[i] = Integer.parseInt(str[12 + i]);
}
selectedVoice = Integer.parseInt(str[24]);
volume = Integer.parseInt(str[25]);
bpm = Integer.parseInt(str[26]);
keyboardBaseNote = Integer.parseInt(str[27]);
keyboardNoteSpacing = Integer.parseInt(str[28]);
arpPatternFile = str[29];
arpRate = Integer.parseInt(str[30]);
arpRatio = Integer.parseInt(str[31]);
arpNoteSpacing = Integer.parseInt(str[32]);
arpPattern = Integer.parseInt(str[33]);
}
}

// Create objects of the above classes.

gateArp arp = new gateArp(1000, 50, 500, 500, 4); // rate, ratio, on time, off time, arp step size
metronome met = new metronome(120, 1, false); // bpm, counter, metronome off
portSettings midiPorts = new portSettings(0, 1, 4); // K-Pro, keyboard, default Synth starting channel

ArrayList patchList = new ArrayList(); // These two get populated later when the user clicks on
ArrayList arpPatternsList = new ArrayList(); // Add Patch or Add Pattern.

 

Advertisements
Previous Post
Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: