//
import synth.*;
import java.awt.*;
public class Guitar2 extends BufferedApplet
{
// PUBLIC METHODS
public void render(Graphics g) {
if (w == 0) {
w = bounds().width;
h = bounds().height;
initColors();
synth.setInstrument(0, "Nylon Str Guitar");
}
g.setColor(Color.black);
g.fillRect(0,0,w,h);
g.setColor(scrimColor);
int ax = X(0)-25, bx = ax+7, cx = bx+7;
int ay = Y(st), by = ay+3, cy = by+4;
g.drawLine(ax,by,cx,by);
g.drawLine(bx,ay,cx,by);
g.drawLine(bx,cy,cx,by);
for (int s = 0 ; s < 6 ; s++) {
int y = Y(s);
for (int f = 0 ; f < 16 ; f++) {
int x = X(f);
int n = pitch[s] + f + 7;
g.setColor(colors[n % colors.length]);
g.fillRect(x, y, 32, 7);
if (mode == 1 && n % 12 == (ci+3) % 12) {
g.setColor(Color.white);
g.fillRect(x, y+7, 32, 1);
}
g.setColor(scrimColor);
String str = notes[n % 12];
g.drawString(str, x + 15 - 3 * str.length(), y - 4);
}
g.setColor(colors[(pitch[s] + fret[s] + 7) % colors.length]);
int grow = pp[s] > 0 ? 2 : 0;
g.fillRect(X(17), y+1-grow, X(20) - X(14), 5+2*grow);
g.setColor(scrimColor);
if (fret[s] > 0)
g.fillOval(X(fret[s]) - 17, y-5, 17, 17);
}
// DRAW THE CHORD FORMS
for (int i = 0 ; i < chords.chord.length ; i++) {
Color chordColor = i == mouseChord ? Color.white : scrimColor;
int x = CX(i);
int y = CY(i);
String name = chordName(chords.chord[i]);
String str = chordValue(chords.chord[i]);
g.setColor(chordColor);
for (int f = 0 ; f < 6 ; f++)
g.fillRect(x + 5 * f, y, 1, 25);
for (int s = 0 ; s < 6 ; s++) {
int ys = y + 5 * s;
g.setColor(chordColor);
g.fillRect(x, ys, 25, 1);
int ch = str.charAt(s);
if (ch == '-') {
g.drawLine(x - 6, ys - 2, x - 2, ys + 2);
g.drawLine(x - 6, ys + 2, x - 2, ys - 2);
}
else {
g.setColor(Color.white);
int fret = str.charAt(s) - '0';
if (fret > 0)
g.fillRect(x + 5 * fret - 1, ys - 1, 3, 3);
}
}
g.setColor(chordColor);
g.drawString(name, x + 12 - 4*name.length(), y + 40);
}
}
public boolean keyDown(Event e, int key) {
if (key >= '1' && key <= '6') {
playNote(key - '1');
return true;
}
if (key == 'm' || key == '7') {
String s = chordName(chords.chord[lastChord]) + (char)key;
if (setChord(s))
return true;
}
if (key >= 'A' && key <= 'G')
key += 'a' - 'A';
if (key >= 'a' && key <= 'g') {
String s = "" + (char)(key + 'A' - 'a');
if (setChord(s))
return true;
}
switch (key) {
case '\n':
String str = chordValue(chords.chord[lastChord]);
for (int s = 0 ; s < 6 ; s++)
if (str.charAt(s) != '-')
playNote(s);
break;
case ' ':
spaceBarIsDown = true;
break;
}
return true;
}
public boolean keyUp(Event e, int key) {
if (key >= '1' && key <= '6') {
liftNote(key - '1');
return true;
}
if (key >= 'A' || key <= 'G' || key >= 'a' || key <= 'g' || key == 'm' || key == '7')
mouseChord = -1;
switch (key) {
case '\n':
for (int s = 0 ; s < 6 ; s++)
liftNote(s);
break;
case ' ':
spaceBarIsDown = false;
break;
case 'x':
mode = (mode + 1) % 2;
damage = true;
break;
case 'z':
writeChords();
damage = true;
break;
case 1004: // UP
if (mode == 0)
st = Math.max(st-1, 0);
else
changeColorShift(0.1);
break;
case 1005: // DOWN
if (mode == 0)
st = Math.min(st+1, 5);
else
changeColorShift(-0.1);
break;
case 1006: // LEFT
if (mode == 0)
if (spaceBarIsDown)
for (int s = 0 ; s < 6 ; s++)
fret[s] = Math.max(0, fret[s]-1);
else
fret[st] = Math.max(0, fret[st]-1);
else
ci = (ci + 11) % 12;
break;
case 1007: // RIGHT
if (mode == 0)
if (spaceBarIsDown)
for (int s = 0 ; s < 6 ; s++)
fret[s] = Math.min(15, fret[s]+1);
else
fret[st] = Math.min(15, fret[st]+1);
else
ci = (ci + 1) % 12;
break;
}
damage = true;
return true;
}
public boolean mouseDown(Event e, int x, int y) {
plucking = F(x) >= 17;
mx = x;
my = y;
if (! plucking)
if (settingChord = F(y) >= 6)
setChord(mouseChord = findChord(x, y));
else if (spaceBarIsDown)
makeBar(x, y);
else
touchFret(x, y);
damage = true;
return true;
}
public boolean mouseDrag(Event e, int x, int y) {
if (settingChord)
setChord(mouseChord = findChord(x, y));
else if (plucking) {
int s0 = S(my), s1 = S(y);
if (x >= X(17) && Math.abs(s0 - s1) == 1) {
playNote(Math.max(s0,s1));
my = y;
}
}
else if (spaceBarIsDown)
makeBar(x, y);
else
touchFret(x, y);
damage = true;
return true;
}
public boolean mouseUp(Event e, int x, int y) {
if (settingChord) {
settingChord = false;
setChord(mouseChord);
mouseChord = -1;
}
else
for (int s = 0 ; s < 6 ; s++)
liftNote(s);
sp = -1;
damage = true;
return true;
}
// PRIVATE METHODS
private void initColors() {
for (int i = 0 ; i < colors.length ; i++) {
int j = (i+9) % 12;
double d = colorShift.shift[j];
hsv[0] = ((j+d) / 12.0) % 1.0;
ColorSpace.hsv2rgb(hsv, rgb);
double t = (double)i / colors.length;
for (int c = 0 ; c < 3 ; c++)
rgb[c] = t < 0.5 ? lerp(.1 + 1.6 * t, 0, rgb[c])
: lerp(1.6 * (t - .5), rgb[c], 1);
float r = Math.max(0,Math.min(1,(float)rgb[0]));
float g = Math.max(0,Math.min(1,(float)rgb[1]));
float b = Math.max(0,Math.min(1,(float)rgb[2]));
colors[i] = new Color(r,g,b);
}
}
private int Y(int s) { return 32 * (s + 1); }
private int X(int f) { return 32 * (f + 1); }
private int S(int y) { return Math.max(-1, Math.min(5, y / 32 - 1)); }
private int F(int x) { return Math.max(-1, x / 32 - 1); }
private int CX(int i) { return 34 + 37 * (i % (chords.chord.length/2)); }
private int CY(int i) { return Y(6) + 4 + i / (chords.chord.length/2) * 60; }
private String chordName(String s) { return s.substring(0,s.indexOf(":")); }
private String chordValue(String s) { return s.substring(s.indexOf(":")+1,s.length()); }
private void writeChords() {
classWriter.begin("Chords");
classWriter.write("chord", chords.chord);
classWriter.end();
}
private boolean setChord(String s) {
for (int i = 0 ; i < chords.chord.length ; i++)
if (chordName(chords.chord[i]).equals(s)) {
setChord(i);
mouseChord = i;
return true;
}
return false;
}
private void changeColorShift(double d) {
if (mode != 1)
return;
colorShift.shift[ci] += d;
colorShift.shift[ci] = (int)(10 * (colorShift.shift[ci] + 100) - 1000) / 10.0;
classWriter.begin("ColorShift");
classWriter.write("shift", colorShift.shift);
classWriter.end();
initColors();
damage = true;
for (int i = 0 ; i < 12 ; i++)
System.err.print(colorShift.shift[i] + (i==ci? "* " : " "));
System.err.println();
}
private void playNote(int s) {
sp = Math.max(0, s);
synth.noteOff(0,pp[sp],0);
pp[sp] = 32 + pitch[sp] + fret[sp] + 7;
synth.noteOn(0,pp[sp],63);
damage = true;
}
private void liftNote(int s) {
synth.noteOff(0,pp[s],0);
pp[s] = 0;
damage = true;
}
private void makeBar(int x, int y) {
int s = Math.max(0, S(y + 7));
int fmin = 15;
for (int i = 0 ; i <= s ; i++)
fmin = Math.min(fmin, fret[i]);
for (int i = 0 ; i <= s ; i++)
fret[i] = Math.min(14, fret[i] + F(x) + 1 - fmin);
damage = true;
}
private void touchFret(int x, int y) {
int s = Math.max(0, Math.min(5, S(y + 16)));
fret[s] = Math.min(15, F(x) + 1);
damage = true;
}
private int findChord(int x, int y) {
for (int i = 0 ; i < chords.chord.length ; i++)
if (x >= CX(i) && y >= CY(i) && x < CX(i) + 36 && y < CY(i) + 36)
return i;
return -1;
}
private void setChord(int i) {
if (i < 0)
return;
lastChord = i;
String str = chordValue(chords.chord[i]);
for (int s = 0 ; s < 6 ; s++)
fret[s] = str.charAt(s) - '0';
damage = true;
}
private double lerp(double t, double a, double b) { return a + t * (b - a); }
// PRIVATE DATA
private int w = 0, h = 0, mode = 0, st = 0;
private int pitch[] = {24, 19, 15, 10, 5, 0};
private int fret[] = {0,0,1,2,2,0};
private double rgb[] = {0,0,0}, hsv[] = {0,1,1};
private String notes[] = {"A","Bb","B","C","C#","D","Eb","E","F","F#","G","G#"};
private Color colors[] = new Color[49];
private Color scrimColor = new Color(255,255,255,128);
private MidiSynth synth = new MidiSynth();
private ColorShift colorShift = new ColorShift();
private boolean plucking = false;
private boolean settingChord = false;
private boolean spaceBarIsDown = false;
private int pp[] = new int[6], sp = -1, mx = 0, my = 0;
private Chords chords = new Chords();
private ClassWriter classWriter = new ClassWriter();
private int ci = 0;
private int mouseChord = -1;
private int lastChord = 0;
}