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