/*
* Copyright (C) 2013-2017 たんらる
*/
package fourthline.mabiicco.ui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JPanel;
import fourthline.mabiicco.midi.IPlayNote;
import fourthline.mabiicco.midi.MabiDLS;
import fourthline.mmlTools.MMLNoteEvent;
public final class KeyboardView extends JPanel implements IPlayNote {
private static final long serialVersionUID = -3850112420986284800L;
private int playNote[] = null;
private final int width = 60;
private final int PLAY_CHANNEL = 15;
private final int DEFAULT_VELOCITY = 11;
private final IMMLManager mmlManager;
private final PianoRollView pianoRollView;
/**
* Create the panel.
* @param manager 関連付けるIMMLManager
* @param pianoRollView 関連付けるPianoRollView
*/
public KeyboardView(IMMLManager manager, final PianoRollView pianoRollView) {
this.mmlManager = manager;
this.pianoRollView = pianoRollView;
updateHeight();
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int note = pianoRollView.convertY2Note( e.getY() );
playNote( note, DEFAULT_VELOCITY );
}
@Override
public void mouseReleased(MouseEvent e) {
offNote();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
int note = pianoRollView.convertY2Note( e.getY() );
playNote( note, DEFAULT_VELOCITY );
}
});
}
public void updateHeight() {
setPreferredSize(new Dimension(width, pianoRollView.getTotalHeight()));
}
/**
* 1オクターブ 12 x 6
* 9オクターブ分つくると、648
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
int height = pianoRollView.getTotalHeight()-1;
Graphics2D g2 = (Graphics2D)g.create();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, width, height);
for (int i = 0; i <= PianoRollView.OCTNUM; i++) {
paintOctPianoLine(g2, i, (char)('0'+PianoRollView.OCTNUM-i-1));
}
g2.setColor(Color.BLUE);
g2.drawLine(width-1, 0, width-1, height);
paintPlayNote(g2);
g2.dispose();
}
private boolean isWhiteKey(int note) {
switch (note%12) {
case 0:
case 2:
case 4:
case 5:
case 7:
case 9:
case 11:
case -1:
return true;
default:
return false;
}
}
private void paintPlayNote(Graphics2D g) {
int yAdd[] = { -2, -2, -1, -2, 1, -3, -2, -2, -1, 0, 0, 2 }; // 補正値
if (playNote == null) {
return;
}
for (int i = 0; i < playNote.length; i++) {
int x = 15;
int note = playNote[i];
if ( isWhiteKey(note) ) {
x += 20;
}
int y = pianoRollView.convertNote2Y(note) + yAdd[(note+12)%12];
g.setColor(Color.RED);
g.fillOval(x, y, 4, 4);
}
}
private void paintOctPianoLine(Graphics2D g, int pos, char posText) {
int octHeight = pianoRollView.getNoteHeight() * 12;
// ド~シのしろ鍵盤
g.setColor(new Color(0.3f, 0.3f, 0.3f));
int startY = octHeight * pos;
for (int i = 0; i < 7; i++) {
double y1 = octHeight * i / 7;
double y2 = octHeight * (i+1) / 7;
g.drawRect(0, (int)(startY+y1), 40, (int)(y2-y1));
}
// 黒鍵盤
int black_posIndex[] = {
1, // A#
2, // G#
3, // F#
5, // D#
6 // C#
};
for (int i = 0; i < black_posIndex.length; i++) {
int y = octHeight * black_posIndex[i] / 7 - pianoRollView.getNoteHeight() / 2-1;
y += startY;
g.setColor(new Color(0.0f, 0.0f, 0.0f));
g.fillRect(0, y, 20, pianoRollView.getNoteHeight());
g.setColor(new Color(0.3f, 0.3f, 0.3f));
g.drawRect(0, y, 20, pianoRollView.getNoteHeight());
}
// グリッド
g.setColor(new Color(0.3f, 0.3f, 0.6f));
g.drawLine(40, startY, width, startY);
// オクターブ
char o_char[] = { 'o', posText };
g.setFont(new Font("Arial", Font.PLAIN, 12));
int y = startY + octHeight;
g.drawChars(o_char, 0, o_char.length, 42, y);
g.drawLine(40, y, width, y);
}
@Override
public void playNote(int note, int velocity) {
if (note < -1) {
offNote();
return;
}
playNote(new int[]{ note }, velocity);
}
@Override
public void playNote(int note[], int velocity) {
if (note == null) {
offNote();
return;
}
playNote = note;
MMLNoteEvent noteEvent[] = new MMLNoteEvent[note.length];
for (int i = 0; i < note.length; i++) {
noteEvent[i] = new MMLNoteEvent(note[i], 0, 0, velocity);
}
MabiDLS dls = MabiDLS.getInstance();
if (!dls.getSequencer().isRunning()) {
int program = mmlManager.getActivePartProgram();
dls.loadRequiredInstruments(mmlManager.getMMLScore());
dls.playNotes(noteEvent, program, PLAY_CHANNEL);
}
repaint();
}
@Override
public void offNote() {
playNote = null;
int program = mmlManager.getActivePartProgram();
MabiDLS.getInstance().playNote(Integer.MIN_VALUE, program, PLAY_CHANNEL, 0);
repaint();
}
}