/* * Created on 16.4.2007 * * Copyright (c) 2006-2007 Karl Helgason * * http://www.frinika.com * * This file is part of Frinika. * * Frinika is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Frinika is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Frinika; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.frinika.notation; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.FontFormatException; import java.awt.Graphics2D; import java.awt.Stroke; import java.awt.geom.CubicCurve2D; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.TreeMap; public class NotationGraphics { public class Note { public float x = 0.0f; public int note = 0; public int dur = 0; public int linedir = 0; public int dotted = 0; public int accidental = 0; public int mark = 0; public Color color = null; public Note() { } public Note(int note, int dur) { this.x = cx; this.note = note; this.dur = dur; } public Note(int note, int dur, int dotted) { this.x = cx; this.note = note; this.dur = dur; this.dotted = dotted; } public Note(int note, int dur, int dotted, int accidental) { this.x = cx; this.note = note; this.dur = dur; this.dotted = dotted; this.accidental = accidental; } public Note(int note, int dur, int dotted, int accidental, int mark) { this.x = cx; this.note = note; this.dur = dur; this.dotted = dotted; this.accidental = accidental; this.mark = mark; } public Note(int note, int dur, int dotted, int accidental, int mark, int linedir) { this.x = cx; this.note = note; this.dur = dur; this.linedir = linedir; this.dotted = dotted; this.accidental = accidental; this.mark = mark; } } public final static int CLEF_F = -7; public final static int CLEF_C = 0; public final static int CLEF_G = 7; public final static int CLEF_NEUTRAL = 128; public final static int CLEF_TAB = 129; public final static int ACCIDENTAL_NATURAL = 32768; public final static int ACCIDENTAL_DOUBLE_SHARP = 200; public final static int ACCIDENTAL_SHARP_AND_A_HALF = 150; public final static int ACCIDENTAL_SHARP = 100; public final static int ACCIDENTAL_DEMISHARP = 50; public final static int ACCIDENTAL_DEMIFLAT = -50; public final static int ACCIDENTAL_FLAT = -100; public final static int ACCIDENTAL_FLAT_AND_A_HALF = -150; public final static int ACCIDENTAL_DOUBLE_FLAT = -200; // NOT IMPLEMTED YET! public final static int ARTICULATION_MARK_STACCATO = 0xE153; public final static int ARTICULATION_MARK_ACCENT = 0xE151; public final static int ARTICULATION_MARK_STOPPED_NOTE = 0xE153; public final static int ARTICULATION_MARK_OPEN_NOTE = 0xE24D; public final static int ARTICULATION_MARK_TENUTO = 0xE156; public final static int ARTICULATION_MARK_FERMATA = 0xE148; public final static int ARTICULATION_MARK_UP_BOW = 0xE15D; public final static int ARTICULATION_MARK_DOWN_BOW = 0xE15E; public final static int ORNAMENT_MARK_TRILL = 0xE161; public final static int ORNAMENT_MARK_MODRENT = 0xE174; public final static int ORNAMENT_MARK_TURN = 0xE160; public final static Font FONT_EMMENTALER = loadFont("/com/frinika/notation/Emmentaler-20.ttf"); private Graphics2D g; private Font music_font; private float music_fontsize; private Stroke music_stroke; private Stroke music_stroke_tie; private Stroke music_stroke_dotted; //private Stroke music_streke_beam; private float beamheight; private float beamspace; private float grid_size; private float cx = 0; private float cy = 0; private int stafflinecount = 5; private boolean in_note_group = false; private static Font loadFont(String filename) { try { InputStream is = NotationGraphics.class.getResourceAsStream(filename); Font font = Font.createFont(Font.TRUETYPE_FONT, is); is.close(); return font; } catch (FontFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } public NotationGraphics() { setSize(25); } public void setSize(float size) { music_fontsize = size; music_font = FONT_EMMENTALER.deriveFont(music_fontsize); music_stroke = new BasicStroke(3.5f*(music_fontsize/100f)); music_stroke_tie = new BasicStroke(4.5f*(music_fontsize/100f)); //music_streke_beam = new BasicStroke(12.5f*(music_fontsize/100f),BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); music_stroke_dotted = new BasicStroke( 3.5f*(music_fontsize/100f), BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f, new float[] {7.7f*(music_fontsize/100f)}, 7.7f*(music_fontsize/100f)); grid_size = 25f*(music_fontsize/100f); beamheight = grid_size*0.25f; beamspace = grid_size*0.4f; } public float getGridSize() { return grid_size; } public void setGraphics(Graphics2D g) { this.g = g; } public float getCurrentX() { return cx; } public float getCurrentY() { return cy; } public float getCurrentCol() { return cx/grid_size; } public float getCurrentLine() { return cy/grid_size; } public void absoluteX(float x) { cx = x; } // Set Y-location of Staff First Line public void absoluteY(float y) { cy = y; } public void relativeX(float x) { cx += x; } // Set Y-location of Staff First Line public void relativeY(float y) { cy += y; } public void absolute(float x) { cx = x*grid_size; } // Set Y-location of Staff First Line public void absoluteLine(float y) { cy = y*grid_size; } public void relative(float x) { cx += x*grid_size; } // Set Y-location of Staff First Line public void relativeLine(float y) { cy += y*grid_size; } public void setStaffLineCount(int count) { stafflinecount = count; } public void drawStaff(float width) { g.setStroke(music_stroke); float grid = getGridSize(); for (int i = 0; i < stafflinecount; i++) { Line2D.Float line = new Line2D.Float(cx, cy-i*grid, cx + width, cy-i*grid); g.draw(line); } } public void drawBarLine() { drawBarLine(1); } public void drawDottedBarLine() { drawBarLine(0); } public void drawDoubleBarLine() { drawBarLine(2); } public void drawBarLine(int type) { float grid = getGridSize(); if(type == 0) { g.setStroke(music_stroke_dotted); Line2D.Float line = new Line2D.Float(cx, cy-grid*(stafflinecount-1), cx, cy); g.draw(line); } if(type == 1) { g.setStroke(music_stroke); Line2D.Float line = new Line2D.Float(cx, cy-grid*(stafflinecount-1), cx, cy); g.draw(line); } if(type == 2) { g.setStroke(music_stroke); float w = grid*0.24f; Line2D.Float line = new Line2D.Float(cx-w, cy-grid*(stafflinecount-1), cx-w, cy); g.draw(line); line = new Line2D.Float(cx+w, cy-grid*(stafflinecount-1), cx+w, cy); g.draw(line); } } public void drawClef(int clef) { if(clef == CLEF_F) drawClef(clef, 6); else if(clef == CLEF_C) drawClef(clef, 4); else if(clef == CLEF_G) drawClef(clef, 2); else if(clef == CLEF_NEUTRAL) drawClef(clef, 4); else drawClef(clef, 4); } public void drawClef(int clef, int line) { g.setFont(music_font); float grid = getGridSize(); if(clef == CLEF_F) { g.drawString("" + (char)0xE18B, cx, cy - grid*(line*0.5f - 0.1f)); } if(clef == CLEF_C) { g.drawString("" + (char)0xE189, cx, cy - grid*(line*0.5f - 0.1f)); } if(clef == CLEF_G) { g.drawString("" + (char)0xE18D, cx, cy - grid*(line*0.5f - 0.1f)); } if(clef == CLEF_NEUTRAL) { g.drawString("" + (char)0xE18F, cx, cy - grid*(line*0.5f - 0.1f)); } if(clef == CLEF_TAB) { g.drawString("" + (char)0xE191, cx, cy - grid*(line*0.5f - 0.1f)); } } public float drawFlatKeySignature(int... notes) { int[] accidentals = new int[notes.length]; for (int i = 0; i < accidentals.length; i++) { accidentals[i] = -100; } return drawKeySignature(notes, accidentals); } public float drawSharpKeySignature(int... notes) { int[] accidentals = new int[notes.length]; for (int i = 0; i < accidentals.length; i++) { accidentals[i] = 100; } return drawKeySignature(notes, accidentals); } public float drawKeySignature(int[] notes, int accidental) { int[] accidentals = new int[notes.length]; for (int i = 0; i < accidentals.length; i++) { accidentals[i] = accidental; } return drawKeySignature(notes, accidentals); } public float drawKeySignature(int[] notes, int[] accidentals) { g.setFont(music_font); float x = 0; float grid = getGridSize(); for (int i = 0; i < accidentals.length; i++) { int accidental = accidentals[i]; int note = notes[i]; if(accidental == -200) { g.drawString("" + (char)0xE114, x*grid+cx, cy-(note*grid*0.5f)); x += 1.7f; } if(accidental == -150) { g.drawString("" + (char)0xE113, x*grid+cx, cy-(note*grid*0.5f)); g.drawString("" + (char)0xE112, x*grid+cx+grid, cy-(note*grid*0.5f)); x += 2.2f; } if(accidental == -100) { g.drawString("" + (char)0xE112, x*grid+cx, cy-(note*grid*0.5f)); x += 1.2f; } if(accidental == -50) { g.drawString("" + (char)0xE113, x*grid+cx, cy-(note*grid*0.5f)); x += 1.2f; } if(accidental == ACCIDENTAL_NATURAL) { g.drawString("" + (char)0xE111, x*grid+cx, cy-(note*grid*0.5f)); x += 1.2f; } if(accidental == 50) { g.drawString("" + (char)0xE10F, x*grid+cx, cy-(note*grid*0.5f)); x += 1.2f; } if(accidental == 100) { g.drawString("" + (char)0xE10E, x*grid+cx, cy-(note*grid*0.5f)); x += 1.2f; } if(accidental == 150) { g.drawString("" + (char)0xE110, x*grid+cx, cy-(note*grid*0.5f)); x += 1.8f; } if(accidental == 200) { g.drawString("" + (char)0xE116, x*grid+cx, cy-(note*grid*0.5f)); x += 1.2f; } } return x; } public void drawTimeSignature(int a, int b) { float grid = getGridSize(); g.setFont(music_font); g.drawString("" + (char)(0x0030 + a), cx, cy-grid*2); g.drawString("" + (char)(0x0030 + b), cx, cy); } // type = 0 (common time) // type = 1 (cut time) public void drawTimeSignature(int type) { float grid = getGridSize(); g.setFont(music_font); g.drawString("" + (char)(0xE193 + type), cx, cy-grid*2); } // note = 0 is first_line (bottom line) // dur =-2 (16 beat) (quadruple whole note) // dur =-1 (8 beat) (double whole note) // dur = 0 (4 beat) (whole note) // dur = 1 (2 beat) (half note) // dur = 2 (1 beat) (quarter note) // dur = 3 (1/2 beat) (eighth note) // dur = 4 (1/4 beat) (sixteenth note) // dur = 5 (1/8 beat) // linedir = -1 (show no line) // linedir = 0 (auto) // linedir = 1 (line is on right going up) // linedir = 2 (line is on left, going down) public Note drawNote(int note, int dur) { return drawNote(new Note(note, dur)); } public Note drawNote(int note, int dur, int dotted) { return drawNote(new Note(note, dur, dotted)); } public Note drawNote(int note, int dur, int dotted, int accidental) { return drawNote(new Note(note, dur, dotted, accidental)); } public Note drawNote(int note, int dur, int dotted, int accidental, int mark) { return drawNote(new Note(note,dur,dotted,accidental,mark)); } public Note drawNote(int note, int dur, int dotted, int accidental, int mark, int linedir) { return drawNote(new Note(note,dur,dotted,accidental,mark,linedir)); } public Note drawNote(Note n) { if(n.linedir == 0) { if(n.note > 4) n.linedir = 2; else n.linedir = 1; } else { if(n.linedir == -1) n.linedir = 0; } if(n.dur < 1) n.linedir = 0; boolean breakgroup = false; for(Note notepart : note_group_list) { // If x and last x is same, then don't break if(Math.abs(notepart.x - cx) < 0.0000001) { breakgroup = false; break; } if(n.linedir != 0 && notepart.linedir != 0) { if(notepart.linedir != n.linedir) { int min = note_group_list.get(0).note; int max = note_group_list.get(0).note; for(Note notepart2 : note_group_list) { if(notepart2.note < min) min = notepart2.note; if(notepart2.note > max) max = notepart2.note; } if(n.note < min) min = n.note; if(n.note > max) max = n.note; if(max - min > 7) { breakgroup = true; break; } } } if(notepart.dur <= 2) if(Math.abs(notepart.x - cx) > 0.0000001) { breakgroup = true; break; } if(n.dur <= 2) { if(notepart.dur > 2) { breakgroup = true; break; } } } if(breakgroup) drawNotes(); addNoteToGroup(n); if(!in_note_group) drawNotes(); return n; } private char getNoteHeadSymbol(int dur) { if(dur == -2) return (char)0xE1BD; else if(dur == -1) return (char)0xE11A; else if(dur == 0) return (char)0xE11B; else if(dur == 1) return (char)0xE11C; else return (char)0xE11D; } private void drawLedge(float cx, int note) { g.setStroke(music_stroke); float grid = getGridSize(); float notebasewidth = grid*1.3f; float ledge_width = grid*0.3f; for(int gi = 1; note <= -gi*2; gi++) { Line2D.Float line = new Line2D.Float(cx-ledge_width, cy+grid*gi, cx+notebasewidth+ledge_width, cy+grid*gi); g.draw(line); } //for(int gi = stafflinecount+1; note >= gi*2; gi++) for(int gi = stafflinecount; note >= gi*2; gi++) { Line2D.Float line = new Line2D.Float(cx-ledge_width, cy-grid*gi, cx+notebasewidth+ledge_width, cy-grid*gi); g.draw(line); } } private class TimePart { float x; int dur; int mark = 0; List<Note> notes = new ArrayList<Note>(); } private TreeMap<Float, TimePart> note_group_xlist = new TreeMap<Float, TimePart>(); private ArrayList<Note> note_group_list = new ArrayList<Note>(); private Note addNoteToGroup(Note notepart) { note_group_list.add(notepart); TimePart timepart = note_group_xlist.get(notepart.x); if(timepart == null) { timepart = new TimePart(); timepart.x = notepart.x; timepart.dur = notepart.dur; timepart.mark = notepart.mark; note_group_xlist.put(notepart.x, timepart); } timepart.notes.add(notepart); return notepart; } private void drawNoteBase(Note notepart, int movefix) { drawLedge(notepart.x, notepart.note); int note = notepart.note; int dur = notepart.dur; int dotted = notepart.dotted; int accidental = notepart.accidental; float grid = getGridSize(); float cx = notepart.x; float notebasewidth = grid*1.3f; g.setFont(music_font); float mx = 0; if(movefix == -1) mx = -notebasewidth; Color bakcolor = null; if(notepart.color != null) { bakcolor = g.getColor(); g.setColor(notepart.color); } if(accidental == -200) { g.drawString("" + (char)0xE114, mx+cx-grid*1.7f, cy-(note*grid*0.5f)); } if(accidental == -150) { g.drawString("" + (char)0xE113, mx+cx-grid*2.2f, cy-(note*grid*0.5f)); g.drawString("" + (char)0xE112, mx+cx-grid*1.2f, cy-(note*grid*0.5f)); } if(accidental == -100) { g.drawString("" + (char)0xE112, mx+cx-grid*1.2f, cy-(note*grid*0.5f)); } if(accidental == -50) { g.drawString("" + (char)0xE113, mx+cx-grid*1.2f, cy-(note*grid*0.5f)); } if(accidental == ACCIDENTAL_NATURAL) { g.drawString("" + (char)0xE111, mx+cx-grid*1.2f, cy-(note*grid*0.5f)); } if(accidental == 50) { g.drawString("" + (char)0xE10F, mx+cx-grid*1.2f, cy-(note*grid*0.5f)); } if(accidental == 100) { g.drawString("" + (char)0xE10E, mx+cx-grid*1.2f, cy-(note*grid*0.5f)); } if(accidental == 150) { g.drawString("" + (char)0xE110, mx+cx-grid*1.7f, cy-(note*grid*0.5f)); } if(accidental == 200) { g.drawString("" + (char)0xE116, mx+cx-grid*1.2f, cy-(note*grid*0.5f)); } if(movefix == 1) mx = notebasewidth; g.drawString("" + getNoteHeadSymbol(dur), cx+mx, cy-(note*grid*0.5f)); if(movefix == -1) mx = 0; float xx = 0; for (int i = 0; i < dotted; i++) { g.drawString("" + (char)0xE119, cx+grid*1.6f+mx+xx , cy-(note*grid*0.5f)); xx += grid*0.6f; } if(bakcolor != null) { g.setColor(bakcolor); } } private void drawNotes() { if(note_group_list.size() == 0) return; float grid = getGridSize(); float notebasewidth = grid*1.3f; float stem_length =3.5f* grid; g.setStroke(music_stroke); int linedir = note_group_list.get(0).linedir; TimePart[] parts = new TimePart[note_group_xlist.values().size()]; note_group_xlist.values().toArray(parts); for(TimePart timepart : parts) { Note[] notes = new Note[timepart.notes.size()]; timepart.notes.toArray(notes); Arrays.sort(notes, new Comparator<Note>() { public int compare(Note o1, Note o2) { return o2.note - o1.note; } }); Note lastpart = null; for(Note notepart : timepart.notes) { if(lastpart != null && (Math.abs(lastpart.note - notepart.note) == 1)) { if(linedir == 0 || linedir == 1) drawNoteBase(notepart, 1); else drawNoteBase(notepart, -1); } else drawNoteBase(notepart,0); lastpart = notepart; } } int maxdur = 0; for (int i = 0; i < note_group_list.size(); i++) { Note notepart = note_group_list.get(i); if(notepart.dur > maxdur) maxdur = notepart.dur; } if(maxdur > 4) { stem_length += (maxdur - 4)*(beamheight+beamspace); } { float x = note_group_list.get(0).x; boolean ok = true; int maxnote = note_group_list.get(0).note; int minnote = note_group_list.get(0).note; for (int i = 0; i < note_group_list.size(); i++) { Note notepart = note_group_list.get(i); if(notepart.note > maxnote) maxnote = notepart.note; if(notepart.note < minnote) minnote = notepart.note; if(notepart.linedir > linedir) linedir = notepart.linedir; if(Math.abs(notepart.x - x) > 0.00000001f) { ok = false; break; } } if(ok) { int dur = note_group_list.get(0).dur; float cx = note_group_list.get(0).x; if(linedir == 1) { Line2D.Float line = new Line2D.Float(cx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f), cx+notebasewidth, cy-(grid*0.3f)-(minnote*grid*0.5f)); g.draw(line); if(dur == 3) g.drawString("" + (char)0xE17F, cx+notebasewidth+(grid*0.1f), cy-(stem_length)-(maxnote*grid*0.5f)); if(dur == 4) g.drawString("" + (char)0xE180, cx+notebasewidth+(grid*0.1f), cy-(stem_length)-(maxnote*grid*0.5f)); if(dur == 5) g.drawString("" + (char)0xE181, cx+notebasewidth+(grid*0.1f), cy-(stem_length)-(maxnote*grid*0.5f)); if(dur == 6) g.drawString("" + (char)0xE182, cx+notebasewidth+(grid*0.1f), cy-(stem_length)-(maxnote*grid*0.5f)); } if(linedir == 2) { Line2D.Float line = new Line2D.Float(cx, cy+stem_length-(minnote*grid*0.5f), cx, cy+(grid*0.3f)-(maxnote*grid*0.5f)); g.draw(line); if(dur == 3) g.drawString("" + (char)0xE183, cx+(grid*0.1f), cy+(stem_length)-(minnote*grid*0.5f)); if(dur == 4) g.drawString("" + (char)0xE186, cx+(grid*0.1f), cy+(stem_length)-(minnote*grid*0.5f)); if(dur == 5) g.drawString("" + (char)0xE187, cx+(grid*0.1f), cy+(stem_length)-(minnote*grid*0.5f)); if(dur == 6) g.drawString("" + (char)0xE188, cx+(grid*0.1f), cy+(stem_length)-(minnote*grid*0.5f)); } note_group_list.clear(); note_group_xlist.clear(); return; } } { int maxnote = note_group_list.get(0).note; float maxnote_x = note_group_list.get(0).x; int minnote = note_group_list.get(0).note; float minnote_x = note_group_list.get(0).x; float minx = note_group_list.get(0).x; float maxx = note_group_list.get(0).x; float minx_note = note_group_list.get(0).note; float maxx_note = note_group_list.get(0).note; for (int i = 0; i < note_group_list.size(); i++) { Note notepart = note_group_list.get(i); if(notepart.note > maxnote) { maxnote = notepart.note; maxnote_x = notepart.x; } if(notepart.note < minnote) { minnote = notepart.note; minnote_x = notepart.x; } if(notepart.x > maxx) { maxx_note = notepart.note; maxx = notepart.x; } if(notepart.x < minx) { minx_note = notepart.note; minx = notepart.x; } //if(notepart.linedir > linedir) linedir = notepart.linedir; } if(linedir == 1) { float h = 0; if(Math.abs(maxnote_x-minnote_x) > 0.00000001f) h = Math.abs((maxnote-minnote)*grid*0.5f) / Math.abs(maxnote_x - minnote_x); if(h > grid*0.05f) h = grid*0.05f; // 1. find optimial h for (int i = 0; i < note_group_list.size(); i++) { Note notepart = note_group_list.get(i); int note = notepart.note; float cx = notepart.x; if(Math.abs(maxnote_x-cx) > 0.00000001f) { float h2 = Math.abs((maxnote-note)*grid*0.5f) / Math.abs(maxnote_x - cx); if(h2 < h) h = h2; } } if(maxnote_x != maxx && maxnote_x != minx) h = 0; //g.setColor(Color.GREEN); for (int i = 0; i < note_group_list.size(); i++) { Note notepart = note_group_list.get(i); int note = notepart.note; float cx = notepart.x; if(minx_note < maxx_note) { Line2D.Float line = new Line2D.Float(cx+notebasewidth, h*(maxx-cx) + cy-stem_length-(maxnote*grid*0.5f), cx+notebasewidth, cy-(grid*0.3f)-(note*grid*0.5f)); g.draw(line); } else { Line2D.Float line = new Line2D.Float(cx+notebasewidth, h*(cx-minx) + cy-stem_length-(maxnote*grid*0.5f), cx+notebasewidth, cy-(grid*0.3f)-(note*grid*0.5f)); g.draw(line); } } //g.setStroke(music_streke_beam); g.setStroke(music_stroke); /* GeneralPath path = new GeneralPath(); if(minx_note < maxx_note) { path.moveTo(minx+notebasewidth, h*(maxx-minx)+cy-stem_length-(maxnote*grid*0.5f)); path.lineTo(minx+notebasewidth, h*(maxx-minx)+cy-stem_length-(maxnote*grid*0.5f)+grid*0.5f); path.lineTo(maxx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)+grid*0.5f); path.lineTo(maxx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)); } else { path.moveTo(minx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)); path.lineTo(minx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)+grid*0.5f); path.lineTo(maxx+notebasewidth, h*(maxx-minx)+cy-stem_length-(maxnote*grid*0.5f)+grid*0.5f); path.lineTo(maxx+notebasewidth, h*(maxx-minx)+cy-stem_length-(maxnote*grid*0.5f)); }*/ /* path.moveTo(minx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)); path.lineTo(minx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)+grid*0.5f); path.lineTo(maxx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)+grid*0.5f); path.lineTo(maxx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)); */ /*path.closePath(); g.draw(path); g.fill(path);*/ //Line2D.Float line = new Line2D.Float(minx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f), maxx+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)); //g.draw(line); for (int i = 0; i < parts.length; i++) { float gy = 0; for (int j = 3; j <= parts[i].dur; j++) { float x1 = parts[i].x; float x2 = parts[i].x; if(i+1 < parts.length) { if(parts[i+1].dur >= j) x2 = parts[i+1].x; else x2 = (x2 + parts[i+1].x) / 2.0f; } else { if(parts[i-1].dur >= j) { gy -= beamheight + beamspace; continue; } x2 = (x2 + parts[i-1].x) / 2.0f; } GeneralPath path = new GeneralPath(); if(minx_note < maxx_note) { //g.setColor(Color.RED); path.moveTo(x1+notebasewidth, h*(maxx-x1)+cy-stem_length-(maxnote*grid*0.5f)-gy); path.lineTo(x1+notebasewidth, h*(maxx-x1)+cy-stem_length-(maxnote*grid*0.5f)-gy+beamheight); path.lineTo(x2+notebasewidth, h*(maxx-x2)+cy-stem_length-(maxnote*grid*0.5f)-gy+beamheight); path.lineTo(x2+notebasewidth, h*(maxx-x2)+cy-stem_length-(maxnote*grid*0.5f)-gy); } else { //g.setColor(Color.BLUE); path.moveTo(x1+notebasewidth, h*(x1-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy); path.lineTo(x1+notebasewidth, h*(x1-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy+beamheight); path.lineTo(x2+notebasewidth, h*(x2-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy+beamheight); path.lineTo(x2+notebasewidth, h*(x2-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy); } path.closePath(); g.draw(path); g.fill(path); g.setColor(Color.BLACK); //line = new Line2D.Float(x1+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)-gy, x2+notebasewidth, cy-stem_length-(maxnote*grid*0.5f)-gy); //g.draw(line); gy -= beamheight+beamspace; } } g.setColor(Color.BLACK); } if(linedir == 2) { float h = 0; if(Math.abs(maxnote_x-minnote_x) > 0.00000001f) h = Math.abs((maxnote-minnote)*grid*0.5f) / Math.abs(maxnote_x - minnote_x); if(h > grid*0.05f) h = grid*0.05f; // 1. find optimial h for (int i = 0; i < note_group_list.size(); i++) { Note notepart = note_group_list.get(i); int note = notepart.note; float cx = notepart.x; if(Math.abs(minnote_x-cx) > 0.00000001f) { float h2 = Math.abs((minnote-note)*grid*0.5f) / Math.abs(minnote_x - cx); if(h2 < h) h = h2; } } if(minnote_x != maxx && minnote_x != minx) h = 0; for (int i = 0; i < note_group_list.size(); i++) { Note notepart = note_group_list.get(i); int note = notepart.note; float cx = notepart.x; //Line2D.Float line = new Line2D.Float(cx, cy+stem_length-(minnote*grid*0.5f), cx, cy+(grid*0.3f)-(note*grid*0.5f)); //g.draw(line); if(minx_note < maxx_note) { Line2D.Float line = new Line2D.Float(cx, -h*(cx - minx) + cy+stem_length-(minnote*grid*0.5f), cx, cy+(grid*0.3f)-(note*grid*0.5f)); g.draw(line); } else { Line2D.Float line = new Line2D.Float(cx, -h*(maxx-cx) + cy+stem_length-(minnote*grid*0.5f), cx, cy+(grid*0.3f)-(note*grid*0.5f)); g.draw(line); } } g.setStroke(music_stroke); /* GeneralPath path = new GeneralPath(); path.moveTo(minx, cy+stem_length-(minnote*grid*0.5f)); path.lineTo(minx, cy+stem_length-(minnote*grid*0.5f)-grid*0.5f); path.lineTo(maxx, cy+stem_length-(minnote*grid*0.5f)-grid*0.5f); path.lineTo(maxx, cy+stem_length-(minnote*grid*0.5f)); path.closePath(); g.draw(path); g.fill(path);*/ for (int i = 0; i < parts.length; i++) { float gy = 0; for (int j = 3; j <= parts[i].dur; j++) { float x1 = parts[i].x; float x2 = parts[i].x; if(i+1 < parts.length) { if(parts[i+1].dur >= j) x2 = parts[i+1].x; else x2 = (x2 + parts[i+1].x) / 2.0f; } else { if(parts[i-1].dur >= j) { gy += beamheight + beamspace; continue; } x2 = (x2 + parts[i-1].x) / 2.0f; } GeneralPath path = new GeneralPath(); /* path.moveTo(x1, cy+stem_length-(minnote*grid*0.5f)-gy); path.lineTo(x1, cy+stem_length-(minnote*grid*0.5f)-gy-grid*0.5f); path.lineTo(x2, cy+stem_length-(minnote*grid*0.5f)-gy-grid*0.5f); path.lineTo(x2, cy+stem_length-(minnote*grid*0.5f)-gy); */ if(minx_note < maxx_note) { //g.setColor(Color.GREEN); path.moveTo(x1, h*(minx-x1)+cy+stem_length-(minnote*grid*0.5f)-gy); path.lineTo(x1, h*(minx-x1)+cy+stem_length-(minnote*grid*0.5f)-gy-beamheight); path.lineTo(x2, h*(minx-x2)+cy+stem_length-(minnote*grid*0.5f)-gy-beamheight); path.lineTo(x2, h*(minx-x2)+cy+stem_length-(minnote*grid*0.5f)-gy); /* path.moveTo(x1+notebasewidth, h*(maxx-x1)+cy-stem_length-(maxnote*grid*0.5f)-gy); path.lineTo(x1+notebasewidth, h*(maxx-x1)+cy-stem_length-(maxnote*grid*0.5f)-gy+grid*0.5f); path.lineTo(x2+notebasewidth, h*(maxx-x2)+cy-stem_length-(maxnote*grid*0.5f)-gy+grid*0.5f); path.lineTo(x2+notebasewidth, h*(maxx-x2)+cy-stem_length-(maxnote*grid*0.5f)-gy);*/ } else { //g.setColor(Color.PINK); path.moveTo(x1, h*(x1-maxx)+cy+stem_length-(minnote*grid*0.5f)-gy); path.lineTo(x1, h*(x1-maxx)+cy+stem_length-(minnote*grid*0.5f)-gy-beamheight); path.lineTo(x2, h*(x2-maxx)+cy+stem_length-(minnote*grid*0.5f)-gy-beamheight); path.lineTo(x2, h*(x2-maxx)+cy+stem_length-(minnote*grid*0.5f)-gy); /* path.moveTo(x1+notebasewidth, h*(x1-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy); path.lineTo(x1+notebasewidth, h*(x1-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy+grid*0.5f); path.lineTo(x2+notebasewidth, h*(x2-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy+grid*0.5f); path.lineTo(x2+notebasewidth, h*(x2-minx)+cy-stem_length-(maxnote*grid*0.5f)-gy); */ } path.closePath(); g.draw(path); g.fill(path); g.setColor(Color.BLACK); //line = new Line2D.Float(x1, cy+stem_length-(minnote*grid*0.5f)-gy, x2, cy+stem_length-(minnote*grid*0.5f)-gy); //g.draw(line); gy += beamheight + beamspace; } } } note_group_list.clear(); note_group_xlist.clear(); return; } } public void startNoteGroup() { if(in_note_group) return; in_note_group = true; } public void endNoteGroup() { if(!in_note_group) return; in_note_group = false; drawNotes(); } public void drawNoteTie(Note note1, Note note2) { g.setStroke(music_stroke_tie); float grid = getGridSize(); float y1 = cy - (note1.note*grid*0.5f); float y2 = cy - (note2.note*grid*0.5f); float x1 = note1.x + grid*0.5f; float x2 = note2.x + grid*0.5f; CubicCurve2D.Float curve = new CubicCurve2D.Float( x1,y1, x1,y1+grid*1f, x2,y2+grid*1f, x2,y2); g.draw(curve); } public void drawRest(int dur) { drawRest(dur, 0); } public void drawRest(int dur, int dotted) { drawNotes(); float grid = getGridSize(); g.setFont(music_font); if(dur == -2) { g.drawString("" + (char)0xE142, cx, cy-grid*2.5f); g.drawString("" + (char)0xE142, cx, cy-grid*1.5f); } else if(dur == -1) g.drawString("" + (char)0xE142, cx, cy-grid*2.5f); else if(dur == 0) g.drawString("" + (char)0xE100, cx, cy-grid*3); else if(dur == 1) g.drawString("" + (char)0xE101, cx, cy-grid*2); else if(dur == 2) g.drawString("" + (char)0xE107, cx, cy-grid*2); else if(dur == 3) g.drawString("" + (char)0xE109, cx, cy-grid*2); else if(dur == 4) g.drawString("" + (char)0xE10A, cx, cy-grid*3); else if(dur == 5) g.drawString("" + (char)0xE10B, cx, cy-grid*2); else if(dur == 6) g.drawString("" + (char)0xE10C, cx, cy-grid*3); else if(dur == 7) g.drawString("" + (char)0xE10D, cx, cy-grid*2); float xx = 0; for (int i = 0; i < dotted; i++) { g.drawString("" + (char)0xE119, cx+grid*1.8f+xx , cy-(5*grid*0.5f)); xx += grid*0.6f; } } }