1 |
/* |
2 |
* JSampler - a java front-end for LinuxSampler |
3 |
* |
4 |
* Copyright (C) 2005-2008 Grigor Iliev <grigor@grigoriliev.com> |
5 |
* |
6 |
* This file is part of JSampler. |
7 |
* |
8 |
* JSampler is free software; you can redistribute it and/or modify |
9 |
* it under the terms of the GNU General Public License version 2 |
10 |
* as published by the Free Software Foundation. |
11 |
* |
12 |
* JSampler is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with JSampler; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
20 |
* MA 02111-1307 USA |
21 |
*/ |
22 |
|
23 |
package org.jsampler.view.std; |
24 |
|
25 |
import java.awt.Font; |
26 |
import java.awt.FontMetrics; |
27 |
import java.awt.Color; |
28 |
import java.awt.Font; |
29 |
import java.awt.FontMetrics; |
30 |
import java.awt.GradientPaint; |
31 |
import java.awt.Graphics2D; |
32 |
import java.awt.Point; |
33 |
import java.awt.Rectangle; |
34 |
import java.awt.RenderingHints; |
35 |
|
36 |
import java.awt.geom.RoundRectangle2D; |
37 |
|
38 |
/** |
39 |
* |
40 |
* @author Grigor Iliev |
41 |
*/ |
42 |
public class BasicPianoRollPainter implements PianoRollPainter { |
43 |
private PianoRoll pianoRoll; |
44 |
|
45 |
private Color borderColor = Color.BLACK; |
46 |
private Color keyColor = Color.WHITE; |
47 |
private Color disabledKeyColor = new Color(0xaaaaaa); |
48 |
private Color pressedKeyColor = Color.GREEN; |
49 |
private Color keySwitchColor = Color.PINK; |
50 |
private Color blackKeyColor = Color.BLACK; |
51 |
|
52 |
public |
53 |
BasicPianoRollPainter(PianoRoll pianoRoll) { |
54 |
if(pianoRoll == null) { |
55 |
throw new IllegalArgumentException("piano roll must be non-null"); |
56 |
} |
57 |
this.pianoRoll = pianoRoll; |
58 |
} |
59 |
|
60 |
@Override |
61 |
public void |
62 |
paint(PianoRoll pianoRoll, Graphics2D g) { |
63 |
double whiteKeyWidth = getWhiteKeyWidth(); |
64 |
double whiteKeyHeight = getWhiteKeyHeight(); |
65 |
double arcw = whiteKeyWidth/4.0d; |
66 |
double arch = whiteKeyHeight/14.0d; |
67 |
|
68 |
g.setPaint(keyColor); |
69 |
|
70 |
RoundRectangle2D.Double rect; |
71 |
|
72 |
g.setRenderingHint ( |
73 |
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF |
74 |
); |
75 |
|
76 |
int i = 0; |
77 |
for(int j = pianoRoll.getFirstKey(); j <= pianoRoll.getLastKey(); j++) { |
78 |
if(!PianoRoll.isWhiteKey(j)) continue; |
79 |
|
80 |
Color c = getKeyColor(j); |
81 |
if(g.getPaint() != c) g.setPaint(c); |
82 |
|
83 |
rect = new RoundRectangle2D.Double ( |
84 |
// If you change this you should also change getKeyRectangle() |
85 |
whiteKeyWidth * i + i, 0, |
86 |
whiteKeyWidth, whiteKeyHeight, |
87 |
arcw, arch |
88 |
); |
89 |
|
90 |
g.fill(rect); |
91 |
i++; |
92 |
} |
93 |
|
94 |
g.setRenderingHint ( |
95 |
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON |
96 |
); |
97 |
|
98 |
g.setStroke(new java.awt.BasicStroke(1.5f)); |
99 |
g.setPaint(borderColor); |
100 |
|
101 |
i = 0; |
102 |
for(int j = pianoRoll.getFirstKey(); j <= pianoRoll.getLastKey(); j++) { |
103 |
if(!PianoRoll.isWhiteKey(j)) continue; |
104 |
|
105 |
rect = new RoundRectangle2D.Double ( |
106 |
whiteKeyWidth * i + i, 0, |
107 |
whiteKeyWidth, whiteKeyHeight, |
108 |
arcw, arch |
109 |
); |
110 |
|
111 |
g.draw(rect); |
112 |
i++; |
113 |
} |
114 |
|
115 |
|
116 |
g.setStroke(new java.awt.BasicStroke(2.5f)); |
117 |
double blackKeyWidth = getBlackKeyWidth(); |
118 |
double blackKeyHeight = getBlackKeyHeight(); |
119 |
|
120 |
i = 0; |
121 |
for(int j = pianoRoll.getFirstKey(); j <= pianoRoll.getLastKey(); j++) { |
122 |
if(pianoRoll.getOctaveLabelsVisible() && j % 12 == 0) { |
123 |
int octave = j / 12 - 2; |
124 |
paintOctaveLabel(g, octave, i); |
125 |
} |
126 |
if(!PianoRoll.isWhiteKey(j)) continue; |
127 |
|
128 |
int k = (i + PianoRoll.getKeyOctaveIndex(pianoRoll.getFirstKey())) % 7; |
129 |
if(k == 2 || k == 6) { i++; continue; } |
130 |
|
131 |
Color c = (j == pianoRoll.getLastKey()) ? blackKeyColor : getKeyColor(j + 1); |
132 |
if(g.getPaint() != c) g.setPaint(c); |
133 |
|
134 |
// If you change this you should also change getKeyRectangle() |
135 |
double x = blackKeyWidth * (2*(i + 1)) - blackKeyWidth * 0.5d + i; |
136 |
rect = new RoundRectangle2D.Double ( |
137 |
// If you change this you should also change getKeyRectangle() |
138 |
x, 0, |
139 |
blackKeyWidth, blackKeyHeight, |
140 |
arcw, arch |
141 |
); |
142 |
/////// |
143 |
|
144 |
boolean pressed = (j == pianoRoll.getLastKey()) ? false : pianoRoll.getKey(j + 1).isPressed(); |
145 |
if(!pressed) g.fill(rect); |
146 |
|
147 |
RoundRectangle2D.Double rect2; |
148 |
rect2 = new RoundRectangle2D.Double ( |
149 |
x, 0, |
150 |
blackKeyWidth, arch, |
151 |
arcw, arch / 1.8d |
152 |
); |
153 |
|
154 |
g.fill(rect2); |
155 |
g.setPaint(borderColor); |
156 |
g.draw(rect); |
157 |
|
158 |
if(pressed) { |
159 |
GradientPaint gr = new GradientPaint ( |
160 |
(float)(x + blackKeyWidth/2), (float)(blackKeyHeight/4), Color.BLACK, |
161 |
(float)(x + blackKeyWidth/2), (float)blackKeyHeight, new Color(0x058a02) |
162 |
); |
163 |
g.setPaint(gr); |
164 |
g.fill(rect); |
165 |
} |
166 |
i++; |
167 |
} |
168 |
} |
169 |
|
170 |
protected void |
171 |
paintOctaveLabel(Graphics2D g, int octave, int whiteKeyIndex) { |
172 |
double h = pianoRoll.getSize().getHeight(); |
173 |
double whiteKeyWidth = getWhiteKeyWidth(); |
174 |
g.setPaint(Color.BLACK); |
175 |
int fsize = (int) (whiteKeyWidth / (1.5 + whiteKeyWidth / 50)); |
176 |
if(fsize < 8) fsize = 8; |
177 |
g.setFont(g.getFont().deriveFont(Font.BOLD, fsize)); |
178 |
|
179 |
float x = (float) (whiteKeyWidth * whiteKeyIndex + whiteKeyIndex); |
180 |
float y = (float) (h - 1); |
181 |
|
182 |
String s = String.valueOf(octave); |
183 |
FontMetrics fm = g.getFontMetrics(); |
184 |
|
185 |
// center text |
186 |
int i = fm.stringWidth(s); |
187 |
if(i < whiteKeyWidth) { |
188 |
x += (whiteKeyWidth - i) / 2; |
189 |
} else { |
190 |
x += 2; |
191 |
} |
192 |
|
193 |
y -= (h / 12); |
194 |
|
195 |
g.drawString(s, x, y); |
196 |
} |
197 |
|
198 |
private Color |
199 |
getKeyColor(int key) { |
200 |
PianoRoll.Key k = pianoRoll.getKey(key); |
201 |
if(PianoRoll.isWhiteKey(key)) { |
202 |
if(k.isPressed()) return pressedKeyColor; |
203 |
if(k.isKeyswitch()) return keySwitchColor; |
204 |
if(k.isDisabled()) return disabledKeyColor; |
205 |
return keyColor; |
206 |
} else { |
207 |
if(k.isPressed()) return Color.GREEN; |
208 |
return blackKeyColor; |
209 |
} |
210 |
} |
211 |
|
212 |
|
213 |
private double |
214 |
getWhiteKeyWidth() { |
215 |
double w = pianoRoll.getSize().getWidth(); |
216 |
return (w - pianoRoll.getWhiteKeyCount()) / pianoRoll.getWhiteKeyCount(); |
217 |
} |
218 |
|
219 |
private double |
220 |
getWhiteKeyHeight() { |
221 |
return pianoRoll.getSize().getHeight() - 3.0d; |
222 |
} |
223 |
|
224 |
private double |
225 |
getBlackKeyWidth() { |
226 |
return getWhiteKeyWidth() / 2.0d; |
227 |
} |
228 |
|
229 |
private double |
230 |
getBlackKeyHeight() { |
231 |
return getWhiteKeyHeight() / 1.5d; |
232 |
} |
233 |
|
234 |
/** |
235 |
* Gets the index of the key containing the specified point. |
236 |
* @return Number between 0 and 127 (inclusive) as specified in the MIDI standard. |
237 |
*/ |
238 |
@Override |
239 |
public int |
240 |
getKeyByPoint(Point p) { |
241 |
double w = getWhiteKeyWidth() + /* space between keys */ 1.0d; |
242 |
if(w == 0) return -1; |
243 |
int whiteKeyNumber = (int) (p.getX() / w); |
244 |
double leftBorder = whiteKeyNumber * w; |
245 |
int key = pianoRoll.getWhiteKeyByNumber(whiteKeyNumber); |
246 |
if(key == -1) return -1; |
247 |
|
248 |
double bh = getBlackKeyHeight(); |
249 |
double blackKeyOffset = w / 4.0d; |
250 |
if(p.getY() > bh) return key; |
251 |
if(key != pianoRoll.getFirstKey() && !PianoRoll.isWhiteKey(key - 1)) { |
252 |
if(p.getX() <= leftBorder + blackKeyOffset) return key - 1; |
253 |
} |
254 |
if(key != pianoRoll.getLastKey() && !PianoRoll.isWhiteKey(key + 1)) { |
255 |
if(p.getX() >= leftBorder + 3 * blackKeyOffset - 3) return key + 1; |
256 |
} |
257 |
|
258 |
return key; |
259 |
} |
260 |
|
261 |
@Override |
262 |
public Rectangle |
263 |
getKeyRectangle(int key) { |
264 |
Rectangle r = new Rectangle(); |
265 |
if(!pianoRoll.hasKey(key)) return r; |
266 |
|
267 |
int whiteKeyIndex = PianoRoll.getWhiteKeyCount(pianoRoll.getFirstKey(), key) - 1; |
268 |
|
269 |
if(PianoRoll.isWhiteKey(key)) { |
270 |
double whiteKeyWidth = getWhiteKeyWidth(); |
271 |
double whiteKeyHeight = getWhiteKeyHeight(); |
272 |
double x = whiteKeyWidth * whiteKeyIndex + whiteKeyIndex; |
273 |
r.setRect(x, 0, whiteKeyWidth, whiteKeyHeight); |
274 |
} else { |
275 |
double blackKeyWidth = getBlackKeyWidth(); |
276 |
double blackKeyHeight = getBlackKeyHeight(); |
277 |
int i = whiteKeyIndex; |
278 |
double x = blackKeyWidth * (2*(i + 1)) - blackKeyWidth * 0.5d + i; |
279 |
r.setRect(x, 0, blackKeyWidth, blackKeyHeight); |
280 |
} |
281 |
|
282 |
return r; |
283 |
} |
284 |
|
285 |
@Override |
286 |
public int |
287 |
getVelocity(Point p, int key) { |
288 |
boolean whiteKey = PianoRoll.isWhiteKey(key); |
289 |
double h = whiteKey ? getWhiteKeyHeight() : getBlackKeyHeight(); |
290 |
int velocity = (int) ((p.getY() / h) * 127.0d + 1); |
291 |
if(velocity < 0) velocity = 0; |
292 |
if(velocity > 127) velocity = 127; |
293 |
return velocity; |
294 |
} |
295 |
} |