void GuiPiano::buttonClicked(Button *button) { //get modifier key so we can handle cmd-clicks when selecting keys ModifierKeys modifier = ModifierKeys::getCurrentModifiers(); for (int i = 0; i <= 119; i++) { if (button == keys[i]) { //========================================================================= //========================================================================= //regular click to set the selected midi pads note or sequencers pad root note if (modifier.isAnyModifierKeyDown() == false) { //first clear all keys for (int i = 0; i < 120; i++) setKeyDisplay(i, false); selectedKeys.clear(); for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++) { int padNum = selectedPads[padIndex]; //========================================================================= //MIDI MODE REG CLICK if (PAD_SETTINGS->getMode() == 1) //Midi Mode { PAD_SETTINGS->setMidiNote(i); if (padIndex == 0) { setKeyDisplay (i, true); selectedKeys.addIfNotAlreadyThere(i); noteNumber = i; } } //========================================================================= //SEQ MODE REG CLICK else if (PAD_SETTINGS->getMode() == 3) //Sequencer Mode { //get currently set 'root' note int rootNote = PAD_SETTINGS->getSequencerMidiNote(0); //get difference between root note and clicked note int transposeValue = rootNote - i; //check to see if the top row of grid will be transposed //to above 119. If so, don't transpose the notes, and just //redraw/re-set what was last there in the below else statement if (PAD_SETTINGS->getSequencerMidiNote(11)-transposeValue <= 119) { //add the transpose value to each note in the scale/set for (int row = 0; row < 12; row++) { int currentVal = PAD_SETTINGS->getSequencerMidiNote(row); if (currentVal >= 0) { int newVal = currentVal-transposeValue; PAD_SETTINGS->setSequencerMidiNote(newVal, row); //update the GUI if (padIndex == 0) { setKeyDisplay (newVal, true); selectedKeys.addIfNotAlreadyThere(newVal); } if (row == 0) noteNumber = i; } } } else { //redraw and re-set what was previously there //bit convoluted to clear everything above //just to redraw it in a certain situation. //Is there a better way to code it? for (int row = 0; row < 12; row++) { if (padIndex == 0) { setKeyDisplay (PAD_SETTINGS->getSequencerMidiNote(row), true); selectedKeys.addIfNotAlreadyThere(PAD_SETTINGS->getSequencerMidiNote(row)); } } } recentlyUpdated = true; } } } //========================================================================= //========================================================================= //cmd-click to select mutiple notes for midi pads or custom scale for sequencer pads else if (modifier.isCommandDown() == true) { //don't intially clear the keys //========================================================================= //MIDI MODE CMD-CLICK //if the number of selected keys is less than the number of selected pads if (selectedKeys.size() < selectedPads.size()) { //cycle through the SELECTED KEYS in the order they were selected, //applying them to the selected pads in the order they were selected. for (int padIndex = 0; padIndex < selectedKeys.size(); padIndex++) { int padNum = selectedPads[padIndex]; if (PAD_SETTINGS->getMode() == 1) //Midi Mode { PAD_SETTINGS->setMidiNote(selectedKeys[padIndex]); //update the GUI if (padIndex == 0) { //add the key setKeyDisplay (i, true); selectedKeys.addIfNotAlreadyThere(i); noteNumber = selectedKeys[0]; } } } } //========================================================================= //SEQ MODE CMD-CLICK for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++) { int padNum = selectedPads[padIndex]; if (PAD_SETTINGS->getMode() == 3) //Sequencer Mode { /* Cmd-click is used to select a custom scale/set of notes for a the sequence grid of a sequencer pad. Click on an unselected key to add it, click on a selected key to remove it. The selected keys/notes will be applied in order of their value to the sequencer rows. If less than 12 notes are selected, the top 'unselected' rows will note have any notes on them. This is the current way that the app handles command-clicks on the piano in seq mode: When the user cmd-clicks a key for the first time (when recentlyUpdated == true) it will clear the piano and allow the user to select 12 individual different keys for each row if the sequence. Each time a key is selected it orders the selectedkey array and applies all the selected keys to the sequence rows. If the number of selected keys is less than the number of rows (12), each row which doesn't currently have a key selected for it is set to an 'off' value of -500. I've chosen 500 as no degree of transposing a note set to -500 could be transposed to be positive by regualar clicking the piano). The app will view any minus midi note number as 'off', whether its to display the note on the piano or play the note as a midi message. This method seems to make more sense over the other possible methods: 1. any 'unchosen' note is set to a default note such as 0 or 60. This is flawed as when transposing the selection it will transpose the default note which might not make sense, plus when ordering the selected keys the default note could be layed out somewhere in the middle of the selected notes, which doesn't make sense as any unselected notes should be set to the top of the grid. 2. any 'unchosen' note is kept the same as the previous note. This also flawed because of the second reason in the point above. */ //=========== click on unselected key =============== if (keys[i]->getToggleState() == true) //if was previous off and clicked { if (recentlyUpdated == true && selectedKeys.size() == 12) // so th cmd-click doesn't delete if incomplete set { if (padIndex == 0) { //clear all keys for (int i = 0; i < 120; i++) setKeyDisplay(i, false); selectedKeys.clear(); } } recentlyUpdated = false; //if the number of selected keys is less than the number of sequencer rows if (selectedKeys.size() < 12) { //update the GUI if (padIndex == 0) { setKeyDisplay (i, true); selectedKeys.addIfNotAlreadyThere(i); //sort selectedKeys into order. //The below loop checks the recently added key/note //and compares in to the previous key and moves //it to the correct location in the array for (int x = selectedKeys.size() - 1; x >= 0; x--) { if (selectedKeys[x] < selectedKeys[x-1]) { selectedKeys.swap(x, x-1); } } } for (int row = 0; row < 12; row++) { int note = selectedKeys[row]; if (row > selectedKeys.size()-1) note = -500; //'off' note PAD_SETTINGS->setSequencerMidiNote(note, row); } } } //=========== click on selected key =============== else if (keys[i]->getToggleState() == false) //if was previous on and clicked { recentlyUpdated = false; //update the GUI (only need to do this a single time) if (padIndex == 0) { setKeyDisplay (i, false); selectedKeys.removeFirstMatchingValue(i); //Don't need to sort keys here do I? //Removing an element will resize the array, //which will cause the top row to be set to note 'off' } for (int row = 0; row < 12; row++) { int note = selectedKeys[row]; if (row > selectedKeys.size()-1) note = -500; //'off' note PAD_SETTINGS->setSequencerMidiNote(note, row); } } noteNumber = selectedKeys[0]; } } } //========================================================================= //========================================================================= //alt-click to transpose mutiple notes for midi pads else if (modifier.isAltDown() == true) { if (AppSettings::Instance()->padSettings[selectedPads[0]]->getMode() == 1) //Midi Mode { //clear all keys for (int i = 0; i < 120; i++) setKeyDisplay(i, false); selectedKeys.clear(); //At the moment the currentl alg. belows won't allow you to transpose a scale //if ANY note will be transposed to above 119. Also, when transposing the note //you select will be the lowest note. However in the old software it was possible //to transpose notational arrangements so that the bottom set of notes would all //equal 0 or the top sets would all equal 119, meaning you could have more choice //over where the arrangment starts and ends. Do we want that here? If so, the below //code will need to be changed to how it was before (most of it has just been //commented out. //Get the 'root note'. //Should the root note be the note of the first select pad (selectedPads[0]). //Or should it be the lowest note? //Below is the code to find the lowest note. Array <int> selectedPadsNotes; for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++) selectedPadsNotes.insert(padIndex, AppSettings::Instance()->padSettings[selectedPads[padIndex]]->getMidiNote()); DefaultElementComparator<int> sorter; selectedPadsNotes.sort (sorter); int rootNote = selectedPadsNotes[0]; //get difference between root note and clicked note int transposeValue = rootNote - i; //check to see if the highest note will be transposed //to above 119. If so, don't transpose the notes, and just //redraw/re-set what was last there in the below else statement if (selectedPadsNotes.getLast()-transposeValue <= 119) { for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++) { int padNum = selectedPads[padIndex]; int currentVal = PAD_SETTINGS->getMidiNote(); int newVal = currentVal-transposeValue; //if (newVal > 119) //newVal = 119; //else if (newVal < 0) //newVal = 0; PAD_SETTINGS->setMidiNote(newVal); //update the GUI setKeyDisplay (newVal, true); selectedKeys.addIfNotAlreadyThere(newVal); if (padIndex == 0) noteNumber = newVal; } } else { //redraw and re-set what was previously there //bit convoluted to clear everything above //just to redraw it in a certain situation. //Is there a better way to code it? for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++) { int padNum = selectedPads[padIndex]; setKeyDisplay (PAD_SETTINGS->getMidiNote(), true); selectedKeys.addIfNotAlreadyThere(PAD_SETTINGS->getMidiNote()); } } } } break; //========================================================================= //========================================================================= } } }