OSDN Git Service

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