OSDN Git Service

・歌詞テキスト表示欄に誤った音名の(A~Gではない)コードを入れたときにダイアログを出すようにした
[midichordhelper/MIDIChordHelper.git] / src / camidion / chordhelper / midieditor / NewSequenceDialog.java
1 package camidion.chordhelper.midieditor;\r
2 \r
3 import java.awt.Dimension;\r
4 import java.awt.Graphics;\r
5 import java.awt.Graphics2D;\r
6 import java.awt.GridLayout;\r
7 import java.awt.Insets;\r
8 import java.awt.Point;\r
9 import java.awt.Rectangle;\r
10 import java.awt.event.ActionEvent;\r
11 import java.awt.event.ActionListener;\r
12 import java.awt.event.ComponentEvent;\r
13 import java.awt.event.ComponentListener;\r
14 import java.awt.event.InputEvent;\r
15 import java.awt.event.MouseEvent;\r
16 import java.awt.event.MouseListener;\r
17 import java.util.ArrayList;\r
18 import java.util.Vector;\r
19 \r
20 import javax.sound.midi.MidiChannel;\r
21 import javax.sound.midi.Sequence;\r
22 import javax.swing.AbstractAction;\r
23 import javax.swing.Action;\r
24 import javax.swing.BoxLayout;\r
25 import javax.swing.JButton;\r
26 import javax.swing.JCheckBox;\r
27 import javax.swing.JComboBox;\r
28 import javax.swing.JComponent;\r
29 import javax.swing.JDialog;\r
30 import javax.swing.JLabel;\r
31 import javax.swing.JPanel;\r
32 import javax.swing.JScrollPane;\r
33 import javax.swing.JSpinner;\r
34 import javax.swing.JTabbedPane;\r
35 import javax.swing.JTextArea;\r
36 import javax.swing.JTextField;\r
37 import javax.swing.SpinnerNumberModel;\r
38 import javax.swing.event.ChangeEvent;\r
39 import javax.swing.event.ChangeListener;\r
40 \r
41 import camidion.chordhelper.ButtonIcon;\r
42 import camidion.chordhelper.ChordHelperApplet;\r
43 import camidion.chordhelper.music.AbstractNoteTrackSpec;\r
44 import camidion.chordhelper.music.ChordProgression;\r
45 import camidion.chordhelper.music.DrumTrackSpec;\r
46 import camidion.chordhelper.music.FirstTrackSpec;\r
47 import camidion.chordhelper.music.MelodyTrackSpec;\r
48 import camidion.chordhelper.music.Range;\r
49 import camidion.chordhelper.pianokeyboard.PianoKeyboardListener;\r
50 import camidion.chordhelper.pianokeyboard.PianoKeyboardPanel;\r
51 \r
52 /**\r
53  * 新しいMIDIシーケンスを生成するダイアログ\r
54  */\r
55 public class NewSequenceDialog extends JDialog {\r
56         private static final Insets ZERO_INSETS = new Insets(0,0,0,0);\r
57         private static final Integer[] PPQList = {\r
58                 48,60,80,96,120,160,192,240,320,384,480,960\r
59         };\r
60         private static final String INITIAL_CHORD_STRING =\r
61                 "Key: C\nC G/B | Am Em/G | F C/E | Dm7 G7 C % | F G7 | Csus4 C\n";\r
62         private JTextArea chordText = new JTextArea(INITIAL_CHORD_STRING, 18, 30);\r
63         private JTextField seqNameText = new JTextField();\r
64         private JComboBox<Integer> ppqComboBox = new JComboBox<Integer>(PPQList);\r
65         private TimeSignatureSelecter timesigSelecter = new TimeSignatureSelecter();\r
66         private TempoSelecter tempoSelecter = new TempoSelecter();\r
67         private MeasureSelecter measureSelecter = new MeasureSelecter();\r
68         private TrackSpecPanel trackSpecPanel = new TrackSpecPanel() {{\r
69                 DrumTrackSpec dts = new DrumTrackSpec(9, "Percussion track");\r
70                 dts.velocity = 127;\r
71                 addTrackSpec(dts);\r
72                 MelodyTrackSpec mts;\r
73                 mts = new MelodyTrackSpec(2, "Bass track", new Range(36,48));\r
74                 mts.isBass = true;\r
75                 mts.velocity = 96;\r
76                 addTrackSpec(mts);\r
77                 mts =  new MelodyTrackSpec(1, "Chord track", new Range(60,72));\r
78                 addTrackSpec(mts);\r
79                 mts = new MelodyTrackSpec(0, "Melody track", new Range(60,84));\r
80                 mts.randomMelody = true;\r
81                 mts.beatPattern = 0xFFFF;\r
82                 mts.continuousBeatPattern = 0x820A;\r
83                 addTrackSpec(mts);\r
84         }};\r
85         /**\r
86          * ダイアログを開くアクション\r
87          */\r
88         public Action openAction = new AbstractAction("New") {\r
89                 {\r
90                         String tooltip = "Generate new song - 新しい曲を生成";\r
91                         putValue(Action.SHORT_DESCRIPTION, tooltip);\r
92                 }\r
93                 @Override\r
94                 public void actionPerformed(ActionEvent e) { setVisible(true); }\r
95         };\r
96         private MidiSequenceEditor midiEditor;\r
97         /**\r
98          * MIDIシーケンス生成アクション\r
99          */\r
100         public Action generateAction = new AbstractAction(\r
101                 "Generate & Add to PlayList",\r
102                 new ButtonIcon(ButtonIcon.EJECT_ICON)\r
103         ) {\r
104                 @Override\r
105                 public void actionPerformed(ActionEvent e) {\r
106                         midiEditor.sequenceListTable.getModel().addSequenceAndPlay(getMidiSequence());\r
107                         NewSequenceDialog.this.setVisible(false);\r
108                 }\r
109         };\r
110         /**\r
111          * 新しいMIDIシーケンスを生成するダイアログを構築します。\r
112          * @param midiEditor シーケンス追加先エディタ\r
113          */\r
114         public NewSequenceDialog(MidiSequenceEditor midiEditor) {\r
115                 this.midiEditor = midiEditor;\r
116                 trackSpecPanel.setChannels(midiEditor.getVirtualMidiDevice().getChannels());\r
117                 setTitle("Generate new sequence - " + ChordHelperApplet.VersionInfo.NAME);\r
118                 add(new JTabbedPane() {{\r
119                         add("Sequence", new JPanel() {{\r
120                                 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));\r
121                                 add(new JPanel() {{\r
122                                         setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
123                                         add(new JLabel("Sequence name:"));\r
124                                         add(seqNameText);\r
125                                 }});\r
126                                 add(new JPanel() {{\r
127                                         setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
128                                         add(new JLabel("Resolution in PPQ ="));\r
129                                         add(ppqComboBox);\r
130                                         add(measureSelecter);\r
131                                 }});\r
132                                 add(new JButton("Randomize (Tempo, Time signature, Chord progression)") {{\r
133                                         setMargin(ZERO_INSETS);\r
134                                         addActionListener(new ActionListener() {\r
135                                                 @Override\r
136                                                 public void actionPerformed(ActionEvent e) {\r
137                                                         setRandomChordProgression(\r
138                                                                 measureSelecter.getMeasureDuration()\r
139                                                         );\r
140                                                 }\r
141                                         });\r
142                                 }});\r
143                                 add(new JPanel() {{\r
144                                         setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
145                                         add(tempoSelecter);\r
146                                         add(new JPanel() {{\r
147                                                 add(new JLabel("Time signature ="));\r
148                                                 add(timesigSelecter);\r
149                                         }});\r
150                                 }});\r
151                                 add(new JPanel() {{\r
152                                         setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
153                                         add(new JLabel("Chord progression :"));\r
154                                         add(new JLabel("Transpose"));\r
155                                         add(new JButton(" + Up ") {{\r
156                                                 setMargin(ZERO_INSETS);\r
157                                                 addActionListener(new ActionListener() {\r
158                                                         @Override\r
159                                                         public void actionPerformed(ActionEvent e) {\r
160                                                                 ChordProgression cp = createChordProgression();\r
161                                                                 cp.transpose(1);\r
162                                                                 setChordProgression(cp);\r
163                                                         }\r
164                                                 });\r
165                                         }});\r
166                                         add(new JButton(" - Down ") {{\r
167                                                 setMargin(ZERO_INSETS);\r
168                                                 addActionListener(new ActionListener() {\r
169                                                         @Override\r
170                                                         public void actionPerformed(ActionEvent e) {\r
171                                                                 ChordProgression cp = createChordProgression();\r
172                                                                 cp.transpose(-1);\r
173                                                                 setChordProgression(cp);\r
174                                                         }\r
175                                                 });\r
176                                         }});\r
177                                         add(new JButton(" Enharmonic ") {{\r
178                                                 setMargin(ZERO_INSETS);\r
179                                                 addActionListener(new ActionListener() {\r
180                                                         @Override\r
181                                                         public void actionPerformed(ActionEvent e) {\r
182                                                                 ChordProgression cp = createChordProgression();\r
183                                                                 cp.toggleEnharmonically();\r
184                                                                 setChordProgression(cp);\r
185                                                         }\r
186                                                 });\r
187                                         }});\r
188                                         add(new JButton("Relative key") {{\r
189                                                 setMargin(ZERO_INSETS);\r
190                                                 addActionListener(new ActionListener() {\r
191                                                         @Override\r
192                                                         public void actionPerformed(ActionEvent e) {\r
193                                                                 ChordProgression cp = createChordProgression();\r
194                                                                 cp.toggleKeyMajorMinor();\r
195                                                                 setChordProgression(cp);\r
196                                                         }\r
197                                                 });\r
198                                         }});\r
199                                 }});\r
200                                 add(new JScrollPane(chordText));\r
201                                 add(new JPanel() {{\r
202                                         setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
203                                         add(new JButton(generateAction){{setMargin(ZERO_INSETS);}});\r
204                                 }});\r
205                         }});\r
206                         add("Track", trackSpecPanel);\r
207                 }});\r
208                 setBounds( 250, 200, 600, 540 );\r
209         }\r
210         /**\r
211          * 新しいコード進行を生成して返します。\r
212          * @return 新しいコード進行\r
213          */\r
214         private ChordProgression createChordProgression() {\r
215                 return new ChordProgression(chordText.getText());\r
216         }\r
217         /**\r
218          * MIDIシーケンスを生成して返します。\r
219          * @return MIDIシーケンス\r
220          */\r
221         public Sequence getMidiSequence() {\r
222                 FirstTrackSpec firstTrackSpec = new FirstTrackSpec(\r
223                         seqNameText.getText(),\r
224                         tempoSelecter.getTempoByteArray(),\r
225                         timesigSelecter.getByteArray()\r
226                 );\r
227                 return createChordProgression().toMidiSequence(\r
228                         (int)ppqComboBox.getSelectedItem(),\r
229                         measureSelecter.getStartMeasurePosition(),\r
230                         measureSelecter.getEndMeasurePosition(),\r
231                         firstTrackSpec,\r
232                         trackSpecPanel.getTrackSpecs()\r
233                 );\r
234         }\r
235         /**\r
236          * コード進行を設定します。テキスト欄に反映されます。\r
237          * @param cp コード進行\r
238          */\r
239         public void setChordProgression(ChordProgression cp) {\r
240                 chordText.setText(cp.toString());\r
241         }\r
242         /**\r
243          * テンポ・拍子・コード進行をランダムに設定\r
244          * @param measureLength 小節数\r
245          */\r
246         public void setRandomChordProgression(int measureLength) {\r
247                 tempoSelecter.setTempo( 80 + (int)(Math.random() * 100) );\r
248                 int timesig_upper = 4;\r
249                 int timesig_lower_index = 2;\r
250                 switch( (int)(Math.random() * 10) ) {\r
251                         case 0: timesig_upper = 3; break; // 3/4\r
252                 }\r
253                 timesigSelecter.setValue((byte)timesig_upper, (byte)timesig_lower_index);\r
254                 setChordProgression(new ChordProgression(measureLength, timesig_upper));\r
255         }\r
256         /**\r
257          * トラック設定画面\r
258          */\r
259         private static class TrackSpecPanel extends JPanel\r
260                 implements PianoKeyboardListener, ActionListener, ChangeListener\r
261         {\r
262                 JComboBox<AbstractNoteTrackSpec> trackSelecter = new JComboBox<>();\r
263                 JLabel trackTypeLabel = new JLabel();\r
264                 JTextField nameTextField = new JTextField(20);\r
265                 MidiChannelComboSelecter chSelecter =\r
266                         new MidiChannelComboSelecter("MIDI Channel:");\r
267                 MidiProgramSelecter pgSelecter = new MidiProgramSelecter();\r
268                 MidiProgramFamilySelecter pgFamilySelecter =\r
269                         new MidiProgramFamilySelecter(pgSelecter) {{\r
270                                 pgSelecter.setFamilySelecter(pgFamilySelecter);\r
271                         }};\r
272                 PianoKeyboardPanel keyboardPanel = new PianoKeyboardPanel() {{\r
273                         keyboard.octaveSizeModel.setValue(6);\r
274                         keyboard.setPreferredSize(new Dimension(400,40));\r
275                         keyboard.setMaxSelectable(2);\r
276                 }};\r
277                 JPanel rangePanel = new JPanel() {{\r
278                         add( new JLabel("Range:") );\r
279                         add(keyboardPanel);\r
280                 }};\r
281                 JCheckBox randomMelodyCheckbox = new JCheckBox("Random melody");\r
282                 JCheckBox bassCheckbox = new JCheckBox("Bass note");\r
283                 JCheckBox randomLyricCheckbox = new JCheckBox("Random lyrics");\r
284                 JCheckBox nsx39Checkbox = new JCheckBox("NSX-39");;\r
285                 BeatPadPanel beatPadPanel = new BeatPadPanel(this);\r
286                 private MidiChannel[] midiChannels;\r
287 \r
288                 public TrackSpecPanel() {\r
289                         nameTextField.addActionListener(this);\r
290                         keyboardPanel.keyboard.addPianoKeyboardListener(this);\r
291                         add(new JPanel() {{\r
292                                 add(new JLabel("Track select:"));\r
293                                 add(trackSelecter);\r
294                         }});\r
295                         add(trackTypeLabel);\r
296                         add(new JPanel() {{\r
297                                 add(new JLabel("Track name (Press [Enter] key to change):"));\r
298                                 add(nameTextField);\r
299                         }});\r
300                         add(chSelecter);\r
301                         add(new VelocitySelecter(keyboardPanel.keyboard.velocityModel));\r
302                         add(new JPanel() {{\r
303                                 add(pgFamilySelecter);\r
304                                 add(pgSelecter);\r
305                         }});\r
306                         add(rangePanel);\r
307                         bassCheckbox.addChangeListener(this);\r
308                         add(bassCheckbox);\r
309                         randomMelodyCheckbox.addChangeListener(this);\r
310                         add(randomMelodyCheckbox);\r
311                         randomLyricCheckbox.addChangeListener(this);\r
312                         add(randomLyricCheckbox);\r
313                         nsx39Checkbox.addChangeListener(this);\r
314                         add(nsx39Checkbox);\r
315                         add(beatPadPanel);\r
316                         trackSelecter.addActionListener(this);\r
317                         chSelecter.comboBox.addActionListener(this);\r
318                         keyboardPanel.keyboard.velocityModel.addChangeListener(\r
319                                 new ChangeListener() {\r
320                                         public void stateChanged(ChangeEvent e) {\r
321                                                 AbstractNoteTrackSpec ants = getTrackSpec();\r
322                                                 ants.velocity = keyboardPanel.keyboard.velocityModel.getValue();\r
323                                         }\r
324                                 }\r
325                         );\r
326                         pgSelecter.addActionListener(this);\r
327                 }\r
328                 @Override\r
329                 public void stateChanged(ChangeEvent e) {\r
330                         Object src = e.getSource();\r
331                         if( src == bassCheckbox ) {\r
332                                 AbstractNoteTrackSpec ants = getTrackSpec();\r
333                                 if( ants instanceof MelodyTrackSpec ) {\r
334                                         MelodyTrackSpec mts = (MelodyTrackSpec)ants;\r
335                                         mts.isBass = bassCheckbox.isSelected();\r
336                                 }\r
337                         }\r
338                         else if( src == randomMelodyCheckbox ) {\r
339                                 AbstractNoteTrackSpec ants = getTrackSpec();\r
340                                 if( ants instanceof MelodyTrackSpec ) {\r
341                                         MelodyTrackSpec mts = (MelodyTrackSpec)ants;\r
342                                         mts.randomMelody = randomMelodyCheckbox.isSelected();\r
343                                 }\r
344                         }\r
345                         else if( src == randomLyricCheckbox ) {\r
346                                 AbstractNoteTrackSpec ants = getTrackSpec();\r
347                                 if( ants instanceof MelodyTrackSpec ) {\r
348                                         MelodyTrackSpec mts = (MelodyTrackSpec)ants;\r
349                                         mts.randomLyric = randomLyricCheckbox.isSelected();\r
350                                 }\r
351                         }\r
352                         else if( src == nsx39Checkbox ) {\r
353                                 AbstractNoteTrackSpec ants = getTrackSpec();\r
354                                 if( ants instanceof MelodyTrackSpec ) {\r
355                                         MelodyTrackSpec mts = (MelodyTrackSpec)ants;\r
356                                         mts.nsx39 = nsx39Checkbox.isSelected();\r
357                                 }\r
358                         }\r
359                 }\r
360                 @Override\r
361                 public void actionPerformed(ActionEvent e) {\r
362                         Object src = e.getSource();\r
363                         AbstractNoteTrackSpec ants;\r
364                         if( src == nameTextField ) {\r
365                                 getTrackSpec().name = nameTextField.getText();\r
366                         }\r
367                         else if( src == trackSelecter ) {\r
368                                 ants = (AbstractNoteTrackSpec)(trackSelecter.getSelectedItem());\r
369                                 String trackTypeString = "Track type: " + (\r
370                                         ants instanceof DrumTrackSpec ? "Percussion" :\r
371                                         ants instanceof MelodyTrackSpec ? "Melody" : "(Unknown)"\r
372                                 );\r
373                                 trackTypeLabel.setText(trackTypeString);\r
374                                 nameTextField.setText(ants.name);\r
375                                 chSelecter.setSelectedChannel(ants.midiChannel);\r
376                                 keyboardPanel.keyboard.velocityModel.setValue(ants.velocity);\r
377                                 pgSelecter.setProgram(ants.programNumber);\r
378                                 keyboardPanel.keyboard.clear();\r
379                                 if( ants instanceof DrumTrackSpec ) {\r
380                                         rangePanel.setVisible(false);\r
381                                         randomMelodyCheckbox.setVisible(false);\r
382                                         randomLyricCheckbox.setVisible(false);\r
383                                         nsx39Checkbox.setVisible(false);\r
384                                         bassCheckbox.setVisible(false);\r
385                                 }\r
386                                 else if( ants instanceof MelodyTrackSpec ) {\r
387                                         MelodyTrackSpec ts = (MelodyTrackSpec)ants;\r
388                                         rangePanel.setVisible(true);\r
389                                         keyboardPanel.keyboard.setSelectedNote(ts.range.min_note);\r
390                                         keyboardPanel.keyboard.setSelectedNote(ts.range.max_note);\r
391                                         keyboardPanel.keyboard.autoScroll(ts.range.min_note);\r
392                                         randomMelodyCheckbox.setSelected(ts.randomMelody);\r
393                                         randomLyricCheckbox.setSelected(ts.randomLyric);\r
394                                         bassCheckbox.setSelected(ts.isBass);\r
395                                         randomMelodyCheckbox.setVisible(true);\r
396                                         randomLyricCheckbox.setVisible(true);\r
397                                         nsx39Checkbox.setVisible(true);\r
398                                         bassCheckbox.setVisible(true);\r
399                                 }\r
400                                 beatPadPanel.setTrackSpec(ants);\r
401                         }\r
402                         else if( src == chSelecter.comboBox ) {\r
403                                 getTrackSpec().midiChannel = chSelecter.getSelectedChannel();\r
404                         }\r
405                         else if( src == pgSelecter ) {\r
406                                 getTrackSpec().programNumber = pgSelecter.getProgram();\r
407                         }\r
408                 }\r
409                 @Override\r
410                 public void pianoKeyPressed(int n, InputEvent e) {\r
411                         noteOn(n);\r
412                         AbstractNoteTrackSpec ants = getTrackSpec();\r
413                         if( ants instanceof MelodyTrackSpec ) {\r
414                                 MelodyTrackSpec ts = (MelodyTrackSpec)ants;\r
415                                 ts.range = new Range(keyboardPanel.keyboard.getSelectedNotes());\r
416                         }\r
417                 }\r
418                 @Override\r
419                 public void pianoKeyReleased(int n, InputEvent e) { noteOff(n); }\r
420                 public void octaveMoved(ChangeEvent event) {}\r
421                 public void octaveResized(ChangeEvent event) {}\r
422                 public void noteOn(int n) {\r
423                         if( midiChannels == null ) return;\r
424                         MidiChannel mc = midiChannels[chSelecter.getSelectedChannel()];\r
425                         mc.noteOn( n, keyboardPanel.keyboard.velocityModel.getValue() );\r
426                 }\r
427                 public void noteOff(int n) {\r
428                         if( midiChannels == null ) return;\r
429                         MidiChannel mc = midiChannels[chSelecter.getSelectedChannel()];\r
430                         mc.noteOff( n, keyboardPanel.keyboard.velocityModel.getValue() );\r
431                 }\r
432                 public void setChannels( MidiChannel midiChannels[] ) {\r
433                         this.midiChannels = midiChannels;\r
434                 }\r
435                 public AbstractNoteTrackSpec getTrackSpec() {\r
436                         Object trackSpecObj = trackSelecter.getSelectedItem();\r
437                         AbstractNoteTrackSpec ants = (AbstractNoteTrackSpec)trackSpecObj;\r
438                         ants.name = nameTextField.getText();\r
439                         return ants;\r
440                 }\r
441                 public Vector<AbstractNoteTrackSpec> getTrackSpecs() {\r
442                         Vector<AbstractNoteTrackSpec> trackSpecs = new Vector<>();\r
443                         int i=0, n_items = trackSelecter.getItemCount();\r
444                         while( i < n_items ) {\r
445                                 trackSpecs.add((AbstractNoteTrackSpec)trackSelecter.getItemAt(i++));\r
446                         }\r
447                         return trackSpecs;\r
448                 }\r
449                 public void addTrackSpec(AbstractNoteTrackSpec trackSpec) {\r
450                         trackSelecter.addItem(trackSpec);\r
451                 }\r
452         }\r
453         private static class MeasureSelecter extends JPanel {\r
454                 public MeasureSelecter() {\r
455                         setLayout(new GridLayout(2,3));\r
456                         add(new JLabel());\r
457                         add(new JLabel("Start",JLabel.CENTER));\r
458                         add(new JLabel("End",JLabel.CENTER));\r
459                         add(new JLabel("Measure",JLabel.RIGHT));\r
460                         add(new JSpinner(startModel));\r
461                         add(new JSpinner(endModel));\r
462                 }\r
463                 private SpinnerNumberModel startModel = new SpinnerNumberModel( 3, 1, 9999, 1 );\r
464                 private SpinnerNumberModel endModel = new SpinnerNumberModel( 8, 1, 9999, 1 );\r
465                 public int getStartMeasurePosition() {\r
466                         return startModel.getNumber().intValue();\r
467                 }\r
468                 public int getEndMeasurePosition() {\r
469                         return endModel.getNumber().intValue();\r
470                 }\r
471                 public int getMeasureDuration() {\r
472                         return getEndMeasurePosition() - getStartMeasurePosition() + 1;\r
473                 }\r
474         }\r
475         //////////////////////////////////////////////////////////////////\r
476         //\r
477         // □=□=□=□=□=□=□=□=\r
478         // □=□=□=□=□=□=□=□=\r
479         //\r
480         private static class BeatPadPanel extends JPanel implements ActionListener {\r
481                 PianoKeyboardListener piano_keyboard_listener;\r
482                 JPanel percussion_selecters_panel;\r
483                 java.util.List<JComboBox<String>> percussionSelecters =\r
484                         new ArrayList<JComboBox<String>>() {\r
485                                 {\r
486                                         for( int i=0; i < DrumTrackSpec.defaultPercussions.length; i++  ) {\r
487                                                 add(new JComboBox<String>());\r
488                                         }\r
489                                 }\r
490                         };\r
491                 BeatPad beat_pad;\r
492 \r
493                 public BeatPadPanel(PianoKeyboardListener pkl) {\r
494                         piano_keyboard_listener = pkl;\r
495                         percussion_selecters_panel = new JPanel();\r
496                         percussion_selecters_panel.setLayout(\r
497                                 new BoxLayout( percussion_selecters_panel, BoxLayout.Y_AXIS )\r
498                         );\r
499                         for( JComboBox<String> cb : percussionSelecters ) {\r
500                                 percussion_selecters_panel.add(cb);\r
501                                 cb.addActionListener(this);\r
502                         }\r
503                         add( percussion_selecters_panel );\r
504                         add( beat_pad = new BeatPad(pkl) );\r
505                         beat_pad.setPreferredSize( new Dimension(400,200) );\r
506                         setLayout( new BoxLayout( this, BoxLayout.X_AXIS ) );\r
507                 }\r
508                 public void actionPerformed(ActionEvent e) {\r
509                         Object src = e.getSource();\r
510                         for( JComboBox<String> cb : percussionSelecters ) {\r
511                                 if( src != cb ) continue;\r
512                                 int note_no = (\r
513                                         (DrumTrackSpec.PercussionComboBoxModel)cb.getModel()\r
514                                 ).getSelectedNoteNo();\r
515                                 piano_keyboard_listener.pianoKeyPressed(note_no,(InputEvent)null);\r
516                         }\r
517                 }\r
518                 public void setTrackSpec( AbstractNoteTrackSpec ants ) {\r
519                         beat_pad.setTrackSpec(ants);\r
520                         if( ants instanceof DrumTrackSpec ) {\r
521                                 DrumTrackSpec dts = (DrumTrackSpec)ants;\r
522                                 int i=0;\r
523                                 for( JComboBox<String> cb : percussionSelecters ) {\r
524                                         cb.setModel(dts.models[i++]);\r
525                                 }\r
526                                 percussion_selecters_panel.setVisible(true);\r
527                         }\r
528                         else if( ants instanceof MelodyTrackSpec ) {\r
529                                 percussion_selecters_panel.setVisible(false);\r
530                         }\r
531                 }\r
532         }\r
533         private static class BeatPad extends JComponent implements MouseListener, ComponentListener {\r
534                 PianoKeyboardListener piano_keyboard_listener;\r
535                 private int on_note_no = -1;\r
536                 AbstractNoteTrackSpec track_spec;\r
537 \r
538                 public static final int MAX_BEATS = 16;\r
539                 Rectangle beat_buttons[][];\r
540                 Rectangle continuous_beat_buttons[][];\r
541 \r
542                 public BeatPad(PianoKeyboardListener pkl) {\r
543                         piano_keyboard_listener = pkl;\r
544                         addMouseListener(this);\r
545                         addComponentListener(this);\r
546                         // addMouseMotionListener(this);\r
547                 }\r
548                 public void paint(Graphics g) {\r
549                         super.paint(g);\r
550                         Graphics2D g2 = (Graphics2D) g;\r
551                         Rectangle r;\r
552                         int note, beat, mask;\r
553 \r
554                         if( track_spec instanceof DrumTrackSpec ) {\r
555                                 DrumTrackSpec dts = (DrumTrackSpec)track_spec;\r
556                                 for( note=0; note<dts.beat_patterns.length; note++ ) {\r
557                                         for( beat=0, mask=0x8000; beat<MAX_BEATS; beat++, mask >>>= 1 ) {\r
558                                                 r = beat_buttons[note][beat];\r
559                                                 if( (dts.beat_patterns[note] & mask) != 0 )\r
560                                                         g2.fillRect( r.x, r.y, r.width, r.height );\r
561                                                 else\r
562                                                         g2.drawRect( r.x, r.y, r.width, r.height );\r
563                                         }\r
564                                 }\r
565                         }\r
566                         else if( track_spec instanceof MelodyTrackSpec ) {\r
567                                 MelodyTrackSpec mts = (MelodyTrackSpec)track_spec;\r
568                                 for( beat=0, mask=0x8000; beat<MAX_BEATS; beat++, mask >>>= 1 ) {\r
569                                         r = beat_buttons[0][beat];\r
570                                         if( (mts.beatPattern & mask) != 0 )\r
571                                                 g2.fillRect( r.x, r.y, r.width, r.height );\r
572                                         else\r
573                                                 g2.drawRect( r.x, r.y, r.width, r.height );\r
574                                         r = continuous_beat_buttons[0][beat];\r
575                                         if( (mts.continuousBeatPattern & mask) != 0 )\r
576                                                 g2.fillRect( r.x, r.y, r.width, r.height );\r
577                                         else\r
578                                                 g2.drawRect( r.x, r.y, r.width, r.height );\r
579                                 }\r
580                         }\r
581 \r
582                 }\r
583                 public void componentShown(ComponentEvent e) { }\r
584                 public void componentHidden(ComponentEvent e) { }\r
585                 public void componentMoved(ComponentEvent e) { }\r
586                 public void componentResized(ComponentEvent e) {\r
587                         sizeChanged();\r
588                 }\r
589                 public void mousePressed(MouseEvent e) {\r
590                         catchEvent(e);\r
591                         if( on_note_no >= 0 ) {\r
592                                 piano_keyboard_listener.pianoKeyPressed( on_note_no ,(InputEvent)e );\r
593                         }\r
594                 }\r
595                 public void mouseReleased(MouseEvent e) {\r
596                         if( on_note_no >= 0 ) {\r
597                                 piano_keyboard_listener.pianoKeyReleased( on_note_no ,(InputEvent)e );\r
598                         }\r
599                         on_note_no = -1;\r
600                 }\r
601                 public void mouseEntered(MouseEvent e) {\r
602                         if((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {\r
603                                 catchEvent(e);\r
604                         }\r
605                 }\r
606                 public void mouseExited(MouseEvent e) { }\r
607                 public void mouseClicked(MouseEvent e) { }\r
608                 private void sizeChanged() {\r
609                         int beat, note, width, height;\r
610                         Dimension d = getSize();\r
611                         int num_notes = 1;\r
612                         if( track_spec instanceof DrumTrackSpec ) {\r
613                                 DrumTrackSpec dts = (DrumTrackSpec)track_spec;\r
614                                 num_notes = dts.models.length;\r
615                         }\r
616                         beat_buttons = new Rectangle[num_notes][];\r
617                         continuous_beat_buttons = new Rectangle[num_notes][];\r
618                         for( note=0; note<beat_buttons.length; note++ ) {\r
619                                 beat_buttons[note] = new Rectangle[MAX_BEATS];\r
620                                 continuous_beat_buttons[note] = new Rectangle[MAX_BEATS];\r
621                                 for( beat=0; beat<MAX_BEATS; beat++ ) {\r
622                                         width = (d.width * 3) / (MAX_BEATS * 4);\r
623                                         height = d.height / num_notes - 1;\r
624                                         beat_buttons[note][beat] = new Rectangle(\r
625                                                 beat * d.width / MAX_BEATS,\r
626                                                 note * height,\r
627                                                 width,\r
628                                                 height\r
629                                         );\r
630                                         width = d.width / (MAX_BEATS * 3);\r
631                                         continuous_beat_buttons[note][beat] = new Rectangle(\r
632                                                 (beat+1) * d.width / MAX_BEATS - width + 1,\r
633                                                 note * height + height / 3,\r
634                                                 width-1,\r
635                                                 height / 3\r
636                                         );\r
637                                 }\r
638                         }\r
639                 }\r
640                 private void catchEvent(MouseEvent e) {\r
641                         Point point = e.getPoint();\r
642                         int note, beat, mask;\r
643 \r
644                         // ビートパターンのビットを反転\r
645                         if( track_spec instanceof DrumTrackSpec ) {\r
646                                 DrumTrackSpec dts = (DrumTrackSpec)track_spec;\r
647                                 for( note=0; note<dts.beat_patterns.length; note++ ) {\r
648                                         for( beat=0, mask=0x8000; beat<MAX_BEATS; beat++, mask >>>= 1 ) {\r
649                                                 if( beat_buttons[note][beat].contains(point) ) {\r
650                                                         dts.beat_patterns[note] ^= mask;\r
651                                                         on_note_no = dts.models[note].getSelectedNoteNo();\r
652                                                         repaint(); return;\r
653                                                 }\r
654                                         }\r
655                                 }\r
656                         }\r
657                         else if( track_spec instanceof MelodyTrackSpec ) {\r
658                                 MelodyTrackSpec mts = (MelodyTrackSpec)track_spec;\r
659                                 for( beat=0, mask=0x8000; beat<MAX_BEATS; beat++, mask >>>= 1 ) {\r
660                                         if( beat_buttons[0][beat].contains(point) ) {\r
661                                                 mts.beatPattern ^= mask;\r
662                                                 repaint(); return;\r
663                                         }\r
664                                         if( continuous_beat_buttons[0][beat].contains(point) ) {\r
665                                                 mts.continuousBeatPattern ^= mask;\r
666                                                 repaint(); return;\r
667                                         }\r
668                                 }\r
669                         }\r
670                 }\r
671                 public void setTrackSpec( AbstractNoteTrackSpec ants ) {\r
672                         track_spec = ants;\r
673                         sizeChanged();\r
674                         repaint();\r
675                 }\r
676         }\r
677 }\r