OSDN Git Service

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