/* * 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 static com.frinika.localization.CurrentLocale.getMessage; import java.awt.AWTEvent; import java.awt.Color; import java.awt.Cursor; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; import java.util.Vector; import com.frinika.notation.NotationGraphics.Note; import com.frinika.project.gui.ProjectFrame; import com.frinika.sequencer.FrinikaSequence; import com.frinika.sequencer.SwingSongPositionListenerWrapper; import com.frinika.sequencer.gui.DragViewTool; import com.frinika.sequencer.gui.EraseTool; import com.frinika.sequencer.gui.Item; import com.frinika.sequencer.gui.ItemPanel; import com.frinika.sequencer.gui.ItemScrollPane; import com.frinika.sequencer.gui.MyCursors; import com.frinika.sequencer.gui.RectZoomTool; import com.frinika.sequencer.gui.SelectTool; import com.frinika.sequencer.gui.WriteTool; import com.frinika.sequencer.gui.pianoroll.AudioFeedBack; import com.frinika.sequencer.gui.pianoroll.DragEventListener; import com.frinika.sequencer.gui.pianoroll.ItemPanelMultiEventListener; import com.frinika.sequencer.gui.pianoroll.ItemPanelPartListener; import com.frinika.sequencer.model.EditHistoryAction; import com.frinika.sequencer.model.EditHistoryContainer; import com.frinika.sequencer.model.EditHistoryListener; import com.frinika.sequencer.model.Lane; import com.frinika.sequencer.model.MidiLane; import com.frinika.sequencer.model.MidiPart; import com.frinika.sequencer.model.MultiEvent; import com.frinika.sequencer.model.NoteEvent; import com.frinika.sequencer.model.Part; import com.frinika.sequencer.model.notation.ClefChange; import com.frinika.sequencer.model.util.EventFilter; import com.frinika.sequencer.model.util.EventsInPartsIterator; public class NotationEditor extends ItemPanel implements EditHistoryListener, EventFilter { public static void main(String[] args) { double tr; int[] ret; /* * tr = 4; ret = parseDurToNotation(tr); System.out.println(tr + " => " + * ret[0]+ " , " + ret[1]); * * tr = 2; ret = parseDurToNotation(tr); System.out.println(tr + " => " + * ret[0]+ " , " + ret[1]); * * tr = 1; ret = parseDurToNotation(tr); System.out.println(tr + " => " + * ret[0]+ " , " + ret[1]); * * tr = 0.5; ret = parseDurToNotation(tr); System.out.println(tr + " => " + * ret[0]+ " , " + ret[1]); */ tr = 1; ret = parseDurToNotationLength(tr); System.out.println(tr + " => " + ret[0] + " , " + ret[1] + " , " + ret[2]); tr = 1 * 2.0 / 3.0; ret = parseDurToNotationLength(tr); System.out.println(tr + " => " + ret[0] + " , " + ret[1] + " , " + ret[2]); } private static double calcDottedDiffLen(int i) { if (i < 1) return 0; if (i == 1) { return 1.0 - Math.log(1.5) / Math.log(4); } return calcDottedDiffLen(i - 1) - Math.log(1 + 3 / ((Math.pow(2, i)) * 2 - 4)) / Math.log(4); } // 0,046554702 -0,29248125 0 dotted // 0,142877241 0,046554702 3 dotted // 0,303841289 0,142877241 2 dotted // 0,70751875 0,303841289 1 dotted private static double[] NOTE_DIFFLEN = new double[20]; // NOTE_DIFFLEN[1] = 0.707518749639422 // NOTE_DIFFLEN[2] = 0.30384128861061993 // NOTE_DIFFLEN[3] = 0.14287724116693876 // NOTE_DIFFLEN[4] = 0.06945654700230317 static { for (int i = 0; i < 20; i++) { NOTE_DIFFLEN[i] = calcDottedDiffLen(i); } } private static double NOTE_TRIPLET = 2 - Math.log(4 * (2.0 / 3.0)) / Math.log(2); // NOTE_TRIPLET = 0.5849625007211563 public static int[] parseDurToNotationLength(double tickdur) { // returns int array // // 0: dur length = 0(whole note) 1(half note) 2(quarter note) .... // 1: dotted = 0(not dotted) 1(dotted once) 2(dotted twice) .... // 2: tuplet = 0(not tupled) 2(triplet) // 3: tuplet = 0(not tupled) 3(triplet) int[] ret = new int[4]; double loglen = 2.0 - Math.log(tickdur) / Math.log(2); int dur = (int) (loglen + (1.0 - NOTE_DIFFLEN[1])); int dotted = 0; double durmod = loglen - dur; // Is it triplet ? if (dur >= 1) if (durmod >= NOTE_TRIPLET - 0.1 && durmod <= NOTE_TRIPLET + 0.1) { ret[0] = dur; ret[1] = dotted; ret[2] = 2; ret[3] = 3; return ret; } // Is it dotted ? if (durmod >= NOTE_DIFFLEN[2]) dotted = 1; else if (durmod >= NOTE_DIFFLEN[3]) dotted = 2; else if (durmod >= NOTE_DIFFLEN[4]) dotted = 3; if (dotted != 0) dur++; ret[0] = dur; ret[1] = dotted; return ret; } Iterable<MultiEvent> notesOnScreen; Iterable<MultiEvent> notesInFocus; EditHistoryContainer editHistory; ItemPanelMultiEventListener multiEventListener; ItemPanelPartListener partListener; AudioFeedBack audioFeedBack; private NoteEvent newNote = null; int velocity = 100; int channel = 1; protected NotationEditor(final ProjectFrame frame, ItemScrollPane scroller) { super(frame.getProjectContainer(), scroller, true, true,.5,false); // PJL added ticksToScreen and sampledBased notesOnScreen = new Iterable<MultiEvent>() { public Iterator<MultiEvent> iterator() { return new EventsInPartsIterator(project.getPartSelection() .getSelected(), NotationEditor.this); } }; notesInFocus = new Iterable<MultiEvent>() { public Iterator<MultiEvent> iterator() { Part focus = project.getPartSelection().getFocus(); if (focus == null) return null; return new EventsInPartsIterator(project.getPartSelection() .getFocus(), NotationEditor.this); } }; project.getDragList().addDragEventListener(new DragEventListener() { public void update() { repaintItems(); } }); this.sequencer = project.getSequencer(); sequencer.addSongPositionListener(new SwingSongPositionListenerWrapper( this)); audioFeedBack = new AudioFeedBack(project); multiEventListener = new ItemPanelMultiEventListener(this); partListener = new ItemPanelPartListener(this); project.getMultiEventSelection().addSelectionListener( multiEventListener); project.getPartSelection().addSelectionListener(partListener); FrinikaSequence seq = (FrinikaSequence) sequencer.getSequence(); ticksPerBeat = seq.getResolution(); editHistory = project.getEditHistoryContainer(); editHistory.addEditHistoryListener(this); /* * setLayout(new BorderLayout()); ScoreTest1 test = new ScoreTest1(); * add(test); */ ng.setSize(30); romanfont = new Font("Times new roman", Font.BOLD, 16).deriveFont(ng .getGridSize() * 2f); romanfont2 = new Font("Times new roman", Font.PLAIN, 16).deriveFont(ng .getGridSize() * 1.8f); addComponentListener(this); makeTools(); enableEvents(AWTEvent.MOUSE_EVENT_MASK); setFocusable(true); } protected void processMouseEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_PRESSED) { grabFocus(); } super.processMouseEvent(e); } void makeTools() { Cursor c = new Cursor(Cursor.DEFAULT_CURSOR); selectTool = new SelectTool(c); rectZoomTool = new RectZoomTool(c); // drumWriteTool = new WriteTool(MyCursors.getCursor("pencil")); writeTool = new WriteTool(MyCursors.getCursor("pencil")); eraseTool = new EraseTool(MyCursors.getCursor("eraser")); dragViewTool = new DragViewTool(MyCursors.getCursor("move")); } public NotationHeader header; NotationGraphics ng = new NotationGraphics(); Font romanfont; Font romanfont2; public boolean isBarTick(long tick) { int bar = project.getSequence().getResolution() * 4; return (tick % bar) == 0; } public long nextBarTick(long tick) { int bar = project.getSequence().getResolution() * 4; return (tick - tick % bar) + bar; } public long previousBarTick(long tick) { int bar = project.getSequence().getResolution() * 4; return tick - tick % bar; } double bar_zoomout_level = 0.1; private long org_screenToTick(int x, boolean quantizeMe) { return super.screenToTickAbs(x, quantizeMe); // PJL TODO check this // is really abs } private int org_tickToScreen(long tick) { return (int)super.userToScreen(tick); } public MidiLane getLaneAtY(int y) { HashSet<Lane> selectedlanes = new HashSet<Lane>(); Collection<Part> parts = project.getPartSelection().getSelected(); for (Part part : parts) { if (!selectedlanes.contains(part.getLane())) selectedlanes.add(part.getLane()); } ng.absoluteY(0); List<Lane> lanes = project.getLanes();// getPartSelection().getSelected(); for (Lane lane : lanes) { if (selectedlanes.contains(lane)) if (lane instanceof MidiLane) { MidiLane midilane = (MidiLane) lane; ng.relativeLine(20); if (y < ng.getCurrentY()) { return midilane; } ng.relativeLine(-6); } } return null; } public ClefChange getClef(MidiLane lane) { MidiPart head = lane.getHeadPart(); ClefChange clef_event = null; Iterator<MultiEvent> iter = head.getMultiEvents().iterator(); while (iter.hasNext()) { MultiEvent event = iter.next(); if (event.getStartTick() > 0) break; if (event instanceof ClefChange) { return (ClefChange) event; } } return new ClefChange(head, 0); } public long screenToTick(int x, boolean quantizeMe) { long tick = super.screenToTickAbs(x, false); long b1 = previousBarTick(tick); long b2 = nextBarTick(tick); long blen = b2 - b1; double d = (tick - b1) / (1.0 - bar_zoomout_level) - (blen * bar_zoomout_level + 0.5); if (d < 0) d = 0; else if (d > blen) d = blen; tick = b1 + (long) d; if (quantizeMe) { double tt = tick; double quant = this.getSnapQuantization(); if (quant < 0) { try { throw new Exception( " SNAP TO BAR NOT IMPLEMENTED IN NOTATION "); } catch (Exception e) { e.printStackTrace(); return tick; } } tt = (long) (Math.round(tt / this.getSnapQuantization())) * this.getSnapQuantization(); tick = (long) tt; } return tick; } public double tickToScreen(long tick) { long b1 = previousBarTick(tick); long b2 = nextBarTick(tick); long blen = b2 - b1; tick = b1 + (long) ((blen * bar_zoomout_level * 0.5) + ((tick - b1) * (1.0 - bar_zoomout_level))); double x = super.userToScreen(tick); return x; } class NoteEventTick implements Comparable { boolean isdragged = false; int status; long tick; int id; NoteEvent event; Note lastnote; public int compareTo(Object o) { long t = tick - ((NoteEventTick) o).tick; if (t < 0) return -1; if (t > 0) return 1; return id - ((NoteEventTick) o).id; } } Map<MidiLane, Integer> laneY = new HashMap<MidiLane, Integer>(); Map<MidiLane, ClefChange> laneClef = new HashMap<MidiLane, ClefChange>(); public void paintHeader(Graphics g, int scroll) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2.setColor(Color.DARK_GRAY); g2.fillRect(0, 0, 400, 20); g2.setColor(Color.BLACK); ng.setGraphics(g2); ng.absoluteY(20 - scroll); // ng.absoluteY(0); HashSet<Lane> selectedlanes = new HashSet<Lane>(); Collection<Part> parts = project.getPartSelection().getSelected(); for (Part part : parts) { if (!selectedlanes.contains(part.getLane())) selectedlanes.add(part.getLane()); } laneY.clear(); laneClef.clear(); List<Lane> lanes = project.getLanes();// getPartSelection().getSelected(); for (Lane lane : lanes) { if (selectedlanes.contains(lane)) if (lane instanceof MidiLane) { MidiLane midilane = (MidiLane) lane; ng.absolute(0); ng.relativeLine(14); laneY.put(midilane, (int) ng.getCurrentY()); laneClef.put(midilane, getClef(midilane)); ng.drawStaff(header.getSize().width); // ng.drawBarLine(); ng.relative(1); ClefChange clefevent = getClef(midilane); ng.drawClef(clefevent.clef_type, clefevent.clef_pos); // Draw // G-Clef g2.setFont(romanfont); g2.drawString(midilane.getName(), ng.getCurrentX(), ng .getCurrentY() - ng.getGridSize() * 6.5f); ng.relative(4); // ng.relative(ng.drawSharpKeySignature(8,5,9,6,3,7,4)+1); // ng.relative(ng.drawSharpKeySignature(8,5,9)+1); // ng.drawTimeSignature(4, 4); ng.drawTimeSignature(0); ng.relative(3); g2.setFont(romanfont2); // g2.drawString("0", ng.getCurrentX(), // ng.getCurrentY()-ng.getGridSize()*4.5f); ng.relative(3); } } } public int[] getNotationNotePos(ClefChange clef_event, int note) { int oct = (note / 12) - 5; int not = note % 12; int n = 0; int a = 0; if (not == 0) { n = 0; a = 0; } if (not == 1) { n = 0; a = 100; } if (not == 2) { n = 1; a = 0; } if (not == 3) { n = 1; a = 100; } if (not == 4) { n = 2; a = 0; } if (not == 5) { n = 3; a = 0; } if (not == 6) { n = 3; a = 100; } if (not == 7) { n = 4; a = 0; } if (not == 8) { n = 4; a = 100; } if (not == 9) { n = 5; a = 0; } if (not == 10) { n = 5; a = 100; } if (not == 11) { n = 6; a = 0; } n = n + oct * 7; if (clef_event.clef_type == NotationGraphics.CLEF_G) { n -= -(0) - (clef_event.clef_pos - 2); } else if (clef_event.clef_type == NotationGraphics.CLEF_C) { n -= -(4) - (clef_event.clef_pos - 2); } else if (clef_event.clef_type == NotationGraphics.CLEF_F) { n -= -(8) - (clef_event.clef_pos - 2); } int[] ret = new int[2]; ret[0] = n; ret[1] = a; return ret; } public int getNoteFromPos(ClefChange clef_event, int n) { if (clef_event.clef_type == NotationGraphics.CLEF_G) { n += -(0) - (clef_event.clef_pos - 2); } else if (clef_event.clef_type == NotationGraphics.CLEF_C) { n += -(4) - (clef_event.clef_pos - 2); } else if (clef_event.clef_type == NotationGraphics.CLEF_F) { n += -(8) - (clef_event.clef_pos - 2); } int oct = n / 7; n = n - oct * 7; if (n < 0) { n = n + 7; oct--; } int not = 0; if (n == 0) { not = 0; } if (n == 1) { not = 2; } if (n == 2) { not = 4; } if (n == 3) { not = 5; } if (n == 4) { not = 7; } if (n == 5) { not = 9; } if (n == 6) { not = 11; } oct += 5; return not + oct * 12; } @Override protected void paintImageImpl(Rectangle clipRect, Graphics2D g) { int clip_min_x = clipRect.x - 500; if (clip_min_x < 0) clip_min_x = 0; int clip_max_x = clipRect.x + clipRect.width + 500; // TODO Auto-generated method stub /* * } * * * public void paint(Graphics g) { * * super.paint(g); */ Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, // RenderingHints.VALUE_FRACTIONALMETRICS_ON); // g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, // RenderingHints.VALUE_STROKE_PURE); g2.setColor(Color.WHITE); g2.fillRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);// 0, // 40, // 2048, // 600); g2.setColor(Color.BLACK); ng.setGraphics(g2); HashSet<Lane> selectedlanes = new HashSet<Lane>(); Collection<Part> parts = project.getPartSelection().getSelected(); for (Part part : parts) { if (!selectedlanes.contains(part.getLane())) selectedlanes.add(part.getLane()); } ng.absoluteLine(0); boolean newNoteAdded = true; if (newNote != null) newNoteAdded = false; int res = project.getSequence().getResolution(); Collection<Item> dragList = project.getDragList(); List<Lane> lanes = project.getLanes();// getPartSelection().getSelected(); for (Lane lane : lanes) { if (selectedlanes.contains(lane)) if (lane instanceof MidiLane) { ng.absolute(0); ng.relativeLine(14); ng.drawStaff(clipRect.width + clipRect.x); long firsttick = org_screenToTick(clipRect.x, false); int max_x = clipRect.width + clipRect.x; long tt = firsttick; while (true) { tt = nextBarTick(tt); int x = org_tickToScreen(tt); if (x > max_x) break; ng.absoluteX(x); ng.drawBarLine(); } MidiLane midilane = (MidiLane) lane; ClefChange clef_event = getClef(midilane); // TreeSet<MultiEvent> multiEvents = new // TreeSet<MultiEvent>(); int id_count = 0; TreeSet<NoteEventTick> multiEventsTicks = new TreeSet<NoteEventTick>(); for (Part part : midilane.getParts()) if (part instanceof MidiPart) if (project.getPartSelection().getSelected() .contains(part)) { MidiPart midipart = (MidiPart) part; // if(midipart.getStartTick() >= 0) // if(midipart.getEndTick() < 1000) { boolean startread = false; for (MultiEvent event : midipart .getMultiEvents()) if (event instanceof NoteEvent) { NoteEvent noteevent = (NoteEvent) event; if (!dragList.isEmpty()) if (noteevent.isSelected()) noteevent = null; if (noteevent != null) { if (!newNoteAdded) { if (noteevent .getStartTick() > newNote .getStartTick()) { newNoteAdded = true; NoteEventTick n = new NoteEventTick(); n.id = id_count++; n.event = newNote; n.tick = newNote .getStartTick(); n.status = 1; multiEventsTicks.add(n); n = new NoteEventTick(); n.id = id_count++; n.event = newNote; n.tick = newNote .getEndTick(); n.status = 0; multiEventsTicks.add(n); } } int x = (int)tickToScreen(noteevent .getStartTick()); if (!startread) { if (x >= clip_min_x) startread = true; } if (startread) { NoteEventTick n = new NoteEventTick(); n.id = id_count++; n.event = noteevent; n.tick = noteevent .getStartTick(); n.status = 1; multiEventsTicks.add(n); if (noteevent.isDrumHit()) { n.status = 2; } else { n = new NoteEventTick(); n.id = id_count++; n.event = noteevent; n.tick = noteevent .getEndTick(); n.status = 0; multiEventsTicks.add(n); } if (x > clip_max_x) break; } } // multiEvents.addAll(midipart.getMultiEvents()); } } } // System.out.println("DRAG PAINT"); for (Item item : dragList) { NoteEvent noteevent = (NoteEvent) item; if (noteevent.getPart().getLane() == lane) { int x = (int) tickToScreen(noteevent.getStartTick()); NoteEventTick n = new NoteEventTick(); n.isdragged = true; n.id = id_count++; n.event = noteevent; n.tick = noteevent.getStartTick(); n.status = 1; multiEventsTicks.add(n); if (noteevent.isDrumHit()) { n.status = 2; } else { n = new NoteEventTick(); n.isdragged = true; n.id = id_count++; n.event = noteevent; n.tick = noteevent.getEndTick(); n.status = 0; multiEventsTicks.add(n); } } } // Avarage tick together 0..32 ticks /* * ArrayList<NoteEventTick> currentgroup = new ArrayList<NoteEventTick>(); * double tickavg = 0; * * for(NoteEventTick event : multiEventsTicks) { * NoteEventTick noteevent = (NoteEventTick)event; long * curtick = event.tick; if(currentgroup.isEmpty()) { * currentgroup.add(event); tickavg = curtick; } else { * if(Math.abs(tickavg - curtick) < res/4) { * currentgroup.add(event); int c = currentgroup.size(); * tickavg = (tickavg*(c-1) + curtick)/c; } else { * for(NoteEventTick event2 : currentgroup) event2.tick = * (long)tickavg; currentgroup.clear(); } } } * for(NoteEventTick event2 : currentgroup) event2.tick = * (long)tickavg; currentgroup.clear(); */ ng.relative(1); long max_tick = 0; TreeMap<Long, List<NoteEventTick>> tickslist = new TreeMap<Long, List<NoteEventTick>>(); for (NoteEventTick event : multiEventsTicks) { List<NoteEventTick> list = tickslist.get(event.tick); if (list == null) { list = new ArrayList<NoteEventTick>(); tickslist.put(event.tick, list); } if (event.tick > max_tick) max_tick = event.tick; list.add(event); } // Add phantom events for bar/measure seperation long m = 0; m = screenToTick(clip_min_x, false); if (m < 0) m = 0; m = m - (m % (res * 4)); while (m < max_tick) { NoteEventTick event = new NoteEventTick(); event.tick = m; event.status = 2; // phantom status // not a real // event List<NoteEventTick> list = tickslist.get(event.tick); if (list == null) { list = new ArrayList<NoteEventTick>(); tickslist.put(event.tick, list); } list.add(event); m += res * 4; // res=quart note, res*4=whole note = in // 4/4 a whole is a bar/measure } ng.startNoteGroup(); TreeMap<Integer, NoteEventTick> act = new TreeMap<Integer, NoteEventTick>(); Iterator<List<NoteEventTick>> iter = tickslist.values() .iterator(); List<NoteEventTick> nextitem = iter.hasNext() ? iter.next() : null; while (nextitem != null) { List<NoteEventTick> curitem = nextitem; nextitem = iter.hasNext() ? iter.next() : null; if (isBarTick(curitem.get(0).tick)) { ng.endNoteGroup(); ng.startNoteGroup(); } ng.absoluteX((int)tickToScreen(curitem.get(0).tick)); long tickdur = nextitem == null ? res : nextitem.get(0).tick - curitem.get(0).tick; int[] ret = parseDurToNotationLength(((double) tickdur) / ((double) res)); int dur = ret[0]; int dotted = ret[1]; int tuplet_a = ret[2]; int tuplet_b = ret[3]; boolean noteprinted = false; for (NoteEventTick event : curitem) { NoteEventTick noteevent = (NoteEventTick) event; if (noteevent.status == 0) act.remove(noteevent.event.getNote()); if (noteevent.status == 1) act.put(noteevent.event.getNote(), noteevent); } for (NoteEventTick event : act.values()) { NoteEventTick noteevent = (NoteEventTick) event; if (noteevent.status == 1) { noteprinted = true; int note = noteevent.event.getNote(); /* * g.setColor(Color.PINK); Rectangle rec = * getItemBounds(noteevent.event); * g.drawRect(rec.x, rec.y, rec.width, * rec.height); g.setColor(Color.BLACK); */ int[] n_ret = getNotationNotePos(clef_event, note); int n = n_ret[0]; int a = n_ret[1]; Note notegraphic = ng.drawNote(n - 2, dur); // G-clef // is // at 2 notegraphic.dotted = dotted; if (tuplet_a == 2 && tuplet_b == 3) // Triplet notegraphic.color = Color.BLUE; if (event.isdragged) notegraphic.color = Color.RED; if (noteevent.event.isSelected()) notegraphic.color = Color.RED; if (newNote != null) if (noteevent.event == newNote) notegraphic.color = Color.GRAY; notegraphic.accidental = a; if (noteevent.lastnote != null) ng.drawNoteTie(noteevent.lastnote, notegraphic); noteevent.lastnote = notegraphic; } } if (!noteprinted) { if (dur < 8) if (nextitem != null) ng.drawRest(dur, dotted); } } ng.endNoteGroup(); /* * ng.startNoteGroup(); ng.drawNote(-2,2); ng.relative(6); * ng.drawNote(-2,2); ng.relative(6); ng.drawNote(0,2); * ng.relative(6); ng.drawNote(2,2); ng.relative(6); * ng.endNoteGroup(); * * ng.drawBarLine(); g2.setFont(romanfont2); * //g2.drawString("1", ng.getCurrentX(), * ng.getCurrentY()-ng.getGridSize()*4.5f); ng.relative(3); * * ng.startNoteGroup(); ng.drawNote(-2,2); ng.relative(6); * ng.drawNote(-2,2); ng.relative(6); ng.drawNote(0,2); * ng.relative(6); ng.drawNote(2,3); ng.relative(3); * ng.drawNote(2,3); ng.relative(6); ng.endNoteGroup(); * * ng.drawBarLine(); g2.setFont(romanfont2); * //g2.drawString("2", ng.getCurrentX(), * ng.getCurrentY()-ng.getGridSize()*4.5f); ng.relative(3); * * // TEST * * ng.startNoteGroup(); ng.drawNote(2,3); ng.drawNote(4,3); * ng.drawNote(6,3); ng.relative(3); ng.endNoteGroup(); * * ng.startNoteGroup(); ng.drawNote(2,2); ng.drawNote(4,2); * ng.drawNote(6,2); ng.relative(3); ng.endNoteGroup(); * * ng.startNoteGroup(); ng.drawNote(2,1); ng.drawNote(4,1); * ng.drawNote(6,1); ng.relative(3); ng.endNoteGroup(); * * ng.startNoteGroup(); ng.drawNote(2,0); ng.drawNote(4,0); * ng.drawNote(6,0); ng.relative(3); ng.endNoteGroup(); * * * ng.startNoteGroup(); ng.drawNote(2,3,0,0,0,1); * ng.drawNote(4,3,0,0,0,1); ng.drawNote(6,3,0,0,0,1); * ng.relative(3); ng.endNoteGroup(); * * ng.startNoteGroup(); ng.drawNote(8,3); ng.relative(3); * ng.drawNote(5,4); ng.relative(3); ng.drawNote(4,4); * ng.relative(3); ng.endNoteGroup(); * * * ng.startNoteGroup(); ng.drawNote(0,2).mark = * NotationGraphics.ARTICULATION_MARK_OPEN_NOTE; * ng.relative(3); ng.drawNote(0,3); ng.relative(3); * ng.drawNote(2,4).mark = * NotationGraphics.ORNAMENT_MARK_TRILL; ng.relative(3); * ng.drawNote(6,5).mark = * NotationGraphics.ORNAMENT_MARK_TURN; ng.relative(3); * ng.drawNote(4,1); ng.relative(3); ng.endNoteGroup(); * * ng.relative(3); * * ng.startNoteGroup(); ng.drawNote(8,4); ng.drawNote(5,4); * ng.drawNote(4,4,0,100); ng.endNoteGroup(); * * ng.relative(6); * * ng.startNoteGroup(); ng.drawNote(-1,4); * ng.drawNote(0,4,0,100); ng.drawNote(4,4); * ng.endNoteGroup(); */ // TEST END } } } private static final long serialVersionUID = 1L; @Override public double getSnapQuantization() { return this.project.getPianoRollSnapQuantization(); } @Override public void setSnapQuantization(double quant) { this.project.setPianoRollSnapQuantization(quant); repaintItems(); } @Override public boolean isSnapQuantized() { return this.project.isPianoRollSnapQuantized(); } @Override public void setSnapQuantized(boolean b) { this.project.setPianoRollSnapQuantized(b); /* * * quantize = b; if (b) * MultiEventClipboard.getDefaultMultiEventClipboard() * .setQuantization(snaptoQuantization); else * MultiEventClipboard.getDefaultMultiEventClipboard() * .setQuantization(1); */ } @Override public void setFocus(Item item) { this.project.getMultiEventSelection().setFocus((MultiEvent) item); this.project.getPartSelection().notifyListeners(); repaintItems(); } @Override public void clientNotifySelectionChange() { this.project.getPartSelection().notifyListeners(); } @Override public void setTimeAtX(int x) { long tick = screenToTick(x, this.project.isPianoRollSnapQuantized()); this.sequencer.setTickPosition(tick); } public void startDrag() { // project.clearDragList(); project.getDragList().startDrag(dragItem); } /** * drags the dragList to Point p. * */ int noteItemHeight = 3; public void dragTo(Point p) { int dxDragged = p.x - xAnchor; int dyDragged = p.y - yAnchor; long dtick = org_screenToTick(dxDragged, project .isPianoRollSnapQuantized()); /* * if (project.isPianoRollSnapQuantized()) { dtick = * snaptoQuantize(dxDragged); } else { dtick = (long) (dxDragged / * ticksToScreen); } */ int dpitch = 0; if (dragMode == OVER_ITEM_MIDDLE) dpitch = -dyDragged / noteItemHeight; if (dtick == 0 && dpitch == 0) return; if (dragArmed) startDrag(); dragArmed = false; Collection<Item> dragList = project.getDragList(); if (dpitch != 0) { int pitlim; if (dpitch > 0) pitlim = 0; else pitlim = 127; for (Item it : dragList) { NoteEvent ev = (NoteEvent) it; int pitch = ((NoteEvent) ev).getNote() + dpitch; if (dpitch > 0) pitlim = Math.max(pitch, pitlim); else pitlim = Math.min(pitch, pitlim); } if (dpitch > 0 && pitlim > 127) dpitch = dpitch - (pitlim - 127); else if (dpitch < 0 && pitlim < 0) dpitch = dpitch - pitlim; } long dt = 0; for (Item it : dragList) { NoteEvent ev = (NoteEvent) it; switch (dragMode) { case OVER_ITEM_MIDDLE: long tick = ev.getStartTick() + dtick; int pitch = ((NoteEvent) ev).getNote() + dpitch; dt = Math.min(dt, tick); ev.setStartTick(tick); ev.setNote(pitch); break; case OVER_ITEM_RIGHT: long dur = ev.getDuration() + dtick; dur = Math.max(1, dur); ev.setDuration(dur); break; case OVER_ITEM_LEFT: dur = ev.getDuration() - dtick; long st = ev.getStartTick() + dtick; dur = Math.max(1, dur); ev.setDuration(dur); ev.setStartTick(st); break; default: System.err.println(" unknown dragmode " + dragMode); try { throw new Exception("WHY OH WHY ARE WE HERE NOW"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (dpitch != 0) feedBack(ev); } if (dt != 0) { for (Item it : dragList) { NoteEvent ev = (NoteEvent) it; long tick = ev.getStartTick() - dt; ev.setStartTick(tick); } } project.getDragList().notifyDragEventListeners(); project.getDragList().notifyFeedbackItemListeners(); xAnchor = xAnchor + (int) (dtick * userToScreen); yAnchor = yAnchor - dpitch * noteItemHeight; // repaintItems(); } @Override public void endDrag() { if (dragArmed) { dragArmed = false; return; } project.getDragList().endDrag(controlIsDown); } @Override public int getHoverStateAt(Point p) { Part focusPart = project.getPartSelection().getFocus(); if (!(focusPart instanceof MidiPart)) return OVER_NOTHING; final int endTol = 20; // final int extraX = 20 ; // if (true) return OVER_ITEM_MIDDLE; int tol = endTol; Iterable<? extends MultiEvent> list; if (focusPart == null) list = notesOnScreen; else list = ((MidiPart) focusPart).getMultiEvents(); for (MultiEvent e : list) { if (e instanceof NoteEvent) { Rectangle rect = getItemBounds(e); if (rect.contains(p)) { /* * if (((NoteEvent)e).isDrumHit()) return OVER_ITEM_MIDDLE; * if (rect.width < endTol * 5) tol = rect.width / 3; if * ((p.x - rect.x) <= tol) return OVER_ITEM_LEFT; if * ((rect.x + rect.width - p.x) <= tol) return * OVER_ITEM_RIGHT; */ return OVER_ITEM_MIDDLE; } } } return OVER_NOTHING; } @Override public Item itemAt(Point p) { Item at = null; for (MultiEvent note : notesOnScreen) { if (getItemBounds(note).contains(p)) { if (note.isSelected()) return note; else if (at == null) at = note; } } return at; } @Override protected void paintImageImplLabel(Graphics2D graphics) { // TODO Auto-generated method stub } @Override public void clientClearSelection() { project.getMultiEventSelection().clearSelection(); } final Rectangle rectTmp = new Rectangle(); private Rectangle getItemBounds(Item it) { NoteEvent e = (NoteEvent) it; long tick = e.getStartTick(); // Careful that origins must always conincide int x1 = (int) tickToScreen(tick); int pitch = e.getNote(); int cy = laneY.get(e.getMidiPart().getLane()); ClefChange clef = laneClef.get(e.getMidiPart().getLane()); if (clef == null) return null; int[] n_ret = getNotationNotePos(clef, e.getNote()); int n = n_ret[0] + 4; float grid = ng.getGridSize(); float y = cy - (n * grid * 0.5f); int noteItemWidth = (int) (grid * 1.2f); int noteItemHeight = (int) grid; int y1 = (int) y;// pitchToScreen(pitch); int dd = noteItemHeight / 2 - 1; rectTmp.setBounds((int) x1, (int) y1, noteItemWidth, noteItemHeight); return rectTmp; // return new Rectangle((int) x1, (int) y1 + 1, w, noteItemHeight - 2); } @Override public void selectInRect(Rectangle rect, boolean shift) { Collection<MultiEvent> addTmp = new Vector<MultiEvent>(); Collection<MultiEvent> delTmp = new Vector<MultiEvent>(); Iterable<? extends MultiEvent> list; Part focusPart = project.getPartSelection().getFocus(); if (!(focusPart instanceof MidiPart)) return; /* * if (focusPart != null) list = ((MidiPart) * focusPart).getMultiEvents(); else */ list = notesOnScreen; for (MultiEvent note : list) { if (note instanceof NoteEvent) { if (rect.intersects(getItemBounds((NoteEvent) note))) { if (shift) { if (note.isSelected()) delTmp.add(note); else addTmp.add(note); } else { addTmp.add(note); } } } } project.getMultiEventSelection().removeSelected(delTmp); project.getMultiEventSelection().addSelected(addTmp); project.getMultiEventSelection().notifyListeners(); } @Override protected void writeReleasedAt(Point p) { if (newNote == null) return; newNote.getPart().add(newNote); project.getMultiEventSelection().setSelected(newNote); project.getEditHistoryContainer().notifyEditHistoryListeners(); project.getMultiEventSelection().notifyListeners(); newNote = null; } public synchronized void writeDraggedAt(Point p) { if (newNote == null) return; long tick = screenToTick(p.x, true); long tick1 = newNote.getStartTick(); long tick2 = tick1 + newNote.getDuration(); int pitch = screenToPitch((MidiLane) newNote.getMidiPart().getLane(), p.y); boolean doit = false; if (tick > tick2) { newNote.setDuration(tick - tick1); doit = true; } else if (tick < tick2 && tick > tick1) { newNote.setDuration(tick - tick1); doit = true; } if (pitch != newNote.getNote()) { doit = true; newNote.setNote(pitch); feedBack(newNote); } project.getDragList().notifyFeedbackItemListeners(newNote); if (doit) repaintItems(); } /** * Used by the write tool to insert a note. */ protected synchronized void writePressedAt(Point p) { Part focusPart = project.getPartSelection().getFocus(); if (focusPart == null || !(focusPart instanceof MidiPart)) { System.out.println(" Please slectect a part "); return; } long tick = screenToTick(p.x, true); int pitch = screenToPitch((MidiLane) focusPart.getLane(), p.y); assert (pitch > 0); assert (pitch < 128); project.getEditHistoryContainer().mark( getMessage("sequencer.pianoroll.add_note")); /* * if (drumWriteMode) { newNote = new NoteEvent((MidiPart) focusPart, * tick, pitch, velocity, channel, 0); } else { */ newNote = new NoteEvent((MidiPart) focusPart, tick, pitch, velocity, channel, (long) project.getPianoRollSnapQuantization()); // } feedBack(newNote); project.getDragList().notifyFeedbackItemListeners(newNote); repaintItems(); } public int screenToPitch(MidiLane lane, int y) { Integer cy_o = laneY.get(lane); if (cy_o == null) return 64; int cy = cy_o; ClefChange clef = laneClef.get(lane); float grid = ng.getGridSize(); int n = (int) ((cy - (y - grid * 0.6f)) / (grid * 0.5f)); n -= 4; int note = getNoteFromPos(clef, n); if (note < 0) note = 0; if (note > 127) note = 127; return note; // int note = getNoteFromPos(clef, n) /* * int cy = laneY.get(e.getMidiPart().getLane()); ClefChange clef = * laneClef.get(e.getMidiPart().getLane()); if(clef == null) return * null; int[] n_ret = getNotationNotePos(clef, e.getNote()); int n = * n_ret[0]+4; */ // TODO FINISH WRITING THIS // return 64; } @Override public void rightButtonPressedOnItem(int x, int y) { // TODO Auto-generated method stub } /** * play the note */ public void feedBack(Item item) { audioFeedBack.select((NoteEvent) item); } @Override public void clientAddToSelection(Item item) { project.getPartSelection().setFocus(((MultiEvent) item).getPart()); project.getMultiEventSelection().addSelected((NoteEvent) item); project.getMultiEventSelection().notifyListeners(); } @Override public void clientRemoveFromSelection(Item item) { project.getMultiEventSelection().removeSelected((NoteEvent) item); project.getMultiEventSelection().notifyListeners(); } @Override public void erase(Item it) { NoteEvent note = (NoteEvent) it; editHistory.mark(getMessage("sequencer.pianoroll.erase_note")); note.getPart().remove(note); editHistory.notifyEditHistoryListeners(); } public void fireSequenceDataChanged(EditHistoryAction[] edithistoryEntries) { repaintItems(); } public boolean isValidEvent(MultiEvent event) { return event instanceof NoteEvent; } public void repaintItems() { super.repaintItems(); header.repaint(); } public void dispose() { project.getMultiEventSelection().removeSelectionListener( multiEventListener); project.getPartSelection().removeSelectionListener(partListener); editHistory.removeEditHistoryListener(this); } }