1 import javax.imageio.ImageIO; 2 import javax.swing.*; 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.io.File; 6 7 public class GUI{ 8 9 private ImageIcon whole, half, quarter, eighth, sixteenth, thirtysecond; 10 private Melody melody, calcMelody; 11 private MusicPlayer musicPlayer; 12 private JFrame frame, rhythmInput, chordsInput, oneChordInput; 13 private JPanel frameBorderPanel, userInputPanel, extraInputPanel, keyChoicePanel, rhythmDisplayPanel, rhythmFramePanel, chordsDisplayPanel, chordsFramePanel, oneChordPanel, oneChordContentPanel, keyNotesCheckBoxPanel, extraNotesCheckBoxPanel, lengthAndMelodyPanel, lengthParametersLabelsPanel, lengthParametersComboBoxesPanel; 14 private RhythmPanel rhythmInputPanel, rhythmDisplayRhythmPanel; 15 private ChordsPanel chordsInputPanel, chordsDisplayChordsPanel; 16 private MelodyPanel melodyDisplayMelodyPanel; 17 private JComboBox tonicCB, scaleCB, timeSigCB, numberMeasuresCB, smallestSubdivCB, chordRootNoteCB, arpeggiateCB; 18 private MutableComboBoxModel subdivModel, chordRootNoteModel; 19 private ComboBoxColorRenderer comboBoxColorRenderer; 20 private JButton enterRhythmB, saveRhythmB, deleteRhythm, enterChordsB, saveChordsB, saveOneChordB, deleteChordsB, createMelodyB, playMelodyB; 21 private JLabel keyL, melodyL, timeSigL, numberMeasuresL, smallestSubdivL, rootNoteL, keyNotesL, extraNotesL; 22 private JCheckBox keyNoteCheckBox2, keyNoteCheckBox3, keyNoteCheckBox4, keyNoteCheckBox5, keyNoteCheckBox6, keyNoteCheckBox7, keyNoteCheckBox8, extraNoteCheckBox1, extraNoteCheckBox2, extraNoteCheckBox3, extraNoteCheckBox4, extraNoteCheckBox5; 23 private JCheckBox[] keyNotesCheckBoxesArray, extraNotesCheckBoxesArray; 24 private boolean rhythmEntered, chordsEntered, editChord, deleteChord; 25 private boolean[] rhythm, bufferRhythm; 26 private Chord[] chords, bufferChords; 27 private Chord bufferOneChord; 28 private int length, chordBeginningIndex, chordEndingIndex; 29 30 public GUI(){ 31 32 33 // Initialising 34 35 try{ 36 whole = new ImageIcon(ImageIO.read(new File("res/edits/whole_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); 37 half = new ImageIcon(ImageIO.read(new File("res/edits/half_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); 38 quarter = new ImageIcon(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); 39 eighth = new ImageIcon(ImageIO.read(new File("res/edits/eighth_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); 40 sixteenth = new ImageIcon(ImageIO.read(new File("res/edits/sixteenth_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); 41 thirtysecond = new ImageIcon(ImageIO.read(new File("res/edits/thirtysecond_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); 42 } catch(Exception e){ 43 System.out.println("Oooops, something went wrong!"); 44 } 45 46 musicPlayer = new MusicPlayer(); 47 frame = new JFrame("MelodyMaker"); 48 rhythmInput = new JFrame("Enter your rhythm"); 49 chordsInput = new JFrame("Enter your chords"); 50 oneChordInput = new JFrame("Build your chord"); 51 frameBorderPanel = new JPanel(); 52 frameBorderPanel.setLayout(new BorderLayout()); 53 rhythmInputPanel = new RhythmPanel(); 54 rhythmDisplayRhythmPanel = new RhythmPanel(); // (TODO: use only this panel for rhythmInput and get rid of rhythmInputFrame & bufferRhythm) 55 rhythmDisplayRhythmPanel.setErase(true); 56 userInputPanel = new JPanel(); 57 userInputPanel.setLayout(new GridLayout(1,2)); 58 extraInputPanel = new JPanel(); 59 extraInputPanel.setLayout(new GridLayout(7,1)); 60 keyChoicePanel = new JPanel(); 61 keyChoicePanel.setLayout(new GridLayout(1,2)); 62 rhythmDisplayPanel = new JPanel(); 63 rhythmDisplayPanel.setLayout(new BorderLayout()); 64 rhythmFramePanel = new JPanel(); 65 rhythmFramePanel.setPreferredSize(new Dimension(Main.OTHER_FRAME_WIDTH, Main.OTHER_FRAME_HEIGHT)); 66 rhythmFramePanel.setLayout(new BorderLayout()); 67 chordsDisplayPanel = new JPanel(); 68 chordsDisplayPanel.setLayout(new BorderLayout()); 69 chordsFramePanel = new JPanel(); 70 chordsFramePanel.setPreferredSize(new Dimension(Main.OTHER_FRAME_WIDTH, Main.OTHER_FRAME_HEIGHT)); 71 chordsFramePanel.setLayout(new BorderLayout()); 72 oneChordPanel = new JPanel(); 73 oneChordPanel.setPreferredSize(new Dimension(Main.CHORD_FRAME_WIDTH, Main.CHORD_FRAME_HEIGHT)); 74 oneChordPanel.setLayout(new BorderLayout()); 75 oneChordContentPanel = new JPanel(); 76 oneChordContentPanel.setLayout(new GridLayout(2,3)); 77 keyNotesCheckBoxPanel = new JPanel(); 78 keyNotesCheckBoxPanel.setLayout(new GridLayout(7,1)); 79 extraNotesCheckBoxPanel = new JPanel(); 80 extraNotesCheckBoxPanel.setLayout(new GridLayout(5,1)); 81 lengthAndMelodyPanel = new JPanel(); 82 lengthAndMelodyPanel.setLayout(new GridLayout(7,1)); 83 lengthParametersLabelsPanel = new JPanel(); 84 lengthParametersLabelsPanel.setLayout(new GridLayout(1,3)); 85 lengthParametersComboBoxesPanel = new JPanel(); 86 lengthParametersComboBoxesPanel.setLayout(new GridLayout(1,3)); 87 melodyDisplayMelodyPanel = new MelodyPanel(); 88 tonicCB = new JComboBox(new String[]{"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}); 89 tonicCB.setSelectedIndex(0); 90 tonicCB.setMaximumRowCount(12); 91 scaleCB = new JComboBox(new String[]{"Ionian (Major)", "Dorian", "Phrygian", "Lydian", "Mixolydian", "Aeolian (Minor)", "Locrian", "Harmonic Minor", "Melodic Minor"}); 92 scaleCB.setMaximumRowCount(9); 93 scaleCB.setSelectedIndex(0); 94 timeSigCB = new JComboBox(new String[]{"4/4", "3/4", "6/4", "2/4", "5/4", "7/4", "7/8", "15/16"}); 95 timeSigCB.setSelectedIndex(0); 96 numberMeasuresCB = new JComboBox(new String[]{"1", "2", "3", "4"}); 97 numberMeasuresCB.setSelectedIndex(0); 98 subdivModel = new DefaultComboBoxModel(); 99 subdivModel.addElement(whole); 100 subdivModel.addElement(half); 101 subdivModel.addElement(quarter); 102 subdivModel.addElement(eighth); 103 subdivModel.addElement(sixteenth); 104 subdivModel.addElement(thirtysecond); 105 smallestSubdivCB = new JComboBox(subdivModel); 106 smallestSubdivCB.setSelectedIndex(4); 107 arpeggiateCB = new JComboBox(new String[]{"No minor 2nd intervals", "Arpeggiate"}); 108 enterRhythmB = new JButton("Enter rhythm"); 109 saveRhythmB = new JButton("Save rhythm"); 110 deleteRhythm = new JButton("Delete rhythm"); 111 deleteRhythm.setVisible(false); 112 enterChordsB = new JButton("Enter chords"); // TODO: Add chord only creation function 113 saveChordsB = new JButton("Save chords"); 114 saveOneChordB = new JButton("Save chord"); 115 deleteChordsB = new JButton("Delete chords"); 116 deleteChordsB.setVisible(false); 117 createMelodyB = new JButton("Create melody"); 118 playMelodyB = new JButton("Play melody"); 119 keyL = new JLabel("Key: "); 120 melodyL = new JLabel("Melody: "); 121 timeSigL = new JLabel("Time Signature: "); 122 numberMeasuresL = new JLabel("Number of measures: "); 123 smallestSubdivL = new JLabel("Smallest Subdivision: "); 124 rootNoteL = new JLabel("Root note"); 125 keyNotesL = new JLabel("Key notes"); 126 extraNotesL = new JLabel("Extra notes"); 127 keyNoteCheckBox2 = new JCheckBox("2"); 128 keyNoteCheckBox3 = new JCheckBox("3"); 129 keyNoteCheckBox4 = new JCheckBox("4"); 130 keyNoteCheckBox5 = new JCheckBox("5"); 131 keyNoteCheckBox6 = new JCheckBox("6"); 132 keyNoteCheckBox7 = new JCheckBox("7"); 133 keyNoteCheckBox8 = new JCheckBox("8"); 134 keyNoteCheckBox8.setVisible(false); 135 extraNoteCheckBox1 = new JCheckBox("1"); 136 extraNoteCheckBox2 = new JCheckBox("2"); 137 extraNoteCheckBox3 = new JCheckBox("3"); 138 extraNoteCheckBox4 = new JCheckBox("4"); 139 extraNoteCheckBox5 = new JCheckBox("5"); 140 keyNotesCheckBoxesArray = new JCheckBox[7]; 141 keyNotesCheckBoxesArray[0] = keyNoteCheckBox2; 142 keyNotesCheckBoxesArray[1] = keyNoteCheckBox3; 143 keyNotesCheckBoxesArray[2] = keyNoteCheckBox4; 144 keyNotesCheckBoxesArray[3] = keyNoteCheckBox5; 145 keyNotesCheckBoxesArray[4] = keyNoteCheckBox6; 146 keyNotesCheckBoxesArray[5] = keyNoteCheckBox7; 147 keyNotesCheckBoxesArray[6] = keyNoteCheckBox8; 148 extraNotesCheckBoxesArray = new JCheckBox[5]; 149 extraNotesCheckBoxesArray[0] = extraNoteCheckBox1; 150 extraNotesCheckBoxesArray[1] = extraNoteCheckBox2; 151 extraNotesCheckBoxesArray[2] = extraNoteCheckBox3; 152 extraNotesCheckBoxesArray[3] = extraNoteCheckBox4; 153 extraNotesCheckBoxesArray[4] = extraNoteCheckBox5; 154 setRhythmEntered(false); 155 setChordsEntered(false); 156 157 setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 16); 158 setCalcMelody(new Melody(getLength())); 159 setRhythm(new boolean[getLength()]); 160 setChords(new Chord[getLength()]); 161 162 chordRootNoteModel = new DefaultComboBoxModel(); 163 addChordRootNoteModelElements(); 164 chordRootNoteCB = new JComboBox(chordRootNoteModel); 165 comboBoxColorRenderer = new ComboBoxColorRenderer(chordRootNoteCB.getRenderer(), getCalcMelody()); 166 chordRootNoteCB.setRenderer(comboBoxColorRenderer); 167 chordRootNoteCB.setMaximumRowCount(12); 168 updateCheckBoxes(); 169 170 chordsInputPanel = new ChordsPanel(getCalcMelody()); 171 chordsDisplayChordsPanel = new ChordsPanel(getCalcMelody()); // (TODO: use only this panel for chordsInput and get rid of chordsInputFrame & bufferChords) 172 chordsDisplayChordsPanel.setErase(true); 173 174 // GUI structuring 175 176 frame.add(frameBorderPanel); 177 try{ 178 frame.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter 179 rhythmInput.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter 180 chordsInput.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter 181 oneChordInput.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter 182 } catch (Exception e){ 183 System.out.println("Oooops, something went wrong!"); 184 } 185 frame.setSize(Main.MAIN_FRAME_WIDTH, Main.MAIN_FRAME_HEIGHT); 186 frame.setResizable(false); 187 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 188 189 frameBorderPanel.add(userInputPanel, BorderLayout.CENTER); 190 191 userInputPanel.add(extraInputPanel); 192 userInputPanel.add(lengthAndMelodyPanel); 193 194 extraInputPanel.add(keyL); 195 extraInputPanel.add(keyChoicePanel); 196 extraInputPanel.add(enterRhythmB); 197 extraInputPanel.add(rhythmDisplayPanel); 198 extraInputPanel.add(enterChordsB); 199 extraInputPanel.add(chordsDisplayPanel); 200 extraInputPanel.add(createMelodyB); 201 202 keyChoicePanel.add(tonicCB); 203 keyChoicePanel.add(scaleCB); 204 205 rhythmInput.add(rhythmFramePanel); 206 rhythmInput.pack(); 207 rhythmInput.setResizable(false); 208 rhythmInput.setLocationRelativeTo(frame); 209 rhythmInput.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 210 rhythmInput.setVisible(false); 211 212 rhythmFramePanel.add(rhythmInputPanel, BorderLayout.CENTER); 213 rhythmFramePanel.add(saveRhythmB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT 214 215 chordsInput.add(chordsFramePanel); 216 chordsInput.pack(); 217 chordsInput.setResizable(false); 218 chordsInput.setLocationRelativeTo(frame); 219 chordsInput.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 220 chordsInput.setVisible(false); 221 222 chordsFramePanel.add(chordsInputPanel, BorderLayout.CENTER); 223 chordsFramePanel.add(saveChordsB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT 224 225 oneChordInput.add(oneChordPanel); 226 oneChordInput.pack(); 227 oneChordInput.setResizable(false); 228 oneChordInput.setLocationRelativeTo(chordsInput); 229 oneChordInput.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 230 oneChordInput.setVisible(false); 231 232 oneChordPanel.add(oneChordContentPanel, BorderLayout.CENTER); 233 oneChordPanel.add(arpeggiateCB, BorderLayout.EAST); // TODO: make this look nicer 234 oneChordPanel.add(saveOneChordB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT 235 236 oneChordContentPanel.add(rootNoteL); 237 oneChordContentPanel.add(keyNotesL); 238 oneChordContentPanel.add(extraNotesL); 239 oneChordContentPanel.add(chordRootNoteCB); 240 oneChordContentPanel.add(keyNotesCheckBoxPanel); 241 oneChordContentPanel.add(extraNotesCheckBoxPanel); 242 243 keyNotesCheckBoxPanel.add(keyNoteCheckBox2); 244 keyNotesCheckBoxPanel.add(keyNoteCheckBox3); 245 keyNotesCheckBoxPanel.add(keyNoteCheckBox4); 246 keyNotesCheckBoxPanel.add(keyNoteCheckBox5); 247 keyNotesCheckBoxPanel.add(keyNoteCheckBox6); 248 keyNotesCheckBoxPanel.add(keyNoteCheckBox7); 249 keyNotesCheckBoxPanel.add(keyNoteCheckBox8); 250 251 extraNotesCheckBoxPanel.add(extraNoteCheckBox1); 252 extraNotesCheckBoxPanel.add(extraNoteCheckBox2); 253 extraNotesCheckBoxPanel.add(extraNoteCheckBox3); 254 extraNotesCheckBoxPanel.add(extraNoteCheckBox4); 255 extraNotesCheckBoxPanel.add(extraNoteCheckBox5); 256 257 rhythmDisplayPanel.add(rhythmDisplayRhythmPanel, BorderLayout.CENTER); 258 rhythmDisplayPanel.add(deleteRhythm, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT 259 260 chordsDisplayPanel.add(chordsDisplayChordsPanel, BorderLayout.CENTER); 261 chordsDisplayPanel.add(deleteChordsB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT 262 263 lengthAndMelodyPanel.add(lengthParametersLabelsPanel); 264 lengthAndMelodyPanel.add(lengthParametersComboBoxesPanel); 265 lengthAndMelodyPanel.add(new JPanel()); 266 lengthAndMelodyPanel.add(new JPanel()); 267 lengthAndMelodyPanel.add(melodyL); 268 lengthAndMelodyPanel.add(melodyDisplayMelodyPanel); 269 lengthAndMelodyPanel.add(playMelodyB); 270 271 lengthParametersLabelsPanel.add(timeSigL); 272 lengthParametersLabelsPanel.add(numberMeasuresL); 273 lengthParametersLabelsPanel.add(smallestSubdivL); 274 275 lengthParametersComboBoxesPanel.add(timeSigCB); 276 lengthParametersComboBoxesPanel.add(numberMeasuresCB); 277 lengthParametersComboBoxesPanel.add(smallestSubdivCB); 278 279 frame.setVisible(true); 280 281 282 // ActionListeners 283 284 enterRhythmB.addActionListener(new ActionListener(){ 285 @Override 286 public void actionPerformed(ActionEvent e){ 287 rhythmInput.setVisible(true); 288 } 289 }); 290 291 rhythmInput.addComponentListener(new ComponentAdapter(){ 292 @Override 293 public void componentShown(ComponentEvent e){ 294 super.componentShown(e); 295 // setBufferRhythm(getRhythm()); 296 setBufferRhythm(new boolean[getLength()]); // TODO: use this approach for every setter 297 for(int i = 0; i < getLength(); i++){ 298 getBufferRhythm()[i] = getRhythm()[i]; 299 } 300 } 301 302 @Override 303 public void componentHidden(ComponentEvent e){ 304 super.componentHidden(e); 305 rhythmInputPanel.setRhythm(getRhythm()); 306 } 307 }); 308 309 rhythmInputPanel.addMouseListener(new MouseListener(){ 310 @Override 311 public void mouseClicked(MouseEvent e){ 312 int clear = (Main.OTHER_FRAME_WIDTH/4)/(getLength()+1); // width of the space in between rectangles 313 int rect = (Main.OTHER_FRAME_WIDTH*3/4)/getLength(); // width of each rectangle 314 for(int i = 1; i <= getLength(); i++){ 315 if(clear*i+rect*(i-1) <= e.getX() & e.getX() <= clear*i+rect*(i-1)+rect && Main.OTHER_FRAME_HEIGHT/3 <= e.getY() && e.getY() <= Main.OTHER_FRAME_HEIGHT*2/3){ 316 getBufferRhythm()[i-1] = !getBufferRhythm()[i-1]; 317 break; 318 } 319 } 320 rhythmInputPanel.setRhythm(getBufferRhythm()); 321 rhythmInputPanel.repaint(); 322 } 323 324 @Override 325 public void mousePressed(MouseEvent e){ 326 327 } 328 329 @Override 330 public void mouseReleased(MouseEvent e){ 331 332 } 333 334 @Override 335 public void mouseEntered(MouseEvent e){ 336 337 } 338 339 @Override 340 public void mouseExited(MouseEvent e){ 341 342 } 343 }); 344 345 saveRhythmB.addActionListener(new ActionListener(){ 346 @Override 347 public void actionPerformed(ActionEvent e){ 348 setRhythm(getBufferRhythm()); 349 rhythmDisplayRhythmPanel.setRhythm(getRhythm()); 350 rhythmInput.setVisible(false); 351 setRhythmEntered(false); 352 for(boolean beat : getRhythm()){ 353 if(beat){ 354 setRhythmEntered(true); 355 deleteRhythm.setVisible(true); 356 enterRhythmB.setText("Edit rhythm"); 357 rhythmDisplayRhythmPanel.setErase(false); 358 break; 359 } 360 } 361 if(!getRhythmEntered()){ 362 deleteRhythm.setVisible(false); 363 enterRhythmB.setText("Enter rhythm"); 364 rhythmDisplayRhythmPanel.setErase(true); 365 } 366 rhythmDisplayRhythmPanel.repaint(); 367 } 368 }); 369 370 deleteRhythm.addActionListener(new ActionListener(){ 371 @Override 372 public void actionPerformed(ActionEvent e){ 373 setRhythm(new boolean[getLength()]); 374 setBufferRhythm(new boolean[getLength()]); 375 rhythmInputPanel.setRhythm(getRhythm()); 376 rhythmInputPanel.repaint(); 377 rhythmDisplayRhythmPanel.setRhythm(getRhythm()); 378 rhythmDisplayRhythmPanel.setErase(true); 379 rhythmDisplayRhythmPanel.repaint(); 380 setRhythmEntered(false); 381 deleteRhythm.setVisible(false); 382 enterRhythmB.setText("Enter rhythm"); 383 } 384 }); 385 386 enterChordsB.addActionListener(new ActionListener(){ 387 @Override 388 public void actionPerformed(ActionEvent e){ 389 chordsInput.setVisible(true); 390 } 391 }); 392 393 chordsInput.addComponentListener(new ComponentAdapter() { 394 @Override 395 public void componentShown(ComponentEvent e) { 396 super.componentShown(e); 397 setBufferChords(new Chord[getLength()]); 398 // set BufferChords to actual Chords for editing of actual Chords 399 for(int i = 0; i < getLength(); i++){ 400 getBufferChords()[i] = getChords()[i]; 401 } 402 } 403 404 @Override 405 public void componentHidden(ComponentEvent e) { 406 super.componentHidden(e); 407 chordsInputPanel.setChords(getChords()); 408 oneChordInput.setVisible(false); 409 } 410 }); 411 412 chordsInputPanel.addMouseListener(new MouseListener(){ 413 @Override 414 public void mouseClicked(MouseEvent e){ 415 416 } 417 418 @Override 419 public void mousePressed(MouseEvent e){ 420 if(e.getButton() == MouseEvent.BUTTON1){ 421 setEditChord(false); 422 setDeleteChord(false); 423 } else if(e.getButton() == MouseEvent.BUTTON2){ 424 setDeleteChord(true); 425 setEditChord(false); 426 } else if(e.getButton() == MouseEvent.BUTTON3){ 427 setEditChord(true); 428 setDeleteChord(false); 429 } 430 setChordBeginningIndex(-1); 431 setChordEndingIndex(-1); 432 int clear = (Main.OTHER_FRAME_WIDTH/4)/(getLength()+1); // width of the space in between rectangles 433 int rect = (Main.OTHER_FRAME_WIDTH*3/4)/getLength(); // width of each rectangle 434 for(int i = 1; i <= getLength(); i++){ 435 if(clear*i+rect*(i-1) <= e.getX() & e.getX() <= clear*i+rect*(i-1)+rect && Main.OTHER_FRAME_HEIGHT/3 <= e.getY() && e.getY() <= Main.OTHER_FRAME_HEIGHT*2/3){ 436 setChordBeginningIndex(i-1); 437 break; 438 } 439 } 440 } 441 442 @Override 443 public void mouseReleased(MouseEvent e){ 444 int clear = (Main.OTHER_FRAME_WIDTH/4)/(getLength()+1); // width of the space in between rectangles 445 int rect = (Main.OTHER_FRAME_WIDTH*3/4)/getLength(); // width of each rectangle 446 for(int i = 1; i <= getLength(); i++){ 447 if(clear*i+rect*(i-1) <= e.getX() & e.getX() <= clear*i+rect*(i-1)+rect && Main.OTHER_FRAME_HEIGHT/3 <= e.getY() && e.getY() <= Main.OTHER_FRAME_HEIGHT*2/3){ 448 setChordEndingIndex(i-1); 449 break; 450 } 451 } 452 453 if(getChordBeginningIndex() != -1 && getChordEndingIndex() != -1){ // only try to make new chord / edit chord if user selected proper interval of beats 454 if(getDeleteChord()){ 455 setBufferOneChord(null); 456 for(ActionListener a : saveOneChordB.getActionListeners()){ // invoke ActionListener of saveOneChordB so that it saves the fact that chords have been deleted 457 a.actionPerformed(new ActionEvent(saveOneChordB, ActionEvent.ACTION_PERFORMED, null)); 458 } 459 } else { 460 if(getBufferChords()[getChordBeginningIndex()] == null){ // if no chord is entered as of now, the user can't edit a chord -> this is also done if getEditChord() is false because one will always have to check at least one if-statement (more inefficient way would be this: 1. if-statement -> if(getEditChord()); 2. if-statement -> the current one) 461 setEditChord(false); 462 } 463 oneChordInput.setVisible(true); // the chord editing window is only supposed to be shown when the user either wants to edit or create a chord 464 } 465 } 466 } 467 468 @Override 469 public void mouseEntered(MouseEvent e){ 470 471 } 472 473 @Override 474 public void mouseExited(MouseEvent e){ 475 476 } 477 }); 478 479 oneChordInput.addComponentListener(new ComponentAdapter(){ 480 @Override 481 public void componentShown(ComponentEvent e){ 482 super.componentShown(e); 483 if(getEditChord()){ 484 setBufferOneChord(copyOnlyChordInformationAndNotReference(getBufferChords()[getChordBeginningIndex()])); 485 updateCheckBoxSelectionStatus(getBufferOneChord()); 486 updateArpeggiateCBSelectedIndex(); 487 chordRootNoteCB.setSelectedIndex(findChordRootNoteCBNoteIndex(getBufferOneChord().getRootNote())); 488 } else { 489 setBufferOneChord(new Chord((String)chordRootNoteCB.getItemAt(0), true)); 490 updateCheckBoxSelectionStatus(getBufferOneChord()); 491 chordRootNoteCB.setSelectedIndex(0); 492 arpeggiateCB.setSelectedIndex(0); 493 } 494 } 495 496 @Override 497 public void componentHidden(ComponentEvent e){ 498 super.componentHidden(e); 499 } 500 }); 501 502 chordRootNoteCB.addActionListener(new ActionListener(){ 503 @Override 504 public void actionPerformed(ActionEvent e){ 505 updateCheckBoxes(); 506 if(getBufferOneChord() != null){ // if the bufferChord is null, the user doesn't want to enter a chord (every time the enterOneChord frame is opened a new bufferChord is created), which means that the bufferChord's notes don't have to be updated 507 getBufferOneChord().setRootNote((String)chordRootNoteCB.getSelectedItem(), getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1); 508 invokeCheckBoxActionListeners(); 509 } 510 } 511 }); 512 513 // keyNotesCheckBoxes ActionListeners 514 for(int i = 0; i < keyNotesCheckBoxesArray.length; i++){ 515 int finalI = i; // i has to be "effectively final" (god knows why) 516 keyNotesCheckBoxesArray[i].addActionListener(new ActionListener(){ 517 @Override 518 public void actionPerformed(ActionEvent e){ 519 if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote 520 if(finalI != 6){ // the rootNote (which is at the last index (of 6) in the keyNotesCheckBoxesArray) belongs to the first index of the keyChordNoteArray -> the index of everything else is shifted by one 521 if(keyNotesCheckBoxesArray[finalI].isSelected()){ 522 getBufferOneChord().getKeyChordNotes()[finalI+1] = Melody.extractActualNoteName(keyNotesCheckBoxesArray[finalI].getText()); 523 } else { 524 getBufferOneChord().getKeyChordNotes()[finalI+1] = null; 525 } 526 } 527 } else { // rootNote == extraNote -> copy keyNotesArray the way it is 528 if(keyNotesCheckBoxesArray[finalI].isSelected()){ 529 getBufferOneChord().getKeyChordNotes()[finalI] = Melody.extractActualNoteName(keyNotesCheckBoxesArray[finalI].getText()); 530 } else { 531 getBufferOneChord().getKeyChordNotes()[finalI] = null; 532 } 533 } 534 } 535 }); 536 } 537 538 // extraNotesCheckBoxes ActionListeners 539 for(int i = 0; i < extraNotesCheckBoxesArray.length; i++){ 540 int finalI = i; // i has to be "effectively final" (god knows why) 541 extraNotesCheckBoxesArray[i].addActionListener(new ActionListener(){ 542 @Override 543 public void actionPerformed(ActionEvent e){ 544 if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote -> copy extraNotesArray the way it is 545 if(extraNotesCheckBoxesArray[finalI].isSelected()){ 546 getBufferOneChord().getExtraChordNotes()[finalI] = extraNotesCheckBoxesArray[finalI].getText(); 547 } else { 548 getBufferOneChord().getExtraChordNotes()[finalI] = null; 549 } 550 } else { // rootNote == extraNote 551 if(finalI != 4){ // the rootNote (which is at the last index (of 4) in the extraNotesCheckBoxesArray) belongs to the first index of the extraChordNotesArray -> the index of everything else is shifted by one 552 if(extraNotesCheckBoxesArray[finalI].isSelected()){ 553 getBufferOneChord().getExtraChordNotes()[finalI+1] = extraNotesCheckBoxesArray[finalI].getText(); 554 } else { 555 getBufferOneChord().getExtraChordNotes()[finalI+1] = null; 556 } 557 } 558 } 559 } 560 }); 561 } 562 563 arpeggiateCB.addActionListener(new ActionListener(){ 564 @Override 565 public void actionPerformed(ActionEvent actionEvent) { 566 getBufferOneChord().setArpeggiate(arpeggiateCB.getSelectedIndex() == 1); 567 } 568 }); 569 570 saveOneChordB.addActionListener(new ActionListener(){ 571 @Override 572 public void actionPerformed(ActionEvent e){ 573 if(getBufferOneChord() != null){ 574 getBufferOneChord().setChordRootNoteCBIndex(findChordRootNoteCBNoteIndex(getBufferOneChord().getRootNote())); 575 } 576 if(getChordEndingIndex() < getChordBeginningIndex()){ 577 // swap values if endingIndex is greater than beginningIndex 578 // 1: a; 2: b (1 == getChordBeginningIndex(); a == getChordBeginningIndex()'s value at the start; 2 == getChordEndingIndex(); b == getChordEndingIndex()'s value at the start) 579 // 1 = 1 - 2 580 setChordBeginningIndex(getChordBeginningIndex()-getChordEndingIndex()); // ==> 1: a-b; 2: b 581 // 2 = 2 + 1 582 setChordEndingIndex(getChordEndingIndex()+getChordBeginningIndex()); // ==> 1: a-b; 2: a 583 // 1 = 2 - 1 584 setChordBeginningIndex(getChordEndingIndex()-getChordBeginningIndex()); // ==> 1: b; 2: a 585 } 586 for(int i = getChordBeginningIndex(); i <= getChordEndingIndex(); i++){ 587 getBufferChords()[i] = getBufferOneChord(); 588 } 589 oneChordInput.setVisible(false); 590 chordsInputPanel.setChords(getBufferChords()); 591 chordsInputPanel.repaint(); 592 } 593 }); 594 595 saveChordsB.addActionListener(new ActionListener(){ 596 @Override 597 public void actionPerformed(ActionEvent e){ 598 setChords(getBufferChords()); 599 chordsDisplayChordsPanel.setChords(getChords()); 600 melodyDisplayMelodyPanel.setChords(getChords()); 601 chordsInput.setVisible(false); 602 oneChordInput.setVisible(false); 603 setChordsEntered(false); 604 for(Chord chord : getChords()){ 605 if(chord != null){ 606 setChordsEntered(true); 607 deleteChordsB.setVisible(true); 608 enterChordsB.setText("Edit chords"); 609 chordsDisplayChordsPanel.setErase(false); 610 break; 611 } 612 } 613 if(!getChordsEntered()){ 614 deleteChordsB.setVisible(false); 615 enterChordsB.setText("Enter chords"); 616 chordsDisplayChordsPanel.setErase(true); 617 } 618 chordsDisplayChordsPanel.repaint(); 619 } 620 }); 621 622 deleteChordsB.addActionListener(new ActionListener(){ 623 @Override 624 public void actionPerformed(ActionEvent e){ 625 setChords(new Chord[getLength()]); 626 setBufferChords(new Chord[getLength()]); 627 chordsInputPanel.setChords(getChords()); // TODO: find out whether it's smarter to create a new Chord[] or to reference getChords() which were just given the value of a new Chord[] 628 chordsInputPanel.repaint(); 629 chordsDisplayChordsPanel.setChords(getChords()); 630 chordsDisplayChordsPanel.setErase(true); 631 chordsDisplayChordsPanel.repaint(); 632 melodyDisplayMelodyPanel.setChords(getChords()); 633 setChordsEntered(false); 634 deleteChordsB.setVisible(false); 635 enterChordsB.setText("Enter chords"); 636 } 637 }); 638 639 // TODO: improve project structure by always using an instance of the Melody class to store all the rhythmic & chords information so that the GUI class actually only deals with GUI stuff 640 641 createMelodyB.addActionListener(new ActionListener(){ 642 @Override 643 public void actionPerformed(ActionEvent e){ 644 setMelody(new Melody(getLength())); 645 getMelody().createKeyNotes((String)tonicCB.getSelectedItem(), scaleCB.getSelectedIndex()); 646 if(getRhythmEntered()){ 647 getMelody().setRhythm(getRhythm()); 648 } else { 649 getMelody().createRhythm(); 650 } 651 if(getChordsEntered()){ 652 getMelody().createChordsMelody(getChords()); 653 } else { 654 getMelody().createMelody(); 655 } 656 melodyDisplayMelodyPanel.setMelody(getMelody()); 657 melodyDisplayMelodyPanel.setErase(false); 658 melodyDisplayMelodyPanel.repaint(); 659 } 660 }); 661 662 playMelodyB.addActionListener(new ActionListener(){ 663 @Override 664 public void actionPerformed(ActionEvent e){ 665 if(getMelody() != null){ 666 for(int i = 0; i < getLength(); i++){ 667 if(getMelody().getRhythm()[i]){ 668 if(getMelody().findKeyNoteIndex(getMelody().getMelody()[i]) < getMelody().getChangeIndex()){ 669 getMusicPlayer().playNote(getMusicPlayer().getNotes().get(getMelody().getMelody()[i]), 500); 670 } else { 671 getMusicPlayer().playNote(getMusicPlayer().getNotes().get(getMelody().getMelody()[i] + "'"), 500); 672 } 673 } else { 674 getMusicPlayer().playNote(getMusicPlayer().getNotes().get("click"), 500); 675 } 676 try{ 677 Thread.sleep(500); 678 } 679 catch(Exception k) { 680 System.out.println("Whoooops..."); 681 } 682 } 683 } 684 } 685 }); 686 687 // TODO: update getChords() when key is changed -> transpose 688 689 tonicCB.addActionListener(new ActionListener(){ 690 @Override 691 public void actionPerformed(ActionEvent e){ 692 updateKey(); 693 } 694 }); 695 696 scaleCB.addActionListener(new ActionListener(){ 697 @Override 698 public void actionPerformed(ActionEvent e){ 699 updateKey(); 700 } 701 }); 702 703 timeSigCB.addActionListener(new ActionListener(){ // TODO: store images in an array and use only one smart "for statement" to add the respective elements to the subdivModel 704 @Override 705 public void actionPerformed(ActionEvent e){ 706 // Delete all elements in smallestSubdivCB 707 int size = subdivModel.getSize(); 708 for(int i = 0; i < size; i++){ 709 subdivModel.removeElementAt(0); 710 } 711 // Add all fitting elements to smallestSubdivCB 712 switch(timeSigCB.getSelectedIndex()){ 713 case 0: 714 subdivModel.addElement(whole); 715 subdivModel.addElement(half); 716 subdivModel.addElement(quarter); 717 subdivModel.addElement(eighth); 718 subdivModel.addElement(sixteenth); 719 subdivModel.addElement(thirtysecond); 720 smallestSubdivCB.setModel(subdivModel); 721 smallestSubdivCB.setSelectedIndex(4); 722 break; 723 case 2: 724 case 3: 725 subdivModel.addElement(half); 726 subdivModel.addElement(quarter); 727 subdivModel.addElement(eighth); 728 subdivModel.addElement(sixteenth); 729 subdivModel.addElement(thirtysecond); 730 smallestSubdivCB.setModel(subdivModel); 731 smallestSubdivCB.setSelectedIndex(3); 732 break; 733 case 1: 734 case 4: 735 case 5: 736 subdivModel.addElement(quarter); 737 subdivModel.addElement(eighth); 738 subdivModel.addElement(sixteenth); 739 subdivModel.addElement(thirtysecond); 740 smallestSubdivCB.setModel(subdivModel); 741 smallestSubdivCB.setSelectedIndex(2); 742 break; 743 case 6: 744 subdivModel.addElement(eighth); 745 subdivModel.addElement(sixteenth); 746 subdivModel.addElement(thirtysecond); 747 smallestSubdivCB.setModel(subdivModel); 748 smallestSubdivCB.setSelectedIndex(1); 749 break; 750 case 7: 751 subdivModel.addElement(sixteenth); 752 subdivModel.addElement(thirtysecond); 753 smallestSubdivCB.setModel(subdivModel); 754 smallestSubdivCB.setSelectedIndex(0); 755 break; 756 default: 757 break; 758 } 759 updateLength(); 760 } 761 }); 762 763 numberMeasuresCB.addActionListener(new ActionListener(){ 764 @Override 765 public void actionPerformed(ActionEvent e){ 766 updateLength(); 767 } 768 }); 769 770 smallestSubdivCB.addActionListener(new ActionListener(){ 771 @Override 772 public void actionPerformed(ActionEvent e){ 773 updateLength(); 774 } 775 }); 776 } 777 778 779 // Getters & Setters 780 781 private Melody getMelody() { 782 return this.melody; 783 } 784 785 private void setMelody(Melody melody) { 786 this.melody = melody; 787 } 788 789 public Melody getCalcMelody() { 790 return this.calcMelody; 791 } 792 793 public void setCalcMelody(Melody calcMelody) { 794 this.calcMelody = calcMelody; 795 calcMelody.createKeyNotes((String)tonicCB.getSelectedItem(), scaleCB.getSelectedIndex()); // updateCalcMelodyNotes 796 } 797 798 public MusicPlayer getMusicPlayer(){ 799 return this.musicPlayer; 800 } 801 802 public void setMusicPlayer(MusicPlayer musicPlayer){ 803 this.musicPlayer = musicPlayer; 804 } 805 806 private boolean getRhythmEntered() { 807 return this.rhythmEntered; 808 } 809 810 private void setRhythmEntered(boolean rhythmEntered) { 811 this.rhythmEntered = rhythmEntered; 812 } 813 814 private boolean getChordsEntered() { 815 return this.chordsEntered; 816 } 817 818 private void setChordsEntered(boolean chordsEntered) { 819 this.chordsEntered = chordsEntered; 820 } 821 822 public boolean getEditChord(){ 823 return this.editChord; 824 } 825 826 public void setEditChord(boolean editChord) { 827 this.editChord = editChord; 828 } 829 830 public boolean getDeleteChord(){ 831 return this.deleteChord; 832 } 833 834 public void setDeleteChord(boolean deleteChord){ 835 this.deleteChord = deleteChord; 836 } 837 838 public boolean[] getRhythm() { 839 return this.rhythm; 840 } 841 842 public void setRhythm(boolean[] rhythm) { 843 this.rhythm = rhythm; 844 } 845 846 public boolean[] getBufferRhythm() { 847 return this.bufferRhythm; 848 } 849 850 public void setBufferRhythm(boolean[] bufferRhythm) { 851 this.bufferRhythm = bufferRhythm; 852 } 853 854 public Chord[] getChords() { 855 return this.chords; 856 } 857 858 public void setChords(Chord[] chords) { 859 this.chords = chords; 860 } 861 862 public Chord[] getBufferChords(){ 863 return this.bufferChords; 864 } 865 866 public void setBufferChords(Chord[] bufferChords){ 867 this.bufferChords = bufferChords; 868 } 869 870 public Chord getBufferOneChord(){ 871 return this.bufferOneChord; 872 } 873 874 public void setBufferOneChord(Chord bufferOneChord){ 875 this.bufferOneChord = bufferOneChord; 876 } 877 878 private int getLength() { 879 return this.length; 880 } 881 882 private void setLength(String timeSig, int numberMeasures, int smallestSubdiv) { 883 if(timeSigCB.getSelectedIndex() != 7){ 884 this.length = numberMeasures * Integer.parseInt(String.valueOf(timeSig.charAt(0))) * smallestSubdiv / Integer.parseInt(String.valueOf(timeSig.charAt(2))); 885 } 886 else { 887 this.length = numberMeasures * 15 * smallestSubdiv / 16; // fixes bug with 15/16 888 } 889 } 890 891 public int getChordBeginningIndex(){ 892 return this.chordBeginningIndex; 893 } 894 895 public void setChordBeginningIndex(int chordBeginningIndex){ 896 this.chordBeginningIndex = chordBeginningIndex; 897 } 898 899 public int getChordEndingIndex(){ 900 return this.chordEndingIndex; 901 } 902 903 public void setChordEndingIndex(int chordEndingIndex){ 904 this.chordEndingIndex = chordEndingIndex; 905 } 906 907 908 // Actual methods 909 910 // (TODO: make new getChords() when length is changed (except when only numberOfMeasures is changed -> then copy the respective measures)) 911 912 private void updateLength(){ 913 if(smallestSubdivCB.getSelectedItem() == whole){ 914 setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 1); 915 } else if(smallestSubdivCB.getSelectedItem() == half){ 916 setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 2); 917 } else if(smallestSubdivCB.getSelectedItem() == quarter){ 918 setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 4); 919 } else if(smallestSubdivCB.getSelectedItem() == eighth){ 920 setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 8); 921 } else if(smallestSubdivCB.getSelectedItem() == sixteenth){ 922 setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 16); 923 } else if(smallestSubdivCB.getSelectedItem() == thirtysecond){ 924 setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 32); 925 } 926 setCalcMelody(new Melody(getLength())); 927 setMelody(null); 928 comboBoxColorRenderer.setCalcMelody(getCalcMelody()); 929 chordsInputPanel.setCalcMelody(getCalcMelody()); 930 chordsDisplayChordsPanel.setCalcMelody(getCalcMelody()); 931 setRhythm(new boolean[getLength()]); 932 setBufferRhythm(new boolean[getLength()]); 933 for(ActionListener a : saveRhythmB.getActionListeners()){ 934 a.actionPerformed(new ActionEvent(saveRhythmB, ActionEvent.ACTION_PERFORMED, null)); // TODO: potentially reopen the windows that were opened before the length was changed for improved workflow 935 } 936 setChords(new Chord[getLength()]); 937 setBufferChords(new Chord[getLength()]); 938 for(ActionListener a : saveChordsB.getActionListeners()){ 939 a.actionPerformed(new ActionEvent(saveChordsB, ActionEvent.ACTION_PERFORMED, null)); // TODO: potentially reopen the windows that were opened before the length was changed for improved workflow 940 } 941 rhythmInputPanel.setLength(getLength()); 942 rhythmInputPanel.repaint(); 943 rhythmDisplayRhythmPanel.setLength(getLength()); 944 chordsInputPanel.setLength(getLength()); 945 chordsInputPanel.repaint(); 946 chordsDisplayChordsPanel.setLength(getLength()); 947 oneChordInput.setVisible(false); // TODO: potentially reopen the windows that were opened before the length was changed for improved workflow 948 melodyDisplayMelodyPanel.setLength(getLength()); 949 melodyDisplayMelodyPanel.setErase(true); 950 melodyDisplayMelodyPanel.repaint(); 951 } 952 953 private void updateChordRootNoteModel(){ 954 // Delete all elements but the last one (caused NullPointerException) 955 int size = chordRootNoteModel.getSize(); 956 for(int i = 0; i < size-1; i++){ 957 chordRootNoteModel.removeElementAt(0); 958 } 959 // Add new elements 960 addChordRootNoteModelElements(); 961 // Delete the last element that was still left from the last set of notes 962 chordRootNoteModel.removeElementAt(0); 963 } 964 965 private void addChordRootNoteModelElements(){ 966 for(int i = getCalcMelody().findAllNotesIndex((String)tonicCB.getSelectedItem()); i < getCalcMelody().findAllNotesIndex((String)tonicCB.getSelectedItem()) + getCalcMelody().getAllNotes().length; i++){ 967 if(i < getCalcMelody().getAllNotes().length){ 968 if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) != -1){ 969 chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i] + " (" + toRoman(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) + 1) + ")"); 970 } else { 971 chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i]); 972 } 973 } else { 974 if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length]) != -1){ 975 chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length] + " (" + toRoman(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length]) + 1) + ")"); 976 } else { 977 chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length]); 978 } 979 } 980 } 981 } 982 983 private void updateCheckBoxes(){ // updates which CheckBoxes should be visible depending on the currently selected key/rootNote & updates the names of the notes of the CheckBoxes 984 if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote 985 keyNoteCheckBox8.setVisible(false); 986 extraNoteCheckBox5.setVisible(true); 987 updateCheckBoxNotes(); 988 } else { // rootNote == extraNote 989 keyNoteCheckBox8.setVisible(true); 990 extraNoteCheckBox5.setVisible(false); 991 updateCheckBoxNotes(); 992 } 993 } 994 995 private void updateCheckBoxNotes(){ // updates the names of the notes of the CheckBoxes 996 int keyIndex = 0; 997 int extraIndex = 0; 998 for(int i = getCalcMelody().findAllNotesIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem()))+1; i < getCalcMelody().getAllNotes().length; i++){ // start iteration through allNotes on note after rootNote 999 if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) != -1){ // current note = keyNote 1000 keyNotesCheckBoxesArray[keyIndex].setText(getCalcMelody().getAllNotes()[i] + " (" + (keyIndex+2) + "/" + (keyIndex+2+7) + ")"); 1001 keyIndex++; 1002 } else { // current note = extraNote 1003 extraNotesCheckBoxesArray[extraIndex].setText(getCalcMelody().getAllNotes()[i]); 1004 extraIndex++; 1005 } 1006 } 1007 for(int i = 0; i <= getCalcMelody().findAllNotesIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())); i++){ // finish iteration through allNotes 1008 if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) != -1){ // current note = keyNote 1009 if(keyIndex != 6){ 1010 keyNotesCheckBoxesArray[keyIndex].setText(getCalcMelody().getAllNotes()[i] + " (" + (keyIndex+2) + "/" + (keyIndex+2+7) + ")"); 1011 } else { 1012 keyNotesCheckBoxesArray[keyIndex].setText(getCalcMelody().getAllNotes()[i] + " (" + (keyIndex+2) + ")"); 1013 } 1014 keyIndex++; 1015 } else { // current note = extraNote 1016 extraNotesCheckBoxesArray[extraIndex].setText(getCalcMelody().getAllNotes()[i]); 1017 extraIndex++; 1018 } 1019 } 1020 } 1021 1022 private void invokeCheckBoxActionListeners(){ // updates getBufferChord() information 1023 // keyNoteCheckBoxes 1024 for(int i = 0; i < keyNotesCheckBoxesArray.length; i++){ 1025 for(ActionListener a: keyNotesCheckBoxesArray[i].getActionListeners()){ 1026 a.actionPerformed(new ActionEvent(keyNotesCheckBoxesArray[i], ActionEvent.ACTION_PERFORMED, null)); 1027 } 1028 } 1029 // extraNoteCheckBoxes 1030 for(int i = 0; i < extraNotesCheckBoxesArray.length; i++){ 1031 for(ActionListener a: extraNotesCheckBoxesArray[i].getActionListeners()){ 1032 a.actionPerformed(new ActionEvent(extraNotesCheckBoxesArray[i], ActionEvent.ACTION_PERFORMED, null)); 1033 } 1034 } 1035 } 1036 1037 private void updateCheckBoxSelectionStatus(Chord chord){ // updates the CheckBoxes so that their selection status corresponds to the selected notes of the parameter (input) chord 1038 if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote 1039 // keyNoteCheckBoxes 1040 for(int i = 0; i < keyNotesCheckBoxesArray.length-1; i++){ // omit the last CheckBox because it's the root note and not visible anyway 1041 keyNotesCheckBoxesArray[i].setSelected(chord.getKeyChordNotes()[i+1] != null); 1042 } 1043 // extraNoteCheckBoxes 1044 for(int i = 0; i < extraNotesCheckBoxesArray.length; i++){ 1045 extraNotesCheckBoxesArray[i].setSelected(chord.getExtraChordNotes()[i] != null); 1046 } 1047 } else { // rootNote == extraNote 1048 // keyNoteCheckBoxes 1049 for(int i = 0; i < keyNotesCheckBoxesArray.length; i++){ 1050 keyNotesCheckBoxesArray[i].setSelected(chord.getKeyChordNotes()[i] != null); 1051 } 1052 // extraNoteCheckBoxes 1053 for(int i = 0; i < extraNotesCheckBoxesArray.length-1; i++){ // omit the last CheckBox because it's the root note and not visible anyway 1054 extraNotesCheckBoxesArray[i].setSelected(chord.getExtraChordNotes()[i+1] != null); 1055 } 1056 } 1057 } 1058 1059 private void updateArpeggiateCBSelectedIndex(){ 1060 if(getBufferOneChord().getArpeggiate()){ 1061 arpeggiateCB.setSelectedIndex(1); 1062 } else { 1063 arpeggiateCB.setSelectedIndex(0); 1064 } 1065 } 1066 1067 private static String toRoman(int number) { 1068 return String.valueOf(new char[number]).replace('\0', 'I') 1069 .replace("IIIII", "V") 1070 .replace("IIII", "IV") 1071 .replace("VV", "X") 1072 .replace("VIV", "IX") 1073 .replace("XXXXX", "L") 1074 .replace("XXXX", "XL") 1075 .replace("LL", "C") 1076 .replace("LXL", "XC") 1077 .replace("CCCCC", "D") 1078 .replace("CCCC", "CD") 1079 .replace("DD", "M") 1080 .replace("DCD", "CM"); 1081 } 1082 1083 private void outputChords(Chord[] chords){ 1084 for(int i = 0; i < chords.length; i++){ 1085 System.out.println(i + ": "); 1086 if(chords[i] != null){ 1087 System.out.println("Rootnote: " + chords[i].getRootNote()); 1088 System.out.println("Arpeggiate: " + chords[i].getArpeggiate()); 1089 System.out.println("KeyChordNotes: "); 1090 for(int j = 0; j < chords[i].getKeyChordNotes().length; j++){ 1091 System.out.print(chords[i].getKeyChordNotes()[j] + ", "); 1092 } 1093 System.out.println(""); 1094 System.out.println("ExtraChordNotes: "); 1095 for(int j = 0; j < chords[i].getExtraChordNotes().length; j++){ 1096 System.out.print(chords[i].getExtraChordNotes()[j] + ", "); 1097 } 1098 } else { 1099 System.out.println("Null"); 1100 } 1101 System.out.println("\n"); 1102 } 1103 } 1104 1105 private int findChordRootNoteCBNoteIndex(String note){ 1106 for(int i = 0; i < 12; i++){ 1107 if(chordRootNoteCB.getItemAt(i).equals(note)){ 1108 return i; 1109 } 1110 } 1111 return -1; 1112 } 1113 1114 private Chord copyOnlyChordInformationAndNotReference(Chord chord){ // returns new Chord with all the information of the input chord 1115 // copy rootNote 1116 Chord newChord = new Chord(chord.getRootNote(), getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName(chord.getRootNote())) != -1); 1117 // copy keyNotes 1118 for(int i = 0; i < newChord.getKeyChordNotes().length; i++){ 1119 newChord.getKeyChordNotes()[i] = chord.getKeyChordNotes()[i]; 1120 } 1121 // copy extraNotes 1122 for(int i = 0; i < newChord.getExtraChordNotes().length; i++){ 1123 newChord.getExtraChordNotes()[i] = chord.getExtraChordNotes()[i]; 1124 } 1125 // copy arpeggiate 1126 newChord.setArpeggiate(chord.getArpeggiate()); 1127 // copy chordRootNoteCBIndex 1128 newChord.setChordRootNoteCBIndex(chord.getChordRootNoteCBIndex()); 1129 return newChord; 1130 } 1131 1132 private void transposeChords(Chord[] chords){ // this is only used when the key was changed and getChordsEntered() is true 1133 int index = 0; 1134 for(int i = 0; i < chords.length; i++){ 1135 if(i == index){ 1136 if(chords[i] != null){ 1137 // transpose the chord at the index 'i' 1138 chordRootNoteCB.setSelectedIndex(chords[i].getChordRootNoteCBIndex()); // this updates the notes to the transposed chord's ones 1139 setBufferOneChord(new Chord((String)chordRootNoteCB.getSelectedItem(), getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1)); // make sure that each chord references a new (transposed) chord 1140 getBufferOneChord().setChordRootNoteCBIndex(chords[i].getChordRootNoteCBIndex()); 1141 getBufferOneChord().setArpeggiate(chords[i].getArpeggiate()); 1142 updateCheckBoxSelectionStatus(chords[i]); // this keeps the selected notes of the original chord stored in the oneChordFrame 1143 invokeCheckBoxActionListeners(); // this extracts the new note information from the frame to the bufferChord 1144 // save the transposed chord to as many beats as necessary 1145 while(index < chords.length-1 && Chord.chordsEqual(chords[i], chords[index+1])){ // always keep the chord of the first beat of potentially several beats of the same chord in order to have something to compare the other beats to 1146 chords[index+1] = copyOnlyChordInformationAndNotReference(getBufferOneChord()); // save some time by not repeating this process of transposing for every beat that actually stores the same chord info as the beat before 1147 index++; 1148 } 1149 chords[i] = copyOnlyChordInformationAndNotReference(getBufferOneChord()); 1150 } 1151 index++; // index has to be incremented even if the current chord is null 1152 } 1153 } 1154 } 1155 1156 private void updateKey(){ 1157 calcMelody.createKeyNotes((String)tonicCB.getSelectedItem(), scaleCB.getSelectedIndex()); // updateCalcMelodyNotes 1158 updateChordRootNoteModel(); 1159 if(getChordsEntered()){ 1160 // transpose getBufferChords() & getChords() 1161 transposeChords(getBufferChords()); 1162 transposeChords(getChords()); 1163 // update chords everywhere else 1164 chordsInputPanel.setChords(getBufferChords()); 1165 chordsInputPanel.repaint(); 1166 chordsDisplayChordsPanel.setChords(getChords()); 1167 chordsDisplayChordsPanel.repaint(); 1168 melodyDisplayMelodyPanel.setChords(getChords()); 1169 } 1170 } 1171 } 1172