// Fragment 2 public class kproUI extends javax.swing.JFrame { // Hold the settings for my metronome. private class metronome { int bpm; // Beats Per Minute int tmr; // Metronome timer int cntr; // Counter, from 1 to 4. int bpmTotal; // BPM * 1000 ms boolean state; // Metronome On/Off button state metronome(int b, int c, boolean s) { tmr = -1; bpm = b; cntr = c; state = s; } } // Store the settings for the MIDI channels for the Kaossilator Pro, some keyboard to be determined later // and the starting channel for the Java software synth (using 12 channels). 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() { // Check for duplicated channel numbers. 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"); } } } // Hold the settings for the gate arpeggiator. 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; } } // Hold all of the program screen settings, to allow reading and writing them to file and individual patch objects. 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() { // Read settings to object from GUI components. 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(){ // Transfer object settings to GUI components. 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(); } // I still can't get object serializing to work for file saving, so brute-force it. private String makeString() { // Put all settings into a string. 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) { // Read a string from a file and parse into the current object. 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]); } } 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(); ArrayList arpPatternsList = new ArrayList();