summaryrefslogtreecommitdiff
path: root/muse2
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2011-04-10 15:13:37 +0000
committerFlorian Jung <flo@windfisch.org>2011-04-10 15:13:37 +0000
commite7505b3824fc0ad83c2520a48d26cb0e92ebb583 (patch)
tree91e03b58aa1c93b6b8567c361c3419e7f3659c95 /muse2
parentd1a740d54d4b2438681656970ce0ec5014652804 (diff)
initial commit on branch scoreedit
Diffstat (limited to 'muse2')
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp3038
-rw-r--r--muse2/muse/midiedit/scoreedit.h566
2 files changed, 2191 insertions, 1413 deletions
diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp
index f236a0d5..6a302486 100644
--- a/muse2/muse/midiedit/scoreedit.cpp
+++ b/muse2/muse/midiedit/scoreedit.cpp
@@ -1,13 +1,18 @@
+//change FONT_PATH to the correct directory
+#define FONT_PATH "/home/flo/muse-glyphs/"
+
//=========================================================
// MusE
// Linux Music Editor
-// $Id: ScoreEdit.cpp,v 1.25.2.15 2009/11/16 11:29:33 lunar_shuttle Exp $
-// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+// scoreedit.cpp
+// (C) Copyright 2011 Florian Jung (florian.a.jung@web.de)
//=========================================================
+
#include <QLayout>
#include <QSizeGrip>
#include <QLabel>
+#include <QScrollBar>
#include <QPushButton>
#include <QToolButton>
#include <QToolTip>
@@ -28,6 +33,11 @@
#include <QSettings>
#include <stdio.h>
+#include <math.h>
+
+#include <iostream>
+#include <sstream>
+using namespace std;
#include "xml.h"
#include "mtscale.h"
@@ -51,20 +61,8 @@
#include "mtrackinfo.h"
-int ScoreEdit::_quantInit = 96;
-int ScoreEdit::_rasterInit = 96;
-int ScoreEdit::_widthInit = 600;
-int ScoreEdit::_heightInit = 400;
-int ScoreEdit::_quantStrengthInit = 80; // 1 - 100%
-int ScoreEdit::_quantLimitInit = 50; // tick value
-bool ScoreEdit::_quantLenInit = false;
-int ScoreEdit::_toInit = 0;
-int ScoreEdit::colorModeInit = 0;
+#include "sig.h"
-static const int xscale = -10;
-static const int yscale = 1;
-static const int pianoWidth = 40;
-static int ScoreEditTools = PointerTool | PencilTool | RubberTool | DrawTool;
//---------------------------------------------------------
@@ -72,1340 +70,1850 @@ static int ScoreEditTools = PointerTool | PencilTool | RubberTool | DrawTool;
//---------------------------------------------------------
ScoreEdit::ScoreEdit(PartList* pl, QWidget* parent, const char* name, unsigned initPos)
- : MidiEditor(_quantInit, _rasterInit, pl, parent, name)
- {
- deltaMode = false;
- resize(_widthInit, _heightInit);
- selPart = 0;
- quantConfig = 0;
- _playEvents = false;
- _quantStrength = _quantStrengthInit;
- _quantLimit = _quantLimitInit;
- _quantLen = _quantLenInit;
- _to = _toInit;
- colorMode = colorModeInit;
-
- QSignalMapper* mapper = new QSignalMapper(this);
- QSignalMapper* colorMapper = new QSignalMapper(this);
-
- //---------Menu----------------------------------
-
- menuEdit = menuBar()->addMenu(tr("&Edit"));
-
- menuEdit->addActions(undoRedo->actions());
-
- menuEdit->addSeparator();
-
- editCutAction = menuEdit->addAction(QIcon(*editcutIconSet), tr("C&ut"));
- mapper->setMapping(editCutAction, PianoCanvas::CMD_CUT);
- connect(editCutAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- editCopyAction = menuEdit->addAction(QIcon(*editcopyIconSet), tr("&Copy"));
- mapper->setMapping(editCopyAction, PianoCanvas::CMD_COPY);
- connect(editCopyAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- editPasteAction = menuEdit->addAction(QIcon(*editpasteIconSet), tr("&Paste"));
- mapper->setMapping(editPasteAction, PianoCanvas::CMD_PASTE);
- connect(editPasteAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- menuEdit->addSeparator();
-
- editDelEventsAction = menuEdit->addAction(tr("Delete &Events"));
- mapper->setMapping(editDelEventsAction, PianoCanvas::CMD_DEL);
- connect(editDelEventsAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- menuEdit->addSeparator();
-
- menuSelect = menuEdit->addMenu(QIcon(*selectIcon), tr("&Select"));
-
- selectAllAction = menuSelect->addAction(QIcon(*select_allIcon), tr("Select &All"));
- mapper->setMapping(selectAllAction, PianoCanvas::CMD_SELECT_ALL);
- connect(selectAllAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- selectNoneAction = menuSelect->addAction(QIcon(*select_deselect_allIcon), tr("&Deselect All"));
- mapper->setMapping(selectNoneAction, PianoCanvas::CMD_SELECT_NONE);
- connect(selectNoneAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- selectInvertAction = menuSelect->addAction(QIcon(*select_invert_selectionIcon), tr("Invert &Selection"));
- mapper->setMapping(selectInvertAction, PianoCanvas::CMD_SELECT_INVERT);
- connect(selectInvertAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- menuSelect->addSeparator();
-
- selectInsideLoopAction = menuSelect->addAction(QIcon(*select_inside_loopIcon), tr("&Inside Loop"));
- mapper->setMapping(selectInsideLoopAction, PianoCanvas::CMD_SELECT_ILOOP);
- connect(selectInsideLoopAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- selectOutsideLoopAction = menuSelect->addAction(QIcon(*select_outside_loopIcon), tr("&Outside Loop"));
- mapper->setMapping(selectOutsideLoopAction, PianoCanvas::CMD_SELECT_OLOOP);
- connect(selectOutsideLoopAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- menuSelect->addSeparator();
-
- //selectPrevPartAction = select->addAction(tr("&Previous Part"));
- selectPrevPartAction = menuSelect->addAction(QIcon(*select_all_parts_on_trackIcon), tr("&Previous Part"));
- mapper->setMapping(selectPrevPartAction, PianoCanvas::CMD_SELECT_PREV_PART);
- connect(selectPrevPartAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- //selNextPartAction = select->addAction(tr("&Next Part"));
- selectNextPartAction = menuSelect->addAction(QIcon(*select_all_parts_on_trackIcon), tr("&Next Part"));
- mapper->setMapping(selectNextPartAction, PianoCanvas::CMD_SELECT_NEXT_PART);
- connect(selectNextPartAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- menuConfig = menuBar()->addMenu(tr("&Config"));
-
- eventColor = menuConfig->addMenu(tr("&Event Color"));
-
- QActionGroup* actgrp = new QActionGroup(this);
- actgrp->setExclusive(true);
-
- //evColorBlueAction = eventColor->addAction(tr("&Blue"));
- evColorBlueAction = actgrp->addAction(tr("&Blue"));
- evColorBlueAction->setCheckable(true);
- colorMapper->setMapping(evColorBlueAction, 0);
-
- //evColorPitchAction = eventColor->addAction(tr("&Pitch colors"));
- evColorPitchAction = actgrp->addAction(tr("&Pitch colors"));
- evColorPitchAction->setCheckable(true);
- colorMapper->setMapping(evColorPitchAction, 1);
-
- //evColorVelAction = eventColor->addAction(tr("&Velocity colors"));
- evColorVelAction = actgrp->addAction(tr("&Velocity colors"));
- evColorVelAction->setCheckable(true);
- colorMapper->setMapping(evColorVelAction, 2);
-
- connect(evColorBlueAction, SIGNAL(triggered()), colorMapper, SLOT(map()));
- connect(evColorPitchAction, SIGNAL(triggered()), colorMapper, SLOT(map()));
- connect(evColorVelAction, SIGNAL(triggered()), colorMapper, SLOT(map()));
-
- eventColor->addActions(actgrp->actions());
-
- connect(colorMapper, SIGNAL(mapped(int)), this, SLOT(eventColorModeChanged(int)));
-
- menuFunctions = menuBar()->addMenu(tr("&Functions"));
-
- menuFunctions->setTearOffEnabled(true);
-
- funcOverQuantAction = menuFunctions->addAction(tr("Over Quantize"));
- mapper->setMapping(funcOverQuantAction, PianoCanvas::CMD_OVER_QUANTIZE);
- connect(funcOverQuantAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcNoteOnQuantAction = menuFunctions->addAction(tr("Note On Quantize"));
- mapper->setMapping(funcNoteOnQuantAction, PianoCanvas::CMD_ON_QUANTIZE);
- connect(funcNoteOnQuantAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcNoteOnOffQuantAction = menuFunctions->addAction(tr("Note On/Off Quantize"));
- mapper->setMapping(funcNoteOnOffQuantAction, PianoCanvas::CMD_ONOFF_QUANTIZE);
- connect(funcNoteOnOffQuantAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcIterQuantAction = menuFunctions->addAction(tr("Iterative Quantize"));
- mapper->setMapping(funcIterQuantAction, PianoCanvas::CMD_ITERATIVE_QUANTIZE);
- connect(funcIterQuantAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- menuFunctions->addSeparator();
-
- funcConfigQuantAction = menuFunctions->addAction(tr("Config Quant..."));
- connect(funcConfigQuantAction, SIGNAL(triggered()), this, SLOT(configQuant()));
-
- menuFunctions->addSeparator();
-
- funcGateTimeAction = menuFunctions->addAction(tr("Modify Gate Time"));
- mapper->setMapping(funcGateTimeAction, PianoCanvas::CMD_MODIFY_GATE_TIME);
- connect(funcGateTimeAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcModVelAction = menuFunctions->addAction(tr("Modify Velocity"));
- mapper->setMapping(funcModVelAction, PianoCanvas::CMD_MODIFY_VELOCITY);
- connect(funcModVelAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcCrescendoAction = menuFunctions->addAction(tr("Crescendo"));
- mapper->setMapping(funcCrescendoAction, PianoCanvas::CMD_CRESCENDO);
- funcCrescendoAction->setEnabled(false);
- connect(funcCrescendoAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcTransposeAction = menuFunctions->addAction(tr("Transpose"));
- mapper->setMapping(funcTransposeAction, PianoCanvas::CMD_TRANSPOSE);
- funcTransposeAction->setEnabled(false);
- connect(funcTransposeAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcThinOutAction = menuFunctions->addAction(tr("Thin Out"));
- mapper->setMapping(funcThinOutAction, PianoCanvas::CMD_THIN_OUT);
- funcThinOutAction->setEnabled(false);
- connect(funcThinOutAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcEraseEventAction = menuFunctions->addAction(tr("Erase Event"));
- mapper->setMapping(funcEraseEventAction, PianoCanvas::CMD_ERASE_EVENT);
- funcEraseEventAction->setEnabled(false);
- connect(funcEraseEventAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcNoteShiftAction = menuFunctions->addAction(tr("Note Shift"));
- mapper->setMapping(funcNoteShiftAction, PianoCanvas::CMD_NOTE_SHIFT);
- funcNoteShiftAction->setEnabled(false);
- connect(funcNoteShiftAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcMoveClockAction = menuFunctions->addAction(tr("Move Clock"));
- mapper->setMapping(funcMoveClockAction, PianoCanvas::CMD_MOVE_CLOCK);
- funcMoveClockAction->setEnabled(false);
- connect(funcMoveClockAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcCopyMeasureAction = menuFunctions->addAction(tr("Copy Measure"));
- mapper->setMapping(funcCopyMeasureAction, PianoCanvas::CMD_COPY_MEASURE);
- funcCopyMeasureAction->setEnabled(false);
- connect(funcCopyMeasureAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcEraseMeasureAction = menuFunctions->addAction(tr("Erase Measure"));
- mapper->setMapping(funcEraseMeasureAction, PianoCanvas::CMD_ERASE_MEASURE);
- funcEraseMeasureAction->setEnabled(false);
- connect(funcEraseMeasureAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcDelMeasureAction = menuFunctions->addAction(tr("Delete Measure"));
- mapper->setMapping(funcDelMeasureAction, PianoCanvas::CMD_DELETE_MEASURE);
- funcDelMeasureAction->setEnabled(false);
- connect(funcDelMeasureAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcCreateMeasureAction = menuFunctions->addAction(tr("Create Measure"));
- mapper->setMapping(funcCreateMeasureAction, PianoCanvas::CMD_CREATE_MEASURE);
- funcCreateMeasureAction->setEnabled(false);
- connect(funcCreateMeasureAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcSetFixedLenAction = menuFunctions->addAction(tr("Set Fixed Length"));
- mapper->setMapping(funcSetFixedLenAction, PianoCanvas::CMD_FIXED_LEN);
- connect(funcSetFixedLenAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- funcDelOverlapsAction = menuFunctions->addAction(tr("Delete Overlaps"));
- mapper->setMapping(funcDelOverlapsAction, PianoCanvas::CMD_DELETE_OVERLAPS);
- connect(funcDelOverlapsAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
- menuPlugins = menuBar()->addMenu(tr("&Plugins"));
- song->populateScriptMenu(menuPlugins, this);
-
- connect(mapper, SIGNAL(mapped(int)), this, SLOT(cmd(int)));
-
- //---------ToolBar----------------------------------
- tools = addToolBar(tr("ScoreEdit tools"));
- tools->setObjectName("ScoreEdit tools");
- tools->addActions(undoRedo->actions());
- tools->addSeparator();
-
- srec = new QToolButton();
- srec->setToolTip(tr("Step Record"));
- srec->setIcon(*steprecIcon);
- srec->setCheckable(true);
- tools->addWidget(srec);
-
- midiin = new QToolButton();
- midiin->setToolTip(tr("Midi Input"));
- midiin->setIcon(*midiinIcon);
- midiin->setCheckable(true);
- tools->addWidget(midiin);
-
- speaker = new QToolButton();
- speaker->setToolTip(tr("Play Events"));
- speaker->setIcon(*speakerIcon);
- speaker->setCheckable(true);
- tools->addWidget(speaker);
-
- tools2 = new EditToolBar(this, ScoreEditTools);
- addToolBar(tools2);
-
- QToolBar* panicToolbar = addToolBar(tr("panic"));
- panicToolbar->setObjectName("panic");
- panicToolbar->addAction(panicAction);
-
- //-------------------------------------------------------------
- // Transport Bar
- QToolBar* transport = addToolBar(tr("transport"));
- transport->setObjectName("transport");
- transport->addActions(transportAction->actions());
-
- addToolBarBreak();
- toolbar = new Toolbar1(this, _rasterInit, _quantInit);
- addToolBar(toolbar);
-
- addToolBarBreak();
- info = new NoteInfo(this);
- addToolBar(info);
-
- //---------------------------------------------------
- // split
- //---------------------------------------------------
-
- splitter = new Splitter(Qt::Vertical, mainw, "splitter");
- splitter->setHandleWidth(2);
-
- hsplitter = new Splitter(Qt::Horizontal, mainw, "hsplitter");
- hsplitter->setChildrenCollapsible(true);
- hsplitter->setHandleWidth(2);
-
- QPushButton* ctrl = new QPushButton(tr("ctrl"), mainw);
- //QPushButton* ctrl = new QPushButton(tr("C"), mainw); // Tim.
- ctrl->setObjectName("Ctrl");
- ctrl->setFont(config.fonts[3]);
- ctrl->setToolTip(tr("Add Controller View"));
- hscroll = new ScrollScale(-25, -2, xscale, 20000, Qt::Horizontal, mainw);
- ctrl->setFixedSize(pianoWidth, hscroll->sizeHint().height());
- //ctrl->setFixedSize(pianoWidth / 2, hscroll->sizeHint().height()); // Tim.
-
- // Tim.
- /*
- QPushButton* trackInfoButton = new QPushButton(tr("T"), mainw);
- trackInfoButton->setObjectName("TrackInfo");
- trackInfoButton->setFont(config.fonts[3]);
- trackInfoButton->setToolTip(tr("Show track info"));
- trackInfoButton->setFixedSize(pianoWidth / 2, hscroll->sizeHint().height());
- */
-
- QSizeGrip* corner = new QSizeGrip(mainw);
-
- midiTrackInfo = new MidiTrackInfo(mainw);
- int mtiw = midiTrackInfo->width(); // Save this.
- midiTrackInfo->setMinimumWidth(100);
- //midiTrackInfo->setMaximumWidth(150);
-
- midiTrackInfo->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding));
- infoScroll = new QScrollArea;
- infoScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- infoScroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- infoScroll->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding));
- infoScroll->setWidget(midiTrackInfo);
- infoScroll->setWidgetResizable(true);
- //infoScroll->setVisible(false);
- //infoScroll->setEnabled(false);
-
- //hsplitter->addWidget(midiTrackInfo);
- hsplitter->addWidget(infoScroll); // Tim.
- hsplitter->addWidget(splitter);
-
+ : MidiEditor(0, 0, pl, parent, name)
+{
+// Splitter* hsplitter;
+ QPushButton* ctrl;
+/*
+ hsplitter = new Splitter(Qt::Vertical, mainw, "hsplitter");
+ hsplitter->setHandleWidth(2);
+
+ ctrl = new QPushButton(tr("ctrl"), mainw);
+ ctrl->setObjectName("Ctrl");
+ ctrl->setFont(config.fonts[3]);
+ ctrl->setToolTip(tr("Add Controller View"));
+
+ hsplitter->addWidget(ctrl);
+*/
+ /*
+ QGridLayout* gridS1 = new QGridLayout(mainw);
+ gridS1->setContentsMargins(0, 0, 0, 0);
+
mainGrid->setRowStretch(0, 100);
mainGrid->setColumnStretch(1, 100);
- mainGrid->addWidget(hsplitter, 0, 1, 1, 3);
-
- // Original.
- /*
- mainGrid->setColumnStretch(1, 100);
- mainGrid->addWidget(splitter, 0, 0, 1, 3);
- mainGrid->addWidget(ctrl, 1, 0);
- mainGrid->addWidget(hscroll, 1, 1);
- mainGrid->addWidget(corner, 1, 2, Qt::AlignBottom|Qt::AlignRight);
- */
-
-
- // Tim.
- /*
- mainGrid->setColumnStretch(2, 100);
- mainGrid->addWidget(splitter, 0, 0, 1, 4);
- mainGrid->addWidget(trackInfoButton, 1, 0);
- mainGrid->addWidget(ctrl, 1, 1);
- mainGrid->addWidget(hscroll, 1, 2);
- mainGrid->addWidget(corner, 1, 3, Qt::AlignBottom|Qt::AlignRight);
- */
-
- //mainGrid->addRowSpacing(1, hscroll->sizeHint().height());
- //mainGrid->addItem(new QSpacerItem(0, hscroll->sizeHint().height()), 1, 0); // Orig + Tim.
-
- QWidget* split1 = new QWidget(splitter);
- split1->setObjectName("split1");
- QGridLayout* gridS1 = new QGridLayout(split1);
- gridS1->setContentsMargins(0, 0, 0, 0);
- gridS1->setSpacing(0);
- //Defined and configure your program change bar here.
- //This may well be a copy of MTScale extended for our needs
- time = new MTScale(&_raster, split1, xscale);
- Piano* piano = new Piano(split1, yscale);
- canvas = new PianoCanvas(this, split1, xscale, yscale);
- vscroll = new ScrollScale(-3, 7, yscale, KH * 75, Qt::Vertical, split1);
-
- //setFocusProxy(canvas); // Tim.
-
- int offset = -(config.division/4);
- canvas->setOrigin(offset, 0);
- canvas->setCanvasTools(ScoreEditTools);
- canvas->setFocus();
- connect(canvas, SIGNAL(toolChanged(int)), tools2, SLOT(set(int)));
- time->setOrigin(offset, 0);
gridS1->setRowStretch(2, 100);
gridS1->setColumnStretch(1, 100);
- //gridS1->setColumnStretch(2, 100); // Tim.
-
- gridS1->addWidget(time, 0, 1, 1, 2);
- gridS1->addWidget(hLine(split1), 1, 0, 1, 3);
- gridS1->addWidget(piano, 2, 0);
- gridS1->addWidget(canvas, 2, 1);
- gridS1->addWidget(vscroll, 2, 2);
-
- // Tim.
- /*
- gridS1->addWidget(time, 0, 2, 1, 3);
- gridS1->addWidget(hLine(split1), 1, 1, 1, 4);
- //gridS1->addWidget(infoScroll, 2, 0);
- gridS1->addWidget(infoScroll, 0, 0, 3, 1);
- gridS1->addWidget(piano, 2, 1);
- gridS1->addWidget(canvas, 2, 2);
- gridS1->addWidget(vscroll, 2, 3);
- */
-
- ctrlLane = new Splitter(Qt::Vertical, splitter, "ctrllane");
- QWidget* split2 = new QWidget(splitter);
- split2->setMaximumHeight(hscroll->sizeHint().height());
- split2->setMinimumHeight(hscroll->sizeHint().height());
- QGridLayout* gridS2 = new QGridLayout(split2);
- gridS2->setContentsMargins(0, 0, 0, 0);
- gridS2->setSpacing(0);
- gridS2->setRowStretch(0, 100);
- gridS2->setColumnStretch(1, 100);
- gridS2->addWidget(ctrl, 0, 0);
- gridS2->addWidget(hscroll, 0, 1);
- gridS2->addWidget(corner, 0, 2, Qt::AlignBottom|Qt::AlignRight);
- //splitter->setCollapsible(0, true);
-
- piano->setFixedWidth(pianoWidth);
-
- // Tim.
- QList<int> mops;
- mops.append(mtiw + 30); // 30 for possible scrollbar
- mops.append(width() - mtiw - 30);
- hsplitter->setSizes(mops);
-
- connect(tools2, SIGNAL(toolChanged(int)), canvas, SLOT(setTool(int)));
-
- connect(ctrl, SIGNAL(clicked()), SLOT(addCtrl()));
- //connect(trackInfoButton, SIGNAL(clicked()), SLOT(toggleTrackInfo())); Tim.
- connect(info, SIGNAL(valueChanged(NoteInfo::ValType, int)), SLOT(noteinfoChanged(NoteInfo::ValType, int)));
- connect(vscroll, SIGNAL(scrollChanged(int)), piano, SLOT(setYPos(int)));
- connect(vscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setYPos(int)));
- connect(vscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setYMag(int)));
- connect(vscroll, SIGNAL(scaleChanged(int)), piano, SLOT(setYMag(int)));
-
- connect(hscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setXPos(int)));
- connect(hscroll, SIGNAL(scrollChanged(int)), time, SLOT(setXPos(int)));
-
- connect(hscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setXMag(int)));
- connect(hscroll, SIGNAL(scaleChanged(int)), time, SLOT(setXMag(int)));
-
- connect(canvas, SIGNAL(newWidth(int)), SLOT(newCanvasWidth(int)));
- connect(canvas, SIGNAL(pitchChanged(int)), piano, SLOT(setPitch(int)));
- connect(canvas, SIGNAL(verticalScroll(unsigned)), vscroll, SLOT(setPos(unsigned)));
- connect(canvas, SIGNAL(horizontalScroll(unsigned)),hscroll, SLOT(setPos(unsigned)));
- connect(canvas, SIGNAL(horizontalScrollNoLimit(unsigned)),hscroll, SLOT(setPosNoLimit(unsigned)));
- connect(canvas, SIGNAL(selectionChanged(int, Event&, Part*)), this,
- SLOT(setSelection(int, Event&, Part*)));
-
- connect(piano, SIGNAL(keyPressed(int, int, bool)), canvas, SLOT(pianoPressed(int, int, bool)));
- connect(piano, SIGNAL(keyReleased(int, bool)), canvas, SLOT(pianoReleased(int, bool)));
- connect(srec, SIGNAL(toggled(bool)), SLOT(setSteprec(bool)));
- connect(midiin, SIGNAL(toggled(bool)), canvas, SLOT(setMidiin(bool)));
- connect(speaker, SIGNAL(toggled(bool)), SLOT(setSpeaker(bool)));
- connect(canvas, SIGNAL(followEvent(int)), SLOT(follow(int)));
-
- connect(hscroll, SIGNAL(scaleChanged(int)), SLOT(updateHScrollRange()));
- piano->setYPos(KH * 30);
- canvas->setYPos(KH * 30);
- vscroll->setPos(KH * 30);
- //setSelection(0, 0, 0); //Really necessary? Causes segfault when only 1 item selected, replaced by the following:
- info->setEnabled(false);
-
- connect(song, SIGNAL(songChanged(int)), SLOT(songChanged1(int)));
-
- setWindowTitle(canvas->getCaption());
-
- updateHScrollRange();
- // connect to toolbar
- connect(canvas, SIGNAL(pitchChanged(int)), toolbar, SLOT(setPitch(int)));
- connect(canvas, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
- connect(piano, SIGNAL(pitchChanged(int)), toolbar, SLOT(setPitch(int)));
- connect(time, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
- connect(toolbar, SIGNAL(quantChanged(int)), SLOT(setQuant(int)));
- connect(toolbar, SIGNAL(rasterChanged(int)),SLOT(setRaster(int)));
- connect(toolbar, SIGNAL(toChanged(int)), SLOT(setTo(int)));
- connect(toolbar, SIGNAL(soloChanged(bool)), SLOT(soloChanged(bool)));
-
- setFocusPolicy(Qt::StrongFocus);
- setEventColorMode(colorMode);
-
- QClipboard* cb = QApplication::clipboard();
- connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged()));
-
- clipboardChanged(); // enable/disable "Paste"
- selectionChanged(); // enable/disable "Copy" & "Paste"
- initShortcuts(); // initialize shortcuts
-
- const Pos cpos=song->cPos();
- canvas->setPos(0, cpos.tick(), true);
- canvas->selectAtTick(cpos.tick());
- //canvas->selectFirst();//
-
- unsigned pos=0;
- if(initPos >= MAXINT)
- pos = song->cpos();
- if(pos > MAXINT)
- pos = MAXINT;
- if (pos)
- hscroll->setOffset((int)pos);
-
- if(canvas->track())
- {
- updateTrackInfo();
- toolbar->setSolo(canvas->track()->solo());
- }
-
- QSettings settings("MusE", "MusE-qt");
- //restoreGeometry(settings.value("ScoreEdit/geometry").toByteArray());
- restoreState(settings.value("ScoreEdit/windowState").toByteArray());
-
- }
+*/
-//---------------------------------------------------------
-// songChanged1
-//---------------------------------------------------------
+ ScoreCanvas* test=new ScoreCanvas(this, mainw, 1, 1);
+ QScrollBar* hscroll = new QScrollBar(Qt::Horizontal, mainw);
-void ScoreEdit::songChanged1(int bits)
- {
-
- if (bits & SC_SOLO)
- {
- toolbar->setSolo(canvas->track()->solo());
- return;
- }
- songChanged(bits);
- //trackInfo->songChanged(bits);
- // We'll receive SC_SELECTION if a different part is selected.
- if (bits & SC_SELECTION)
- updateTrackInfo();
- }
-//---------------------------------------------------------
-// configChanged
-//---------------------------------------------------------
+connect(hscroll, SIGNAL(valueChanged(int)), test, SLOT(scroll_event(int)));
+connect(song, SIGNAL(songChanged(int)), test, SLOT(song_changed(int)));
+// mainGrid->setRowStretch(0, 100);
+// mainGrid->setColumnStretch(1, 100);
+ mainGrid->addWidget(test, 0, 0);
+ mainGrid->addWidget(hscroll,1,0);
+
+hscroll->setMinimum(0);
+hscroll->setMaximum(1000);
+hscroll->setPageStep(100);
+// gridS1->addWidget(test,0,0);
+
+// gridS1->addWidget(canvas, 0, 0);
+ // hsplitter->addWidget(test);
+}
-void ScoreEdit::configChanged()
- {
- initShortcuts();
- //trackInfo->updateTrackInfo();
- }
//---------------------------------------------------------
-// updateHScrollRange
+// ~ScoreEdit
//---------------------------------------------------------
-void ScoreEdit::updateHScrollRange()
+ScoreEdit::~ScoreEdit()
{
- int s, e;
- canvas->range(&s, &e);
- // Show one more measure.
- e += AL::sigmap.ticksMeasure(e);
- // Show another quarter measure due to imprecise drawing at canvas end point.
- e += AL::sigmap.ticksMeasure(e) / 4;
- // Compensate for the fixed piano and vscroll widths.
- e += canvas->rmapxDev(pianoWidth - vscroll->width());
- int s1, e1;
- hscroll->range(&s1, &e1);
- if(s != s1 || e != e1)
- hscroll->setRange(s, e);
+
}
-void ScoreEdit::updateTrackInfo()
+
+ScoreCanvas::ScoreCanvas(MidiEditor* pr, QWidget* parent,
+ int sx, int sy) : View(parent, sx, sy)
{
- selected = curCanvasPart()->track();
- if (selected->isMidiTrack()) {
- midiTrackInfo->setTrack(selected);
- ///midiTrackInfo->updateTrackInfo(-1);
- }
+ editor = pr;
+ setFocusPolicy(Qt::StrongFocus);
+ setBg(Qt::white);
+
+ setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
+// setMinimumSize(400,600);
+
+ load_pixmaps();
+
+ x_pos=0;
+
+ song_changed(0);
+//fertig mit aufbereiten
+ cout << "---------------- CALCULATING DONE ------------------" << endl;
+
}
-//---------------------------------------------------------
-// follow
-//---------------------------------------------------------
+void ScoreCanvas::song_changed(int)
+{
+ cout << "song changed!" << endl;
+ pos_add_list.clear();
+ eventlist=createAppropriateEventList(editor->parts(), editor->parts()->begin()->second->track());
+ itemlist=create_itemlist(eventlist);
+ process_itemlist(itemlist); // do note- and rest-grouping and collision avoiding
+ calc_item_pos(itemlist);
+ redraw();
+ cout << "song had changed, recalculation complete" << endl;
+}
-void ScoreEdit::follow(int pos)
- {
- int s, e;
- canvas->range(&s, &e);
+//flo code starting here
- if (pos < e && pos >= s)
- hscroll->setOffset(pos);
- if (pos < s)
- hscroll->setOffset(s);
- }
+string IntToStr(int i)
+{
+ ostringstream s;
+ s<<i;
+ return s.str();
+}
-//---------------------------------------------------------
-// setTime
-//---------------------------------------------------------
-void ScoreEdit::setTime(unsigned tick)
- {
- toolbar->setTime(tick);
- time->setPos(3, tick, false);
- }
-//---------------------------------------------------------
-// ~ScoreEdit
-//---------------------------------------------------------
+void ScoreCanvas::load_pixmaps()
+{
+ pix_whole.load(FONT_PATH "whole.png");
+ pix_half.load(FONT_PATH "half.png");
+ pix_quarter.load(FONT_PATH "quarter.png");
+ pix_r1.load(FONT_PATH "rest1.png");
+ pix_r2.load(FONT_PATH "rest2.png");
+ pix_r4.load(FONT_PATH "rest4.png");
+ pix_r8.load(FONT_PATH "rest8.png");
+ pix_r16.load(FONT_PATH "rest16.png");
+ pix_dot.load(FONT_PATH "dot.png");
+ pix_flag_up[0].load(FONT_PATH "flags8u.png");
+ pix_flag_up[1].load(FONT_PATH "flags16u.png");
+ pix_flag_up[2].load(FONT_PATH "flags32u.png");
+ pix_flag_up[3].load(FONT_PATH "flags64u.png");
+ pix_flag_down[0].load(FONT_PATH "flags8d.png");
+ pix_flag_down[1].load(FONT_PATH "flags16d.png");
+ pix_flag_down[2].load(FONT_PATH "flags32d.png");
+ pix_flag_down[3].load(FONT_PATH "flags64d.png");
+ pix_noacc.load(FONT_PATH "acc_none.png");
+ pix_sharp.load(FONT_PATH "acc_sharp.png");
+ pix_b.load(FONT_PATH "acc_b.png");
+
+ for (int i=0;i<10;i++)
+ pix_num[i].load(QString((string(FONT_PATH "")+IntToStr(i)+string(".png")).c_str()));
+}
-ScoreEdit::~ScoreEdit()
- {
- // undoRedo->removeFrom(tools); // p4.0.6 Removed
- }
-//---------------------------------------------------------
-// cmd
-// pulldown menu commands
-//---------------------------------------------------------
-void ScoreEdit::cmd(int cmd)
- {
- ((PianoCanvas*)canvas)->cmd(cmd, _quantStrength, _quantLimit, _quantLen, _to);
- }
+int modulo(int a, int b) // similar to a % b
+{
+ return (((a%b)+b)%b);
+}
-//---------------------------------------------------------
-// setSelection
-// update Info Line
-//---------------------------------------------------------
+#define DEFAULT_REST_HEIGHT 6 // TODO
-void ScoreEdit::setSelection(int tick, Event& e, Part* p)
- {
- int selections = canvas->selectionSize();
-
- selEvent = e;
- selPart = (MidiPart*)p;
- selTick = tick;
-
- if (selections > 1) {
- info->setEnabled(true);
- info->setDeltaMode(true);
- if (!deltaMode) {
- deltaMode = true;
- info->setValues(0, 0, 0, 0, 0);
- tickOffset = 0;
- lenOffset = 0;
- pitchOffset = 0;
- veloOnOffset = 0;
- veloOffOffset = 0;
- }
- }
- else if (selections == 1) {
- deltaMode = false;
- info->setEnabled(true);
- info->setDeltaMode(false);
- info->setValues(tick,
- selEvent.lenTick(),
- selEvent.pitch(),
- selEvent.velo(),
- selEvent.veloOff());
- }
- else {
- deltaMode = false;
- info->setEnabled(false);
- }
- selectionChanged();
- }
-//---------------------------------------------------------
-// edit currently selected Event
-//---------------------------------------------------------
+bool operator< (const note_pos_t& a, const note_pos_t& b)
+{
+ if (a.height<b.height) return true;
+ if (a.height>b.height) return false;
+ return a.vorzeichen<b.vorzeichen;
+}
-void ScoreEdit::noteinfoChanged(NoteInfo::ValType type, int val)
- {
- int selections = canvas->selectionSize();
-
- if (selections == 0) {
- printf("noteinfoChanged while nothing selected\n");
- }
- else if (selections == 1) {
- Event event = selEvent.clone();
- switch(type) {
- case NoteInfo::VAL_TIME:
- event.setTick(val - selPart->tick());
- break;
- case NoteInfo::VAL_LEN:
- event.setLenTick(val);
- break;
- case NoteInfo::VAL_VELON:
- event.setVelo(val);
- break;
- case NoteInfo::VAL_VELOFF:
- event.setVeloOff(val);
- break;
- case NoteInfo::VAL_PITCH:
- event.setPitch(val);
- break;
- }
- // Indicate do undo, and do not do port controller values and clone parts.
- //audio->msgChangeEvent(selEvent, event, selPart);
- audio->msgChangeEvent(selEvent, event, selPart, true, false, false);
- }
- else {
- // multiple events are selected; treat noteinfo values
- // as offsets to event values
-
- int delta = 0;
- switch (type) {
- case NoteInfo::VAL_TIME:
- delta = val - tickOffset;
- tickOffset = val;
- break;
- case NoteInfo::VAL_LEN:
- delta = val - lenOffset;
- lenOffset = val;
- break;
- case NoteInfo::VAL_VELON:
- delta = val - veloOnOffset;
- veloOnOffset = val;
- break;
- case NoteInfo::VAL_VELOFF:
- delta = val - veloOffOffset;
- veloOffOffset = val;
- break;
- case NoteInfo::VAL_PITCH:
- delta = val - pitchOffset;
- pitchOffset = val;
- break;
- }
- if (delta)
- canvas->modifySelected(type, delta);
- }
- }
-//---------------------------------------------------------
-// addCtrl
-//---------------------------------------------------------
+//TODO: all das unten richtig machen!
+#define TICKS_PER_WHOLE (config.division*4)
+#define SONG_LENGTH (TICKS_PER_WHOLE*8)
+
+#define quant_max 3 //whole, half, quarter = 0,1,2
+#define quant_max_fraction (1 << quant_max) //whole, half, quarter= 1,2,4
+#define FLO_QUANT (TICKS_PER_WHOLE/quant_max_fraction)
+//FLO_QUANT = how many ticks has a single quantisation area?
+
+
+//FINDMICH MARKER
+//TODO: quant_max richtig setzen!
+
+/* builds the event list used by the score editor.
+ * that list contains only note-on and -off, time-sig- and
+ * key-change events.
+ * it stores them sorted by their time (quantized); if more
+ * events with the same time occur, the NOTE-OFFs are
+ * put before the NOTE-ONs
+ * it only operates on parts which a) are selected by the
+ * editor and b) belong to track
+ *
+ * this abstracts the rest of the renderer from muse's internal
+ * data structures, making this easy to port to another application
+ */
+ScoreEventList ScoreCanvas::createAppropriateEventList(PartList* pl, Track* track)
+{
+ using AL::sigmap;
+ using AL::iSigEvent;
+
+ ScoreEventList result;
+
+ //insert note on/off events
+ for (iPart partIt=pl->begin(); partIt!=pl->end(); partIt++)
+ {
+ Part* part=partIt->second;
+ if (part->track()==track)
+ {
+ EventList* el=part->events();
+
+ for (iEvent it=el->begin(); it!=el->end(); it++)
+ {
+ Event& event=it->second;
+
+ if (event.isNote() && !event.isNoteOff())
+ {
+ unsigned begin, end;
+ //TODO quantizing must be done with the proper functions!
+ begin=int(rint((float)event.tick() / FLO_QUANT))*FLO_QUANT;
+ end=int(rint((float)event.endTick() / FLO_QUANT))*FLO_QUANT;
+ cout <<"inserting note on at "<<begin<<" with pitch="<<event.pitch()<<" and len="<<end-begin<<endl;
+ cout<< "\tinserting corresponding note off at "<<endl;
+ result.insert(pair<unsigned, FloEvent>(begin, FloEvent(begin,event.pitch(), event.velo(),end-begin,FloEvent::NOTE_ON,part,&it->second)));
+ result.insert(pair<unsigned, FloEvent>(end, FloEvent(end,event.pitch(), event.veloOff(),0,FloEvent::NOTE_OFF,part,&it->second)));
+ }
+ //else ignore it
+ }
+ }
+ //else ignore it
+ }
+
+ //insert bars and time signatures
+ for (iSigEvent it=sigmap.begin(); it!=sigmap.end(); it++)
+ {
+ unsigned from=it->second->tick;
+ unsigned to=it->first;
+ unsigned ticks_per_measure=sigmap.ticksMeasure(it->second->tick);
+
+ if (to > unsigned(SONG_LENGTH))
+ {
+ cout << "time signature's end-of-validness is outside of our song, limiting it." << endl;
+ to=SONG_LENGTH;
+ }
+
+ cout << "new signature from tick "<<from<<" to " << to << ": "<<it->second->sig.z<<"/"<<it->second->sig.n<<"; ticks per measure = "<<ticks_per_measure<<endl;
+ result.insert(pair<unsigned, FloEvent>(from, FloEvent(from, FloEvent::TIME_SIG, it->second->sig.z, it->second->sig.n) ) );
+ for (unsigned t=from; t<to; t+=ticks_per_measure)
+ result.insert(pair<unsigned, FloEvent>(t, FloEvent(t,0,0,ticks_per_measure,FloEvent::BAR) ) );
+ }
+
+
+ //TODO FINDMICH MARKER
+ result.insert(pair<unsigned, FloEvent>(0, FloEvent(0,FloEvent::KEY_CHANGE, C ) ) );
+
+ return result;
+}
-CtrlEdit* ScoreEdit::addCtrl()
- {
- ///CtrlEdit* ctrlEdit = new CtrlEdit(splitter, this, xscale, false, "pianoCtrlEdit");
- CtrlEdit* ctrlEdit = new CtrlEdit(ctrlLane/*splitter*/, this, xscale, false, "pianoCtrlEdit"); // ccharrett
- connect(tools2, SIGNAL(toolChanged(int)), ctrlEdit, SLOT(setTool(int)));
- connect(hscroll, SIGNAL(scrollChanged(int)), ctrlEdit, SLOT(setXPos(int)));
- connect(hscroll, SIGNAL(scaleChanged(int)), ctrlEdit, SLOT(setXMag(int)));
- connect(ctrlEdit, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
- connect(ctrlEdit, SIGNAL(destroyedCtrl(CtrlEdit*)), SLOT(removeCtrl(CtrlEdit*)));
- connect(ctrlEdit, SIGNAL(yposChanged(int)), toolbar, SLOT(setInt(int)));
-
- ctrlEdit->setTool(tools2->curTool());
- ctrlEdit->setXPos(hscroll->pos());
- ctrlEdit->setXMag(hscroll->getScaleValue());
-
- ctrlEdit->show();
- ctrlEditList.push_back(ctrlEdit);
- return ctrlEdit;
- }
-//---------------------------------------------------------
-// removeCtrl
-//---------------------------------------------------------
+bool is_sharp_key(tonart_t t)
+{
+ return ((t>=SHARP_BEGIN) && (t<=SHARP_END));
+}
+bool is_b_key(tonart_t t)
+{
+ return ((t>=B_BEGIN) && (t<=B_END));
+}
-void ScoreEdit::removeCtrl(CtrlEdit* ctrl)
- {
- for (std::list<CtrlEdit*>::iterator i = ctrlEditList.begin();
- i != ctrlEditList.end(); ++i) {
- if (*i == ctrl) {
- ctrlEditList.erase(i);
- break;
- }
- }
- }
+int n_accidentials(tonart_t t)
+{
+ if (is_sharp_key(t))
+ return t-SHARP_BEGIN-1;
+ else
+ return t-B_BEGIN-1;
+}
-//---------------------------------------------------------
-// closeEvent
-//---------------------------------------------------------
-void ScoreEdit::closeEvent(QCloseEvent* e)
- {
- QSettings settings("MusE", "MusE-qt");
- //settings.setValue("ScoreEdit/geometry", saveGeometry());
- settings.setValue("ScoreEdit/windowState", saveState());
+//note needs to be 0..11
+note_pos_t ScoreCanvas::note_pos_(int note, tonart_t key)
+{
+ note_pos_t result;
+ //C CIS D DIS E F FIS G GIS A AIS H
+ int foo[12]={0,-1, 1,-1, 2,3,-1, 4,-1, 5, -1,6};
+
+ if ((note<0) || (note>=12))
+ cout << "WARNING: ILLEGAL FUNCTION CALL (note_pos, note out of range)" << endl;
+
+ if (foo[note]!=-1)
+ {
+ result.height=foo[note];
+ result.vorzeichen=NONE;
+ }
+ else
+ {
+ if (is_sharp_key(key))
+ {
+ result.height=foo[note-1];
+ result.vorzeichen=SHARP;
+ }
+ else // if is_b_key
+ {
+ result.height=foo[note+1];
+ result.vorzeichen=B;
+ }
+ }
+
+ // Special cases for GES / FIS keys
+ if (key==GES)
+ {
+ // convert a H to a Ces
+ if (note==11)
+ {
+ result.height=12;
+ result.vorzeichen=B;
+ }
+ }
+ else if (key==FIS)
+ {
+ // convert a F to an Eis
+ if (note==5)
+ {
+ result.height=2;
+ result.vorzeichen=SHARP;
+ }
+ }
+
+ return result;
+}
- emit deleted((unsigned long)this);
- e->accept();
- }
-//---------------------------------------------------------
-// readConfiguration
-//---------------------------------------------------------
+// V -------------------------- <-- height=10
+// I C -------------------------- <-- height=8
+// O L -------------------------- <-- height=6
+// L E -------------------------- <-- height=4
+// I F -------------------------- <-- height=2
+// N --o-- <-- this is C4. height=0
-void ScoreEdit::readConfiguration(Xml& xml)
- {
- for (;;) {
- Xml::Token token = xml.parse();
- if (token == Xml::Error || token == Xml::End)
- break;
- const QString& tag = xml.s1();
- switch (token) {
- case Xml::TagStart:
- if (tag == "quant")
- _quantInit = xml.parseInt();
- else if (tag == "raster")
- _rasterInit = xml.parseInt();
- else if (tag == "quantStrength")
- _quantStrengthInit = xml.parseInt();
- else if (tag == "quantLimit")
- _quantLimitInit = xml.parseInt();
- else if (tag == "quantLen")
- _quantLenInit = xml.parseInt();
- else if (tag == "to")
- _toInit = xml.parseInt();
- else if (tag == "colormode")
- colorModeInit = xml.parseInt();
- else if (tag == "width")
- _widthInit = xml.parseInt();
- else if (tag == "height")
- _heightInit = xml.parseInt();
- else
- xml.unknown("ScoreEdit");
- break;
- case Xml::TagEnd:
- if (tag == "ScoreEdit")
- return;
- default:
- break;
- }
- }
- }
+// the "spaces" in between the lines have odd numbers.
+// that is, the space between line 2 and 4 is numbered 3.
-//---------------------------------------------------------
-// writeConfiguration
-//---------------------------------------------------------
+// these numbers do not change when clef changes. line 2
+// is always the "bottom line" of the system.
+// in violin clef, line 2 is E4
+// in bass clef, line 2 is G2
-void ScoreEdit::writeConfiguration(int level, Xml& xml)
- {
- xml.tag(level++, "ScoreEdit");
- xml.intTag(level, "quant", _quantInit);
- xml.intTag(level, "raster", _rasterInit);
- xml.intTag(level, "quantStrength", _quantStrengthInit);
- xml.intTag(level, "quantLimit", _quantLimitInit);
- xml.intTag(level, "quantLen", _quantLenInit);
- xml.intTag(level, "to", _toInit);
- xml.intTag(level, "width", _widthInit);
- xml.intTag(level, "height", _heightInit);
- xml.intTag(level, "colormode", colorModeInit);
- xml.etag(level, "ScoreEdit");
- }
+note_pos_t ScoreCanvas::note_pos (int note, tonart_t key, clef_t clef)
+{
+ int octave=(note/12)-1; //integer division
+ note=note%12;
+
+ //now octave contains the octave the note is in
+ //(A4 is the 440Hz tone. C4 is the "low C" in the violin clef
+ //and the "high C" in the bass clef.
+ //note contains 0 for C, 1 for Cis, ..., 11 for H (or B if you're not german)
+
+ note_pos_t pos=note_pos_(note,key);
+
+ switch (clef)
+ {
+ case VIOLIN:
+ pos.height=pos.height + (octave-4)*7;
+ break;
+
+ case BASS:
+ pos.height=pos.height + (octave-3)*7 + 5;
+ break;
+ }
+
+ return pos;
+}
-//---------------------------------------------------------
-// soloChanged
-// signal from solo button
-//---------------------------------------------------------
-void ScoreEdit::soloChanged(bool flag)
- {
- audio->msgSetSolo(canvas->track(), flag);
- song->update(SC_SOLO);
- }
+int ScoreCanvas::calc_len(int l, int d)
+{
+ // l=0,1,2 -> whole, half, quarter (think of 2^0, 2^1, 2^2)
+ // d=number of dots
+
+ int tmp=0;
+ for (int i=0;i<=d;i++)
+ tmp+=TICKS_PER_WHOLE / pow(2, l+i);
+
+ return tmp;
+}
-//---------------------------------------------------------
-// setRaster
-//---------------------------------------------------------
+bool operator< (const note_len_t& a,const note_len_t& b) //TODO sane sorting order
+{
+ if (a.len<b.len) return true;
+ else if (a.dots<b.dots) return true;
+ else return false;
+}
-void ScoreEdit::setRaster(int val)
- {
- _rasterInit = val;
- MidiEditor::setRaster(val);
- canvas->redrawGrid();
- canvas->setFocus(); // give back focus after kb input
- }
+//quant_max must be in log(len), that is
+//whole, half, quarter, eighth = 0,1,2,3
+//NOT: 1,2,4,8! (think of 2^foo)
+//len is in ticks
+list<note_len_t> ScoreCanvas::parse_note_len(int len_ticks, bool allow_dots, bool allow_normal, int begin_tick)
+{
+ list<note_len_t> retval;
+
+ if (allow_normal)
+ {
+ int dot_max = allow_dots ? quant_max : 0;
+
+ for (int i=0;i<=quant_max;i++)
+ for (int j=0;j<=dot_max-i;j++)
+ if (calc_len(i,j) == len_ticks)
+ {
+ retval.push_back(note_len_t (i,j));
+ return retval;
+ }
+ }
+
+ //if !allow_normal or if the above failed
+
+ // 1 e + e 2 e + e 3 e + e 4 e + e
+ int foo[]={1,7,6,7,5,7,6,7,4,7,6,7,5,7,6,7,3,7,6,7,5,7,6,7,4,7,6,7,5,7,6,7,2,7,6,7,5,7,6,7,4,7,6,7,5,7,6,7,3,7,6,7,5,7,6,7,4,7,6,7,5,7,6,7};
+ #define foo_len (sizeof(foo)/sizeof(*foo))
+
+ int begin=begin_tick * 64 / TICKS_PER_WHOLE;
+ int len=len_ticks * 64 / TICKS_PER_WHOLE;
+
+ int pos=begin;
+ int len_done=0;
+
+ while (len_done<len)
+ {
+ int len_now=0;
+ int last_number=foo[pos];
+
+ while (! ((foo[pos]<last_number) || (len_done==len) || (pos==foo_len)) ) {pos++;len_done++;len_now++;}
+
+ len_now=len_now*TICKS_PER_WHOLE/64;
+
+ cout << "add " << len_now << " ticks" << endl;
+ for (int i=0; i<=quant_max; i++)
+ {
+ int tmp=calc_len(i,0);
+ if (tmp <= len_now)
+ {
+ retval.push_back(note_len_t(i));
+ len_now-=tmp;
+ if (len_now==0) break;
+ }
+ }
+
+ if (len_now!=0)
+ cout << "WARNING: THIS SHOULD NEVER HAPPEN. wasn't able to split note len properly; len_now="<<len_now << endl;
+
+ if (pos==foo_len) //we cross measure boundaries?
+ pos=0;
+ }
+
+
+ return retval;
+}
-//---------------------------------------------------------
-// setQuant
-//---------------------------------------------------------
-void ScoreEdit::setQuant(int val)
- {
- _quantInit = val;
- MidiEditor::setQuant(val);
- canvas->setFocus();
- }
-//---------------------------------------------------------
-// writeStatus
-//---------------------------------------------------------
+#define YLEN 10
+#define YDIST (2*YLEN)
+#define NOTE_XLEN 10
+#define NOTE_SHIFT 3
+#define PIXELS_PER_WHOLE (320) //how many px are between two wholes?
+#define PIXELS_PER_NOTEPOS (PIXELS_PER_WHOLE/quant_max_fraction) //how many px are between the smallest drawn beats?
-void ScoreEdit::writeStatus(int level, Xml& xml) const
- {
- writePartList(level, xml);
- xml.tag(level++, "ScoreEdit");
- MidiEditor::writeStatus(level, xml);
- splitter->writeStatus(level, xml);
- hsplitter->writeStatus(level, xml);
-
- for (std::list<CtrlEdit*>::const_iterator i = ctrlEditList.begin();
- i != ctrlEditList.end(); ++i) {
- (*i)->writeStatus(level, xml);
- }
-
- xml.intTag(level, "steprec", canvas->steprec());
- xml.intTag(level, "midiin", canvas->midiin());
- xml.intTag(level, "tool", int(canvas->tool()));
- xml.intTag(level, "quantStrength", _quantStrength);
- xml.intTag(level, "quantLimit", _quantLimit);
- xml.intTag(level, "quantLen", _quantLen);
- xml.intTag(level, "playEvents", _playEvents);
- xml.intTag(level, "xpos", hscroll->pos());
- xml.intTag(level, "xmag", hscroll->mag());
- xml.intTag(level, "ypos", vscroll->pos());
- xml.intTag(level, "ymag", vscroll->mag());
- xml.tag(level, "/ScoreEdit");
- }
+//PIXELS_PER_NOTEPOS must be greater or equal to 3*NOTE_XLEN + 2*NOTE_SHIFT
+//because if tick 0 is at x=0: the notes can be shifted by NOTE_SHIFT.
+//additionally, they can be moved by NOTE_XLEN (collision avoiding)
+//then, they have their own width, which is NOTE_XLEN/2 into the x>0-area
+//the same thing applies to the x<0-area
-//---------------------------------------------------------
-// readStatus
-//---------------------------------------------------------
+// OOO
+// |
+// ^actual calculated x, without shifting or moving
+// ^ and
+// ^ : moved note (by XLEN)
+// additionally, a shift is possible
+// total_width = shift + move + note_xlen + move + shift, where move==note_xlen
+// total_width = 2*shift + 3*note_xlen
+// if total_width is greater than px_per_notepos, there will be collisions!
-void ScoreEdit::readStatus(Xml& xml)
- {
- for (;;) {
- Xml::Token token = xml.parse();
- if (token == Xml::Error || token == Xml::End)
- break;
- const QString& tag = xml.s1();
- switch (token) {
- case Xml::TagStart:
- if (tag == "steprec") {
- int val = xml.parseInt();
- canvas->setSteprec(val);
- srec->setChecked(val);
- }
- else if (tag == "midiin") {
- int val = xml.parseInt();
- canvas->setMidiin(val);
- midiin->setChecked(val);
- }
- else if (tag == "tool") {
- int tool = xml.parseInt();
- canvas->setTool(tool);
- tools2->set(tool);
- }
- else if (tag == "midieditor")
- MidiEditor::readStatus(xml);
- else if (tag == "ctrledit") {
- CtrlEdit* ctrl = addCtrl();
- ctrl->readStatus(xml);
- }
- else if (tag == splitter->objectName())
- splitter->readStatus(xml);
- else if (tag == hsplitter->objectName())
- hsplitter->readStatus(xml);
- else if (tag == "quantStrength")
- _quantStrength = xml.parseInt();
- else if (tag == "quantLimit")
- _quantLimit = xml.parseInt();
- else if (tag == "quantLen")
- _quantLen = xml.parseInt();
- else if (tag == "playEvents") {
- _playEvents = xml.parseInt();
- canvas->playEvents(_playEvents);
- speaker->setChecked(_playEvents);
- }
- else if (tag == "xmag")
- hscroll->setMag(xml.parseInt());
- else if (tag == "xpos")
- hscroll->setPos(xml.parseInt());
- else if (tag == "ymag")
- vscroll->setMag(xml.parseInt());
- else if (tag == "ypos")
- vscroll->setPos(xml.parseInt());
- else
- xml.unknown("ScoreEdit");
- break;
- case Xml::TagEnd:
- if (tag == "ScoreEdit") {
- _quantInit = _quant;
- _rasterInit = _raster;
- toolbar->setRaster(_raster);
- toolbar->setQuant(_quant);
- canvas->redrawGrid();
- return;
- }
- default:
- break;
- }
- }
- }
-
-static int rasterTable[] = {
- //-9----8- 7 6 5 4 3(1/4) 2 1
- 4, 8, 16, 32, 64, 128, 256, 512, 1024, // triple
- 6, 12, 24, 48, 96, 192, 384, 768, 1536,
- 9, 18, 36, 72, 144, 288, 576, 1152, 2304 // dot
- };
+#define NOTE_MOVE_X (PIXELS_PER_NOTEPOS/2)
+//TODO richtige werte finden!
+#define REST_AUSWEICH_X 10
+#define DOT_XDIST 6
+#define DOT_XBEGIN 10
+#define DOT_XBEGIN_REST 10
-//---------------------------------------------------------
-// viewKeyPressEvent
-//---------------------------------------------------------
+#define TIMESIG_POSADD 20
+#define NUMBER_HEIGHT (pix_num[0].height())
-void ScoreEdit::keyPressEvent(QKeyEvent* event)
- {
- if (info->hasFocus()) {
- event->ignore();
- return;
- }
-
- int index;
- int n = sizeof(rasterTable)/sizeof(*rasterTable);
- for (index = 0; index < n; ++index)
- if (rasterTable[index] == raster())
- break;
- if (index == n) {
- index = 0;
- // raster 1 is not in table
- }
- int off = (index / 9) * 9;
- index = index % 9;
-
- int val = 0;
-
- PianoCanvas* pc = (PianoCanvas*)canvas;
- int key = event->key();
-
- //if (event->state() & Qt::ShiftButton)
- if (((QInputEvent*)event)->modifiers() & Qt::ShiftModifier)
- key += Qt::SHIFT;
- //if (event->state() & Qt::AltButton)
- if (((QInputEvent*)event)->modifiers() & Qt::AltModifier)
- key += Qt::ALT;
- //if (event->state() & Qt::ControlButton)
- if (((QInputEvent*)event)->modifiers() & Qt::ControlModifier)
- key+= Qt::CTRL;
-
- if (key == Qt::Key_Escape) {
- close();
- return;
- }
- else if (key == shortcuts[SHRT_TOOL_POINTER].key) {
- tools2->set(PointerTool);
- return;
- }
- else if (key == shortcuts[SHRT_TOOL_PENCIL].key) {
- tools2->set(PencilTool);
- return;
- }
- else if (key == shortcuts[SHRT_TOOL_RUBBER].key) {
- tools2->set(RubberTool);
- return;
- }
- else if (key == shortcuts[SHRT_TOOL_LINEDRAW].key) {
- tools2->set(DrawTool);
- return;
- }
- else if (key == shortcuts[SHRT_POS_INC].key) {
- pc->pianoCmd(CMD_RIGHT);
- return;
- }
- else if (key == shortcuts[SHRT_POS_DEC].key) {
- pc->pianoCmd(CMD_LEFT);
- return;
- }
- else if (key == shortcuts[SHRT_POS_INC_NOSNAP].key) {
- pc->pianoCmd(CMD_RIGHT_NOSNAP);
- return;
- }
- else if (key == shortcuts[SHRT_POS_DEC_NOSNAP].key) {
- pc->pianoCmd(CMD_LEFT_NOSNAP);
- return;
- }
- else if (key == shortcuts[SHRT_INSERT_AT_LOCATION].key) {
- pc->pianoCmd(CMD_INSERT);
- return;
- }
- else if (key == Qt::Key_Delete) {
- pc->pianoCmd(CMD_DELETE);
- return;
- }
- else if (key == shortcuts[SHRT_ZOOM_IN].key) {
- int mag = hscroll->mag();
- int zoomlvl = ScrollScale::getQuickZoomLevel(mag);
- if (zoomlvl < 23)
- zoomlvl++;
-
- int newmag = ScrollScale::convertQuickZoomLevelToMag(zoomlvl);
- hscroll->setMag(newmag);
- //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag);
- return;
- }
- else if (key == shortcuts[SHRT_ZOOM_OUT].key) {
- int mag = hscroll->mag();
- int zoomlvl = ScrollScale::getQuickZoomLevel(mag);
- if (zoomlvl > 1)
- zoomlvl--;
-
- int newmag = ScrollScale::convertQuickZoomLevelToMag(zoomlvl);
- hscroll->setMag(newmag);
- //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag);
- return;
- }
- else if (key == shortcuts[SHRT_GOTO_CPOS].key) {
- PartList* p = this->parts();
- Part* first = p->begin()->second;
- hscroll->setPos(song->cpos() - first->tick() );
- return;
- }
- else if (key == shortcuts[SHRT_SCROLL_LEFT].key) {
- int pos = hscroll->pos() - config.division;
- if (pos < 0)
- pos = 0;
- hscroll->setPos(pos);
- return;
- }
- else if (key == shortcuts[SHRT_SCROLL_RIGHT].key) {
- int pos = hscroll->pos() + config.division;
- hscroll->setPos(pos);
- return;
- }
- else if (key == shortcuts[SHRT_SET_QUANT_1].key)
- val = rasterTable[8 + off];
- else if (key == shortcuts[SHRT_SET_QUANT_2].key)
- val = rasterTable[7 + off];
- else if (key == shortcuts[SHRT_SET_QUANT_3].key)
- val = rasterTable[6 + off];
- else if (key == shortcuts[SHRT_SET_QUANT_4].key)
- val = rasterTable[5 + off];
- else if (key == shortcuts[SHRT_SET_QUANT_5].key)
- val = rasterTable[4 + off];
- else if (key == shortcuts[SHRT_SET_QUANT_6].key)
- val = rasterTable[3 + off];
- else if (key == shortcuts[SHRT_SET_QUANT_7].key)
- val = rasterTable[2 + off];
- else if (key == shortcuts[SHRT_TOGGLE_TRIOL].key)
- val = rasterTable[index + ((off == 0) ? 9 : 0)];
- else if (key == shortcuts[SHRT_EVENT_COLOR].key) {
- if (colorMode == 0)
- colorMode = 1;
- else if (colorMode == 1)
- colorMode = 2;
- else
- colorMode = 0;
- setEventColorMode(colorMode);
- return;
- }
- else if (key == shortcuts[SHRT_TOGGLE_PUNCT].key)
- val = rasterTable[index + ((off == 18) ? 9 : 18)];
-
- else if (key == shortcuts[SHRT_TOGGLE_PUNCT2].key) {//CDW
- if ((off == 18) && (index > 2)) {
- val = rasterTable[index + 9 - 1];
- }
- else if ((off == 9) && (index < 8)) {
- val = rasterTable[index + 18 + 1];
- }
- else
- return;
- }
- else { //Default:
- event->ignore();
- return;
- }
- setQuant(val);
- setRaster(val);
- toolbar->setQuant(_quant);
- toolbar->setRaster(_raster);
- }
+//kann 0 oder 1 sein:
+//bei notenkollisionen mit ungerader anzahl von kollidierenden
+//wird immer so ausgewichen, dass möglichst wenige ausweichen müssen
+//wenn die anzahl aber gerade ist, gibt es keine "bessere" lösung
+//in dem fall werden immer die geraden (0) bzw. ungeraden (1)
+//ausweichen.
+#define AUSWEICHEN_BEVORZUGT 0
-//---------------------------------------------------------
-// configQuant
-//---------------------------------------------------------
+#define STEM_LEN 30
-void ScoreEdit::configQuant()
- {
- if (!quantConfig) {
- quantConfig = new QuantConfig(_quantStrength, _quantLimit, _quantLen);
- connect(quantConfig, SIGNAL(setQuantStrength(int)), SLOT(setQuantStrength(int)));
- connect(quantConfig, SIGNAL(setQuantLimit(int)), SLOT(setQuantLimit(int)));
- connect(quantConfig, SIGNAL(setQuantLen(bool)), SLOT(setQuantLen(bool)));
- }
- quantConfig->show();
- }
+#define DOTTED_RESTS true
+#define UNSPLIT_RESTS true
-//---------------------------------------------------------
-// setSteprec
-//---------------------------------------------------------
+#define AUX_LINE_LEN 1.5
-void ScoreEdit::setSteprec(bool flag)
- {
- canvas->setSteprec(flag);
- if (flag == false)
- midiin->setChecked(flag);
- }
+#define ACCIDENTIAL_DIST 11
+#define KEYCHANGE_ACC_DIST 9
+#define KEYCHANGE_ACC_LEFTDIST 3
+#define KEYCHANGE_ACC_RIGHTDIST 3
-//---------------------------------------------------------
-// eventColorModeChanged
-//---------------------------------------------------------
-void ScoreEdit::eventColorModeChanged(int mode)
- {
- colorMode = mode;
- colorModeInit = colorMode;
-
- ((PianoCanvas*)(canvas))->setColorMode(colorMode);
- }
+#define stdmap std::map
-//---------------------------------------------------------
-// setEventColorMode
-//---------------------------------------------------------
+#define no_notepos note_pos_t()
-void ScoreEdit::setEventColorMode(int mode)
- {
- colorMode = mode;
- colorModeInit = colorMode;
-
- ///eventColor->setItemChecked(0, mode == 0);
- ///eventColor->setItemChecked(1, mode == 1);
- ///eventColor->setItemChecked(2, mode == 2);
- evColorBlueAction->setChecked(mode == 0);
- evColorPitchAction->setChecked(mode == 1);
- evColorVelAction->setChecked(mode == 2);
-
- ((PianoCanvas*)(canvas))->setColorMode(colorMode);
- }
+#define TIE_DIST 5
+#define TIE_HEIGHT 6
+#define TIE_THICKNESS 3
-//---------------------------------------------------------
-// clipboardChanged
-//---------------------------------------------------------
+void ScoreCanvas::draw_tie (QPainter& p, int x1, int x4, int yo, bool up)
+{
+ QPainterPath path;
+
+ int y1, y2, y3;
+
+ if (up)
+ {
+ y1 = yo - TIE_DIST;
+ y2 = y1 - TIE_HEIGHT;
+ y3=y2-TIE_THICKNESS;
+ }
+ else
+ {
+ y1 = yo + TIE_DIST;
+ y2 = y1 + TIE_HEIGHT;
+ y3=y2+TIE_THICKNESS;
+ }
+
+ int x2 = x1 + (x4-x1)/4;
+ int x3 = x4 - (x4-x1)/4;
+
+ path.moveTo(x1,y1);
+ path.cubicTo( x2,y2 , x3,y2 , x4,y1 );
+ path.cubicTo( x3,y3 , x2,y3 , x1,y1 );
+
+ p.setPen(Qt::black);
+ p.setBrush(Qt::black);
+
+ p.drawPath(path);
+}
-void ScoreEdit::clipboardChanged()
- {
- editPasteAction->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-eventlist")));
- }
+ScoreItemList ScoreCanvas::create_itemlist(ScoreEventList& eventlist)
+{
+ ScoreItemList itemlist;
+ tonart_t tmp_key=C;
+ int lastevent=0;
+ int next_measure=-1;
+
+ for (ScoreEventList::iterator it=eventlist.begin(); it!=eventlist.end(); it++)
+ {
+ int t, pitch, len, velo, actual_tick;
+ FloEvent::typeEnum type;
+ t=it->first;
+ pitch=it->second.pitch;
+ velo=it->second.vel;
+ len=it->second.len;
+ type=it->second.type;
+ actual_tick=it->second.tick;
+ if (actual_tick==-1) actual_tick=t;
+
+ note_pos_t notepos=note_pos(pitch,tmp_key,VIOLIN); //TODO einstellmöglichkeiten
+
+ printf("FLO: t=%i\ttype=%i\tpitch=%i\tvel=%i\tlen=%i\n",it->first, it->second.type, it->second.pitch, it->second.vel, it->second.len);
+ cout << "\tline="<<notepos.height<<"\tvorzeichen="<<notepos.vorzeichen << endl;
+
+
+ if (type==FloEvent::BAR)
+ {
+ // if neccessary, insert rest at between last note and end-of-measure
+ int rest=t-lastevent;
+ if (rest)
+ {
+ printf("\tend-of-measure: set rest at %i with len %i\n",lastevent,rest);
+
+ list<note_len_t> lens=parse_note_len(rest,DOTTED_RESTS,UNSPLIT_RESTS,lastevent);
+ unsigned tmppos=lastevent;
+ for (list<note_len_t>::iterator x=lens.begin(); x!=lens.end(); x++)
+ {
+ cout << "\t\tpartial rest with len="<<x->len<<", dots="<<x->dots<<endl;
+ itemlist[tmppos].insert( FloItem(FloItem::REST,notepos,x->len,x->dots) );
+ tmppos+=calc_len(x->len,x->dots);
+ itemlist[tmppos].insert( FloItem(FloItem::REST_END,notepos,0,0) );
+ }
+ }
+
+ lastevent=t;
+ next_measure=t+len;
+
+ itemlist[t].insert( FloItem(FloItem::BAR,no_notepos,0,0) );
+ }
+ else if (type==FloEvent::NOTE_ON)
+ {
+ int rest=t-lastevent;
+ if (rest)
+ {
+ printf("\tset rest at %i with len %i\n",lastevent,rest);
+ // no need to check if the rest crosses measure boundaries;
+ // it can't.
+
+ list<note_len_t> lens=parse_note_len(rest,DOTTED_RESTS,UNSPLIT_RESTS,lastevent);
+ unsigned tmppos=lastevent;
+ for (list<note_len_t>::iterator x=lens.begin(); x!=lens.end(); x++)
+ {
+ cout << "\t\tpartial rest with len="<<x->len<<", dots="<<x->dots<<endl;
+ itemlist[tmppos].insert( FloItem(FloItem::REST,notepos,x->len,x->dots) );
+ tmppos+=calc_len(x->len,x->dots);
+ itemlist[tmppos].insert( FloItem(FloItem::REST_END,notepos,0,0) );
+ }
+ }
+
+
+
+ printf("\tset note at %i with len=%i\n", t, len);
+
+ int tmplen;
+ bool tied_note;
+
+ // if the note exceeds the current measure, split it.
+ if (t+len>next_measure)
+ {
+ tmplen=next_measure-t;
+ tied_note=true;
+
+ //append the "rest" of the note to our EventList, so that
+ //it gets processed again when entering the new measure
+ int newlen=len-tmplen;
+ eventlist.insert(pair<unsigned, FloEvent>(next_measure, FloEvent(actual_tick,pitch, velo,0,FloEvent::NOTE_OFF, it->second.source_part, it->second.source_event)));
+ eventlist.insert(pair<unsigned, FloEvent>(next_measure, FloEvent(actual_tick,pitch, velo,newlen,FloEvent::NOTE_ON, it->second.source_part, it->second.source_event)));
+
+ cout << "\t\tnote was split to length "<<tmplen<<" + " << newlen<<endl;
+ }
+ else
+ {
+ tmplen=len;
+ tied_note=false;
+ }
+
+ list<note_len_t> lens=parse_note_len(tmplen,true,true,t);
+ unsigned tmppos=t;
+ int n_lens=lens.size();
+ int count=0;
+ for (list<note_len_t>::iterator x=lens.begin(); x!=lens.end(); x++)
+ {
+ cout << "\t\tpartial note with len="<<x->len<<", dots="<<x->dots<<endl;
+ count++;
+
+ bool tie;
+
+ if (count<n_lens)
+ tie=true; // all notes except the last are always tied
+ else
+ tie=tied_note; // only the last respects tied_note
+
+ itemlist[tmppos].insert( FloItem(FloItem::NOTE,notepos,x->len,x->dots, tie, actual_tick, it->second.source_part, it->second.source_event) );
+ tmppos+=calc_len(x->len,x->dots);
+ itemlist[tmppos].insert( FloItem(FloItem::NOTE_END,notepos,0,0) );
+ }
+ }
+ else if (type==FloEvent::NOTE_OFF)
+ {
+ lastevent=t;
+ }
+ else if (type==FloEvent::TIME_SIG)
+ {
+ cout << "inserting TIME SIGNATURE "<<it->second.num<<"/"<<it->second.denom<<" at "<<t<<endl;
+ itemlist[t].insert( FloItem(FloItem::TIME_SIG, it->second.num, it->second.denom) );
+ }
+ else if (type==FloEvent::KEY_CHANGE)
+ {
+ cout << "inserting KEY CHANGE ("<<it->second.tonart<<") at "<<t<<endl;
+ itemlist[t].insert( FloItem(FloItem::KEY_CHANGE, it->second.tonart) );
+ tmp_key=it->second.tonart; // TODO FINDMICH MARKER das muss schöner werden
+ }
+ }
+
+ return itemlist;
+}
-//---------------------------------------------------------
-// selectionChanged
-//---------------------------------------------------------
+void ScoreCanvas::process_itemlist(ScoreItemList& itemlist)
+{
+ stdmap<int,int> occupied;
+
+ //iterate through all times with items
+ for (ScoreItemList::iterator it2=itemlist.begin(); it2!=itemlist.end(); it2++)
+ {
+ set<FloItem, floComp>& curr_items=it2->second;
+
+ cout << "at t="<<it2->first<<endl;
+
+ // phase 0: keep track of active notes and rests -------------------
+ // (and occupied lines)
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end(); it++)
+ {
+ if ((it->type==FloItem::NOTE) || (it->type==FloItem::REST))
+ occupied[it->pos.height]++;
+ else if ((it->type==FloItem::NOTE_END) || (it->type==FloItem::REST_END))
+ occupied[it->pos.height]--;
+ }
+
+ cout << "occupied: ";
+ for (stdmap<int,int>::iterator i=occupied.begin(); i!=occupied.end(); i++)
+ if (i->second) cout << i->first << "("<<i->second<<") ";
+ cout << endl;
+
+
+
+
+
+ // phase 1: group rests together -----------------------------------
+ int n_groups=0;
+ bool dont_group=false;
+
+ //iterate through all rests R at that time
+ // iterate through all rests X at that time below R
+ // if something is between X and R ("barrier"), stop
+ // else: group them together
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end();)
+ {
+ //only operate on rests; ignore rests which are created by this code
+ //(can be seen on already_grouped)
+ if ((it->type==FloItem::REST) && (it->already_grouped==false))
+ {
+ cout << "trying to group" << endl;
+
+ int lastheight;
+ int height_cumulative=0;
+ int counter=0;
+
+ lastheight=it->pos.height;
+
+ set<FloItem, floComp>::iterator tmp;
+ for (tmp=it; tmp!=curr_items.end();)
+ {
+ cout << "checking if we can proceed with an item at height="<<tmp->pos.height<<endl;
+
+ for (int i=lastheight+1; i<=tmp->pos.height-1; i++)
+ if (occupied[i]!=0)
+ {
+ cout << "we can NOT, because occ["<<i<<"] != 0" << endl;
+ //stop grouping that rest
+ goto get_out_here;
+ }
+
+ lastheight=tmp->pos.height;
+
+ // the current item is a rest with equal len? cool!
+ if (tmp->type==FloItem::REST && tmp->len==it->len && tmp->dots==it->dots)
+ {
+ // füge diese pause zur gruppe dazu und entferne sie von diesem set hier
+ // entfernen aber nur, wenn sie nicht it, also die erste pause ist, die brauchen wir noch!
+ cout << "\tgrouping rest at height="<<tmp->pos.height<<endl;
+ height_cumulative+=tmp->pos.height;
+ counter++;
+ if (tmp!=it)
+ curr_items.erase(tmp++);
+ else
+ tmp++;
+ }
+ else //it's something else? well, we can stop grouping that rest then
+ {
+ cout << "we can NOT, because that item is not a rest" << endl;
+ //stop grouping that rest
+ goto get_out_here;
+ }
+ }
+ cout << "no items to proceed on left, continuing" << endl;
+ get_out_here:
+
+ n_groups++;
+
+ // entferne it vom set und
+ // füge eine pause mit dem "mittelwert" ein.
+ // occupied und die "_END"-events bleiben unberührt
+
+ FloItem temp=*it;
+ temp.already_grouped=true;
+
+ // have we grouped all available rests into one single?
+ if ( (n_groups==1) && (tmp==curr_items.end()) && !dont_group)
+ {
+ cout << "wow, we were able to group all rests into one single" << endl;
+ if (temp.len==0) //the whole rest is shifted one line (one space and one line)
+ temp.pos.height=DEFAULT_REST_HEIGHT+2;
+ else
+ temp.pos.height=DEFAULT_REST_HEIGHT;
+ }
+ else
+ {
+ cout << "creating group #"<<n_groups<<endl;
+ temp.pos.height=rint((float)height_cumulative/counter);
+ }
+
+ // do NOT first insert, then erase, because if temp.height ==
+ // it->height, the set considers temp and it equal (it doesn't
+ // take already_grouped into account)
+ // the result of this: insert does nothing, and erase erases
+ // the item. effect: you don't have the rest at all
+ curr_items.erase(it++);
+
+ cout << "replacing all grouped rests with a rest at height="<<temp.pos.height<<endl;
+
+ curr_items.insert(temp);
+ }
+ else
+ {
+ if (it->type==FloItem::NOTE)
+ dont_group=true;
+
+ it++;
+ }
+ }
+
+
+
+
+
+ // phase 2: avoid collisions of items ------------------------------
+ set<FloItem, floComp>::iterator lastit, groupbegin, invalid;
+ invalid=curr_items.end();
+ lastit=invalid;
+ groupbegin=invalid;
+ int count;
+
+ //TODO FINDMICH MARKER: is "grouping" notes and rests together okay?
+ // or is it better to ignore rests when grouping?
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end(); it++)
+ if ( (it->type==FloItem::NOTE) || (it->type==FloItem::REST) )
+ {
+ if (lastit != invalid)
+ {
+ if (it->pos.height == lastit->pos.height+1) // they would collide?
+ {
+ if (groupbegin==invalid) // we have no group atm?
+ {
+ groupbegin=lastit; // start a new group
+ count=1; // because lastit has to be taken into account.
+ // for "it", there's a count++ later
+ }
+
+ // the following will work even on start-new-group,
+ // because lastit will be "untouched", and that's why
+ // still be initalized to "false"
+ it->ausweich=!lastit->ausweich;
+
+ count++;
+ }
+ else
+ {
+ if (groupbegin!=invalid) //this is the first item which
+ { //doesn't belong to the previous group any more
+ if (count%2 == 0) //count is even?
+ if (modulo(groupbegin->pos.height, 2) == AUSWEICHEN_BEVORZUGT)
+ for (set<FloItem, floComp>::iterator tmp=groupbegin; tmp!=it; tmp++)
+ tmp->ausweich=!tmp->ausweich;
+
+ groupbegin=invalid;
+ }
+ // else: everything is ok :)
+ }
+ }
+
+ lastit=it;
+ }
+
+ // this could be the case if the last processed item before end()
+ // still belonged to a group. finalize this last group as well:
+ if (groupbegin!=invalid)
+ {
+ if (count%2 == 0) //count is even?
+ if (modulo(groupbegin->pos.height, 2) == AUSWEICHEN_BEVORZUGT)
+ for (set<FloItem, floComp>::iterator tmp=groupbegin; tmp!=curr_items.end(); tmp++)
+ tmp->ausweich=!tmp->ausweich;
+ }
+ // else: everything is ok :)
+
+
+
+
+
+ // phase 3: group notes by their length and ------------------------
+ // find out appropriate stem directions
+group_them_again:
+ stdmap<int, cumulative_t> lengths;
+ bool has_whole=false;
+
+ // find out which note lengths are present at that time
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end(); it++)
+ if (it->type==FloItem::NOTE)
+ lengths[it->len].add(it->pos.height);
+
+ cout << "note lengths at that time are:";
+ for (stdmap<int, cumulative_t>::iterator it=lengths.begin(); it!=lengths.end(); it++)
+ cout << it->first << "("<< it->second.mean() <<") ";
+ cout << endl;
+
+ if (lengths.erase(0)) // in case "0" is in the set, erase it
+ has_whole=true; // but remember there were whole notes
+
+ if (lengths.size()==0)
+ {
+ cout << "no notes other than wholes, or no notes at all. we can relax" << endl;
+ }
+ else if (lengths.size()==1)
+ {
+ pair<const int, cumulative_t>& group=*(lengths.begin());
+ stem_t stem;
+ int shift=0;
+ cout << "only one non-whole note group (len="<<group.first<<") at height="<<group.second.mean()<< endl;
+
+ if (group.second.mean()>=6)
+ {
+ stem=DOWNWARDS;
+ if (has_whole)
+ shift=-1;
+ }
+ else
+ {
+ stem=UPWARDS;
+ if (has_whole)
+ shift=1;
+ }
+
+ // for each note in that group
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end(); it++)
+ if ( (it->type==FloItem::NOTE) && (it->len==group.first) )
+ {
+ it->stem=stem;
+ it->shift=shift;
+ }
+ }
+ else if (lengths.size()==2)
+ {
+ stdmap<int, cumulative_t>::iterator it=lengths.begin();
+ pair<const int, cumulative_t>& group1=*it;
+ it++;
+ pair<const int, cumulative_t>& group2=*it;
+ stem_t stem1, stem2;
+ int shift1=0, shift2=0;
+ cout << "two non-whole note group: len="<<group1.first<<" at height="<<group1.second.mean()<<" and len="<<group2.first<<" at height="<<group2.second.mean()<< endl;
+
+ if (group1.second.mean()<group2.second.mean())
+ {
+ stem1=DOWNWARDS;
+ stem2=UPWARDS;
+ shift1=-1;
+ if (has_whole)
+ shift2=1;
+ }
+ else
+ {
+ stem1=UPWARDS;
+ stem2=DOWNWARDS;
+ shift2=-1;
+ if (has_whole)
+ shift1=1;
+ }
+
+ // for each note in group1
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end(); it++)
+ if ( (it->type==FloItem::NOTE) && (it->len==group1.first) )
+ {
+ it->stem=stem1;
+ it->shift=shift1;
+ }
+
+ // for each note in group2
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end(); it++)
+ if ( (it->type==FloItem::NOTE) && (it->len==group2.first) )
+ {
+ it->stem=stem2;
+ it->shift=shift2;
+ }
+ }
+ else //more than 2 groups
+ {
+ //at this time, there are no iterators pointing to curr_items.
+ //this means, we can erase and insert safely into curr_items here.
+
+ //group1 contains the longer notes, group2 the shorter
+
+ int group1_n=lengths.size()/2; //round down
+ int group2_n=lengths.size()-group1_n;
+
+ int group1_len, group2_len;
+ int group1_len_ticks, group2_len_ticks;
+
+
+ stdmap<int, cumulative_t>::iterator lit=lengths.begin();
+ for (int i=0;i<group1_n-1;i++) lit++; //go to the group1_n-th entry
+ group1_len=lit->first;
+ for (int i=0;i<group2_n;i++) lit++; //go to the (group1_n+group2_n)-th entry (i.e., the last before end() )
+ group2_len=lit->first;
+
+ group1_len_ticks=calc_len(group1_len,0);
+ group2_len_ticks=calc_len(group2_len,0);
+
+ cout << "we have "<<lengths.size()<<" groups. putting the "<<group1_n<<" longest and the "<<group2_n<<"shortest groups together"<<endl;
+ cout << "\tgroup1 will have len="<<group1_len<<" ("<<group1_len_ticks<<" ticks), group2 will have len="<<group2_len<<" ("<<group2_len_ticks<<" ticks)"<<endl;
+
+ for (set<FloItem, floComp>::iterator it=curr_items.begin(); it!=curr_items.end();)
+ if (it->type==FloItem::NOTE)
+ {
+ //if *it belongs to group1 and has not already its destination length
+ cout << "\tprocessing note-item with len="<<it->len<<endl;
+ if (it->len<group1_len)
+ {
+ cout << "\t\thas to be changed to fit into group 1" << endl;
+ FloItem tmp=*it;
+ curr_items.erase(it++);
+
+ int len_ticks_remaining=calc_len(tmp.len, tmp.dots)-group1_len_ticks;
+ bool tied_note=tmp.tied;
+
+
+ //shorten the current item to it's group's length
+ tmp.len=group1_len;
+ tmp.dots=0;
+ tmp.tied=true;
+ curr_items.insert(tmp);
+
+ //create items for the remaining lengths (and a note_END for the just created shortened note)
+ int t=it2->first+group1_len_ticks;
+
+ itemlist[t].insert( FloItem(FloItem::NOTE_END,tmp.pos,0,0) );
+
+ list<note_len_t> lens=parse_note_len(len_ticks_remaining,true,true,t);
+ unsigned tmppos=t;
+ int n_lens=lens.size();
+ int count=0;
+ for (list<note_len_t>::iterator x=lens.begin(); x!=lens.end(); x++)
+ {
+ cout << "\t\twhile regrouping: partial note with len="<<x->len<<", dots="<<x->dots<<endl;
+ count++;
+
+ bool tie;
+
+ if (count<n_lens)
+ tie=true; // all notes except the last are always tied
+ else
+ tie=tied_note; // only the last respects tied_note
+
+ itemlist[tmppos].insert( FloItem(FloItem::NOTE, tmp.pos,x->len,x->dots, tie, tmp.begin_tick, tmp.source_part, tmp.source_event) );
+ tmppos+=calc_len(x->len,x->dots);
+ itemlist[tmppos].insert( FloItem(FloItem::NOTE_END, tmp.pos,0,0) );
+ }
+
+ }
+ //else if *it belongs to group2 and has not already its destination length
+ else if ((it->len<group2_len) && (it->len>group1_len))
+ {
+ cout << "\t\thas to be changed to fit into group 2" << endl;
+
+ FloItem tmp=*it;
+ curr_items.erase(it++);
+
+ int len_ticks_remaining=calc_len(tmp.len, tmp.dots)-group2_len_ticks;
+ bool tied_note=tmp.tied;
+
+
+ //shorten the current item to it's group's length
+ tmp.len=group2_len;
+ tmp.dots=0;
+ tmp.tied=true;
+ curr_items.insert(tmp);
+
+ //create items for the remaining lengths (and a note_END for the just created shortened note)
+ int t=it2->first+group2_len_ticks;
+
+ itemlist[t].insert( FloItem(FloItem::NOTE_END,tmp.pos,0,0) );
+
+ list<note_len_t> lens=parse_note_len(len_ticks_remaining,true,true,t);
+ unsigned tmppos=t;
+ int n_lens=lens.size();
+ int count=0;
+ for (list<note_len_t>::iterator x=lens.begin(); x!=lens.end(); x++)
+ {
+ cout << "\t\twhile regrouping: partial note with len="<<x->len<<", dots="<<x->dots<<endl;
+ count++;
+
+ bool tie;
+
+ if (count<n_lens)
+ tie=true; // all notes except the last are always tied
+ else
+ tie=tied_note; // only the last respects tied_note
+
+ itemlist[tmppos].insert( FloItem(FloItem::NOTE,tmp.pos,x->len,x->dots, tie, tmp.begin_tick, tmp.source_part, tmp.source_event) );
+ tmppos+=calc_len(x->len,x->dots);
+ itemlist[tmppos].insert( FloItem(FloItem::NOTE_END,tmp.pos,0,0) );
+ }
+
+ }
+ else //nothing to do?
+ {
+ cout << "\t\tnothing to do" << endl;
+ it++;
+ }
+ }
+ else
+ it++;
+
+ goto group_them_again; //do it again
+ }
+
+ }
+}
-void ScoreEdit::selectionChanged()
- {
- bool flag = canvas->selectionSize() > 0;
- editCutAction->setEnabled(flag);
- editCopyAction->setEnabled(flag);
- editDelEventsAction->setEnabled(flag);
- }
+//draw a pixmap centered
+void ScoreCanvas::draw_pixmap(QPainter& p, int x, int y, const QPixmap& pm)
+{
+ cout << "drawing pixmap width size="<<pm.width()<<"/"<<pm.height()<<" at "<<x<<"/"<<y<<endl;
+ p.drawPixmap(x-pm.width()/2,y-pm.height()/2,pm);
+}
-//---------------------------------------------------------
-// setSpeaker
-//---------------------------------------------------------
+QRect bbox_center(int x, int y, const QSize& size)
+{
+ //why x-foo/2+foo? because due to integer divisions,
+ // x-foo/2+foo can be smaller than x+foo/2!
+ return QRect(x-size.width()/2,y-size.height()/2,size.width(),size.height());
+}
-void ScoreEdit::setSpeaker(bool val)
- {
- _playEvents = val;
- canvas->playEvents(_playEvents);
- }
+QRect FloItem::bbox() const
+{
+ return bbox_center(x,y,pix->size());
+}
-//---------------------------------------------------------
-// resizeEvent
-//---------------------------------------------------------
+void ScoreCanvas::draw_note_lines(QPainter& p)
+{
+ int xend=width();
+
+ for (int i=0;i<5;i++)
+ p.drawLine(0,YDIST+i*YLEN,xend,YDIST+i*YLEN);
+}
-void ScoreEdit::resizeEvent(QResizeEvent* ev)
- {
- QWidget::resizeEvent(ev);
- _widthInit = ev->size().width();
- _heightInit = ev->size().height();
- }
+void ScoreCanvas::calc_item_pos(ScoreItemList& itemlist)
+{
+ tonart_t curr_key=C;
+ int pos_add=0;
+
+ for (ScoreItemList::iterator it2=itemlist.begin(); it2!=itemlist.end(); it2++)
+ {
+ for (set<FloItem, floComp>::iterator it=it2->second.begin(); it!=it2->second.end();it++)
+ {
+ //if this changes, also change the line(s) with Y_MARKER
+ it->x=it2->first * PIXELS_PER_WHOLE/TICKS_PER_WHOLE +pos_add;
+ it->y=YDIST+4*YLEN - (it->pos.height-2)*YLEN/2;
+
+ if (it->type==FloItem::NOTE)
+ {
+ it->x+=NOTE_MOVE_X + it->shift*NOTE_SHIFT;
+
+ switch (it->len)
+ {
+ case 0: it->pix=&pix_whole; break;
+ case 1: it->pix=&pix_half; break;
+ default: it->pix=&pix_quarter; break;
+ }
+
+ it->stem_x=it->x;
+
+ if (it->ausweich)
+ {
+ if ((it->stem==UPWARDS) || (it->len==0))
+ it->x += it->pix->width()-1; //AUSWEICH_X
+ else
+ it->x -= it->pix->width()-1; //AUSWEICH_X
+ }
+
+ //if there's a tie, try to find the tie's destination and set is_tie_dest
+ if (it->tied)
+ {
+ set<FloItem, floComp>::iterator dest;
+ set<FloItem, floComp>& desttime = itemlist[it2->first+calc_len(it->len,it->dots)];
+ for (dest=desttime.begin(); dest!=desttime.end();dest++)
+ if ((dest->type==FloItem::NOTE) && (dest->pos==it->pos))
+ {
+ dest->is_tie_dest=true;
+ dest->tie_from_x=it->x;
+ break;
+ }
+
+ if (dest==desttime.end())
+ cout << "THIS SHOULD NEVER HAPPEN: did not find destination note for tie!" << endl;
+ }
+ }
+ else if (it->type==FloItem::REST)
+ {
+ switch (it->len)
+ {
+ case 0: it->pix=&pix_r1; break;
+ case 1: it->pix=&pix_r2; break;
+ case 2: it->pix=&pix_r4; break;
+ case 3: it->pix=&pix_r8; break;
+ case 4: it->pix=&pix_r16; break;
+ }
+
+ it->x+=NOTE_MOVE_X + (it->ausweich ? REST_AUSWEICH_X : 0); //AUSWEICH_X
+ }
+ else if (it->type==FloItem::BAR)
+ {
+ //nothing to do :)
+ }
+ else if (it->type==FloItem::TIME_SIG)
+ {
+ pos_add+=TIMESIG_POSADD;
+
+ pos_add_list[it2->first]+=TIMESIG_POSADD;
+ //+= is used instead of =, because a key- and time-
+ //change can occur at the same time.
+ }
+ else if (it->type==FloItem::KEY_CHANGE)
+ {
+ tonart_t new_key=it->tonart;
+
+ int aufloes_begin; //einschließlich
+ int aufloes_end; //ausschließlich!
+ int neue_vz_end; //ausschließlich!
+
+ neue_vz_end=n_accidentials(new_key);
+
+ int n_acc_drawn=0;
+
+ //both are sharp or b keys?
+ if (is_sharp_key(curr_key) == is_sharp_key(new_key))
+ {
+ // wenn new weniger vorzeichen hat als curr:
+ // löse nur diese auf
+ if (n_accidentials(curr_key)>n_accidentials(new_key))
+ {
+ aufloes_begin=n_accidentials(new_key);
+ aufloes_end=n_accidentials(curr_key);
+ }
+ else
+ {
+ aufloes_begin=aufloes_end=0; //löse garnichts auf
+ }
+ }
+ else //different key-families (# and b mixed up)
+ {
+ aufloes_begin=0;
+ aufloes_end=n_accidentials(curr_key);
+ }
+
+ n_acc_drawn=aufloes_end-aufloes_begin + neue_vz_end;
+
+ pos_add+=n_acc_drawn*KEYCHANGE_ACC_DIST+ KEYCHANGE_ACC_LEFTDIST+ KEYCHANGE_ACC_RIGHTDIST;
+
+ pos_add_list[it2->first]+=n_acc_drawn*KEYCHANGE_ACC_DIST+ KEYCHANGE_ACC_LEFTDIST+ KEYCHANGE_ACC_RIGHTDIST;
+ //+= is used instead of =, because a key- and time-
+ //change can occur at the same time.
+
+ curr_key=new_key;
+ }
+ }
+ }
+}
-/*
-//---------------------------------------------------------
-// trackInfoScroll
-//---------------------------------------------------------
+void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, int x1, int x2)
+{
+ int from_tick, to_tick;
+ ScoreItemList::iterator from_it, to_it;
+
+ //in general: drawing too much isn't bad. drawing too few is.
+
+ from_tick=x_to_tick(x1);
+ from_it=itemlist.lower_bound(from_tick);
+ //from_it now contains the first time which is fully drawn
+ //however, the previous beat could still be relevant, when it's
+ //partly drawn. so we decrement from_it
+ if (from_it!=itemlist.begin()) from_it--;
+
+ //decrement until we're at a time with a bar
+ //otherwise, drawing accidentials will be broken
+ while (from_it!=itemlist.begin() && from_it->second.find(FloItem(FloItem::BAR))==from_it->second.end())
+ from_it--;
+
+
+ to_tick=x_to_tick(x2);
+ to_it=itemlist.upper_bound(to_tick);
+ //to_it now contains the first time which is not drawn at all any more
+ //however, a tie from 1:04 to 2:01 is stored in 2:01, not in 1:04,
+ //so for drawing ties, we need to increment to_it, so that the
+ //"first time not drawn at all any more" is the last which gets
+ //actually drawn.
+ if (to_it!=itemlist.end()) to_it++; //do one tick more than neccessary. this will draw ties
+
+ draw_items(p,itemlist,from_it, to_it);
+}
-void ScoreEdit::trackInfoScroll(int y)
- {
- if (trackInfo->visibleWidget())
- trackInfo->visibleWidget()->move(0, -y);
- }
-*/
+void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist)
+{
+ draw_items(p,itemlist,x_pos,x_pos+width());
+}
-//---------------------------------------------------------
-// initShortcuts
-//---------------------------------------------------------
+void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList::iterator from_it, ScoreItemList::iterator to_it)
+{
+ vorzeichen_t curr_accidential[7];
+ vorzeichen_t default_accidential[7];
+ for (int i=0;i<7;i++) default_accidential[i]=NONE;
+ tonart_t curr_key=C;
+
+ for (ScoreItemList::iterator it2=from_it; it2!=to_it; it2++)
+ {
+ cout << "at t="<<it2->first << endl;
+
+ int upstem_y1 = -1, upstem_y2=-1, upstem_x=-1, upflag=-1;
+ int downstem_y1 = -1, downstem_y2=-1, downstem_x=-1, downflag=-1;
+
+ for (set<FloItem, floComp>::iterator it=it2->second.begin(); it!=it2->second.end();it++)
+ {
+ if (it->type==FloItem::NOTE)
+ {
+ cout << "\tNOTE at line"<<it->pos.height<<" with acc.="<<it->pos.vorzeichen<<", len="<<pow(2,it->len);
+ for (int i=0;i<it->dots;i++) cout << ".";
+ cout << " , stem=";
+ if (it->stem==UPWARDS)
+ cout << "UPWARDS";
+ else
+ cout << "DOWNWARDS";
+
+ cout << " , shift="<<it->shift<<", ausweich="<<it->ausweich<<", ";
+ if (!it->tied) cout << "un";
+ cout << "tied, is_tie_dest="<<it->is_tie_dest<<endl;
+
+ if (it->len!=0) //only for non-whole notes the stems are relevant!
+ {
+ if (it->stem==UPWARDS)
+ {
+ if (upstem_y1 == -1)
+ upstem_y1=it->y;
+
+ upstem_y2=it->y;
+
+
+ if ((upflag!=-1) && (upflag!=it->len))
+ cout << "WARNING: THIS SHOULD NEVER HAPPEN: upflag != this->flag" << endl;
+ upflag=it->len;
+
+ if ((upstem_x!=-1) && (upstem_x!=it->stem_x ))
+ cout << "WARNING: THIS SHOULD NEVER HAPPEN: upstem_x != x_result" << endl;
+ upstem_x=it->stem_x;
+ }
+ else
+ {
+ if (downstem_y1 == -1)
+ downstem_y1=it->y;
+
+ downstem_y2=it->y;
+
+
+ if ((downflag!=-1) && (downflag!=it->len))
+ cout << "WARNING: THIS SHOULD NEVER HAPPEN: downflag != this->flag" << endl;
+ downflag=it->len;
+
+ if ((downstem_x!=-1) && (downstem_x!=it->stem_x))
+ cout << "WARNING: THIS SHOULD NEVER HAPPEN: downstem_x != x_result" << endl;
+ downstem_x=it->stem_x; //important: before the below calculation!
+ }
+ }
+
+
+ if (it->pos.height <= 0) //we need auxiliary lines on the bottom?
+ { //Y_MARKER
+ for (int i=0; i>=it->pos.height; i-=2)
+ p.drawLine(it->x-it->pix->width()*AUX_LINE_LEN/2 -x_pos,YDIST+4*YLEN - (i-2)*YLEN/2,it->x+it->pix->width()*AUX_LINE_LEN/2-x_pos,YDIST+4*YLEN - (i-2)*YLEN/2);
+ }
+ else if (it->pos.height >= 12) //we need auxiliary lines on the top?
+ { //Y_MARKER
+ for (int i=12; i<=it->pos.height; i+=2)
+ p.drawLine(it->x-it->pix->width()*AUX_LINE_LEN/2 -x_pos,YDIST+4*YLEN - (i-2)*YLEN/2,it->x+it->pix->width()*AUX_LINE_LEN/2-x_pos,YDIST+4*YLEN - (i-2)*YLEN/2);
+ }
+
+
+ draw_pixmap(p,it->x -x_pos,it->y,*it->pix);
+
+ //draw dots
+
+ int x_dot=DOT_XBEGIN;
+ int y_dot;
+ if (modulo(it->pos.height, 2) == 0) //note is on a line?
+ y_dot=YLEN * 0.33; // actually 0.5, but that would be _exactly_ in the space
+ else //note is between two lines?
+ y_dot=YLEN * 0.1;
+
+ if (it->stem==DOWNWARDS)
+ y_dot=-y_dot;
+ //else y_dot=y_dot;
+
+ for (int i=0;i<it->dots;i++)
+ {
+ draw_pixmap(p,it->x+x_dot -x_pos,it->y+y_dot,pix_dot);
+ x_dot+=DOT_XDIST;
+ }
+
+
+
+ //draw accidentials
+ if (it->pos.vorzeichen != curr_accidential[modulo(it->pos.height,7)])
+ {
+ QPixmap* acc_pix;
+ switch (it->pos.vorzeichen)
+ {
+ case NONE: acc_pix=&pix_noacc; break;
+ case SHARP: acc_pix=&pix_sharp; break;
+ case B: acc_pix=&pix_b; break;
+ }
+ draw_pixmap(p,it->x-ACCIDENTIAL_DIST -x_pos,it->y, *acc_pix);
+
+ curr_accidential[modulo(it->pos.height,7)]=it->pos.vorzeichen;
+ }
+
+
+ //if needed, draw tie
+ if (it->is_tie_dest)
+ {
+ cout << "drawing tie" << endl;
+ draw_tie(p,it->tie_from_x-x_pos,it->x -x_pos,it->y, (it->len==0) ? true : (it->stem==DOWNWARDS) );
+ // in english: "if it's a whole note, tie is upwards (true). if not, tie is upwards if
+ // stem is downwards and vice versa"
+ }
+ }
+ else if (it->type==FloItem::REST)
+ {
+ cout << "\tREST at line"<<it->pos.height<<" with len="<<pow(2,it->len);
+ for (int i=0;i<it->dots;i++) cout << ".";
+ cout << " , ausweich="<<it->ausweich<<endl;
+
+ draw_pixmap(p,it->x -x_pos,it->y,*it->pix);
+
+
+ //draw dots
+
+ int x_dot=DOT_XBEGIN_REST;
+ int y_dot;
+ if (modulo(it->pos.height, 2) == 0) //rest is on a line?
+ y_dot=YLEN * 0.33; // actually 0.5, but that would be _exactly_ in the space
+ else //note is between two lines?
+ y_dot=YLEN * 0.1;
+
+ if (it->len!=0) // all rests except the whole are treated as
+ y_dot=-y_dot; // if they had a downwards stem
+
+ for (int i=0;i<it->dots;i++)
+ {
+ draw_pixmap(p,it->x+x_dot -x_pos,it->y+y_dot,pix_dot);
+ x_dot+=DOT_XDIST;
+ }
+ }
+ else if (it->type==FloItem::BAR)
+ {
+ cout << "\tBAR" << endl;
+
+ p.drawLine(it->x -x_pos,YDIST,it->x -x_pos,YDIST+4*YLEN);
+
+ for (int i=0;i<7;i++)
+ curr_accidential[i]=default_accidential[i];
+ }
+ else if (it->type==FloItem::TIME_SIG)
+ {
+ cout << "\tTIME SIGNATURE: "<<it->num<<"/"<<it->denom<<endl;
+
+ int y_coord=YDIST+2*YLEN;
+ p.drawPixmap(it->x + 5 -x_pos, y_coord, pix_num[it->denom]);
+ p.drawPixmap(it->x + 5 -x_pos, y_coord-NUMBER_HEIGHT, pix_num[it->num]);
+ }
+ else if (it->type==FloItem::KEY_CHANGE)
+ {
+ tonart_t new_key=it->tonart;
+ cout << "\tKEY CHANGE: from "<<curr_key<<" to "<<new_key<<endl;
+
+ int sharp_pos[]={10,7,11,8,5,9,6};
+ int b_pos[]={6,9,5,8,4,7,3};
+
+ int* aufloes_ptr;
+ int* neue_vz_ptr;
+
+ aufloes_ptr = is_sharp_key(curr_key) ? sharp_pos : b_pos;
+ neue_vz_ptr = is_sharp_key(new_key) ? sharp_pos : b_pos;
+
+ int aufloes_begin; //einschließlich
+ int aufloes_end; //ausschließlich!
+ int neue_vz_end; //ausschließlich!
+
+ neue_vz_end=n_accidentials(new_key);
+
+ int n_acc_drawn=0;
+
+ //both are sharp or b keys?
+ if (is_sharp_key(curr_key) == is_sharp_key(new_key))
+ {
+ cout << "\tboth are # or b-keys" << endl;
+ // wenn new weniger vorzeichen hat als curr:
+ // löse nur diese auf
+ if (n_accidentials(curr_key)>n_accidentials(new_key))
+ {
+ aufloes_begin=n_accidentials(new_key);
+ aufloes_end=n_accidentials(curr_key);
+ cout << "\taufloesen im intervall ["<<aufloes_begin<<";"<<aufloes_end<<"["<<endl;
+ }
+ else
+ {
+ aufloes_begin=aufloes_end=0; //löse garnichts auf
+ cout << "\tnichts wird aufgeloest"<<endl;
+ }
+ }
+ else
+ {
+ cout << "\tdifferent key-families (# and b mixed up)" << endl;
+ // löse alle auf
+ aufloes_begin=0;
+ aufloes_end=n_accidentials(curr_key);
+ cout << "\talle werden aufgeloest" << endl;
+ }
+
+ // vorzeichen von [aufloes_begin;aufloes_end[ aus curr_key auflösen
+ for (int i=aufloes_begin; i<aufloes_end; i++)
+ {
+ int y_coord=YDIST+4*YLEN - ( aufloes_ptr[i] -2)*YLEN/2; //Y_MARKER
+ draw_pixmap(p,it->x + n_acc_drawn*KEYCHANGE_ACC_DIST + KEYCHANGE_ACC_LEFTDIST -x_pos,y_coord,pix_noacc);
+ n_acc_drawn++;
+ }
+
+ QPixmap* pix = is_sharp_key(new_key) ? &pix_sharp : &pix_b;
+ vorzeichen_t new_accidential = is_sharp_key(new_key) ? SHARP : B;
+
+ for (int i=0;i<7;i++)
+ default_accidential[i]=NONE;
+
+ // alle vorzeichen aus new_key zeichnen
+ for (int i=0; i<neue_vz_end; i++)
+ {
+ int y_coord=YDIST+4*YLEN - ( neue_vz_ptr[i] -2)*YLEN/2; //Y_MARKER
+ draw_pixmap(p,it->x + n_acc_drawn*KEYCHANGE_ACC_DIST + KEYCHANGE_ACC_LEFTDIST -x_pos,y_coord,*pix);
+ n_acc_drawn++;
+
+ default_accidential[neue_vz_ptr[i]%7]=new_accidential;
+ }
+
+ curr_key=new_key;
+ for (int i=0;i<7;i++)
+ curr_accidential[i]=default_accidential[i];
+ }
+ }
+
+ //note: y1 is bottom, y2 is top!
+ if (upstem_x!=-1)
+ {
+ upstem_x=upstem_x-pix_quarter.width()/2 +pix_quarter.width() -1;
+ p.drawLine(upstem_x -x_pos, upstem_y1, upstem_x -x_pos, upstem_y2-STEM_LEN);
+
+ if (upflag>=3) //if the note needs a flag
+ p.drawPixmap(upstem_x -x_pos,upstem_y2-STEM_LEN,pix_flag_up[upflag-3]);
+ }
+ if (downstem_x!=-1)
+ {
+ downstem_x=downstem_x-pix_quarter.width()/2;
+ p.drawLine(downstem_x -x_pos, downstem_y1+STEM_LEN, downstem_x -x_pos, downstem_y2);
+
+ if (downflag>=3) //if the note needs a flag
+ p.drawPixmap(downstem_x -x_pos,downstem_y1+STEM_LEN-pix_flag_down[downflag-3].height(),pix_flag_down[downflag-3]);
+ }
+ }
+}
-void ScoreEdit::initShortcuts()
- {
- editCutAction->setShortcut(shortcuts[SHRT_CUT].key);
- editCopyAction->setShortcut(shortcuts[SHRT_COPY].key);
- editPasteAction->setShortcut(shortcuts[SHRT_PASTE].key);
- editDelEventsAction->setShortcut(shortcuts[SHRT_DELETE].key);
-
- selectAllAction->setShortcut(shortcuts[SHRT_SELECT_ALL].key);
- selectNoneAction->setShortcut(shortcuts[SHRT_SELECT_NONE].key);
- selectInvertAction->setShortcut(shortcuts[SHRT_SELECT_INVERT].key);
- selectInsideLoopAction->setShortcut(shortcuts[SHRT_SELECT_ILOOP].key);
- selectOutsideLoopAction->setShortcut(shortcuts[SHRT_SELECT_OLOOP].key);
- selectPrevPartAction->setShortcut(shortcuts[SHRT_SELECT_PREV_PART].key);
- selectNextPartAction->setShortcut(shortcuts[SHRT_SELECT_NEXT_PART].key);
-
- eventColor->menuAction()->setShortcut(shortcuts[SHRT_EVENT_COLOR].key);
- //evColorBlueAction->setShortcut(shortcuts[ ].key);
- //evColorPitchAction->setShortcut(shortcuts[ ].key);
- //evColorVelAction->setShortcut(shortcuts[ ].key);
-
- funcOverQuantAction->setShortcut(shortcuts[SHRT_OVER_QUANTIZE].key);
- funcNoteOnQuantAction->setShortcut(shortcuts[SHRT_ON_QUANTIZE].key);
- funcNoteOnOffQuantAction->setShortcut(shortcuts[SHRT_ONOFF_QUANTIZE].key);
- funcIterQuantAction->setShortcut(shortcuts[SHRT_ITERATIVE_QUANTIZE].key);
-
- funcConfigQuantAction->setShortcut(shortcuts[SHRT_CONFIG_QUANT].key);
-
- funcGateTimeAction->setShortcut(shortcuts[SHRT_MODIFY_GATE_TIME].key);
- funcModVelAction->setShortcut(shortcuts[SHRT_MODIFY_VELOCITY].key);
- funcCrescendoAction->setShortcut(shortcuts[SHRT_CRESCENDO].key);
- funcTransposeAction->setShortcut(shortcuts[SHRT_TRANSPOSE].key);
- funcThinOutAction->setShortcut(shortcuts[SHRT_THIN_OUT].key);
- funcEraseEventAction->setShortcut(shortcuts[SHRT_ERASE_EVENT].key);
- funcNoteShiftAction->setShortcut(shortcuts[SHRT_NOTE_SHIFT].key);
- funcMoveClockAction->setShortcut(shortcuts[SHRT_MOVE_CLOCK].key);
- funcCopyMeasureAction->setShortcut(shortcuts[SHRT_COPY_MEASURE].key);
- funcEraseMeasureAction->setShortcut(shortcuts[SHRT_ERASE_MEASURE].key);
- funcDelMeasureAction->setShortcut(shortcuts[SHRT_DELETE_MEASURE].key);
- funcCreateMeasureAction->setShortcut(shortcuts[SHRT_CREATE_MEASURE].key);
- funcSetFixedLenAction->setShortcut(shortcuts[SHRT_FIXED_LEN].key);
- funcDelOverlapsAction->setShortcut(shortcuts[SHRT_DELETE_OVERLAPS].key);
-
- }
-//---------------------------------------------------------
-// execDeliveredScript
-//---------------------------------------------------------
-void ScoreEdit::execDeliveredScript(int id)
+void ScoreCanvas::draw(QPainter& p, const QRect& rect)
{
- //QString scriptfile = QString(INSTPREFIX) + SCRIPTSSUFFIX + deliveredScriptNames[id];
- QString scriptfile = song->getScriptPath(id, true);
- song->executeScript(scriptfile.toAscii().data(), parts(), quant(), true);
+ cout <<"now in ScoreCanvas::draw"<<endl;
+
+
+
+ p.setPen(Qt::black);
+
+ draw_note_lines(p);
+ draw_items(p, itemlist);
}
-//---------------------------------------------------------
-// execUserScript
-//---------------------------------------------------------
-void ScoreEdit::execUserScript(int id)
+int ScoreCanvas::tick_to_x(int t)
{
- QString scriptfile = song->getScriptPath(id, false);
- song->executeScript(scriptfile.toAscii().data(), parts(), quant(), true);
+ int x=t*PIXELS_PER_WHOLE/TICKS_PER_WHOLE;
+
+ for (std::map<int,int>::iterator it=pos_add_list.begin(); it!=pos_add_list.end() && it->first<=t; it++)
+ x+=it->second;
+
+ return x;
}
-//---------------------------------------------------------
-// newCanvasWidth
-//---------------------------------------------------------
+int ScoreCanvas::calc_posadd(int t)
+{
+ int result=0;
-void ScoreEdit::newCanvasWidth(int /*w*/)
- {
-/*
- int nw = w + (vscroll->width() - 18); // 18 is the fixed width of the CtlEdit VScale widget.
- if(nw < 1)
- nw = 1;
-
- for (std::list<CtrlEdit*>::iterator i = ctrlEditList.begin();
- i != ctrlEditList.end(); ++i) {
- // Changed by Tim. p3.3.7
- //(*i)->setCanvasWidth(w);
- (*i)->setCanvasWidth(nw);
- }
-
- updateHScrollRange();
-*/
- }
+ for (std::map<int,int>::iterator it=pos_add_list.begin(); it!=pos_add_list.end() && it->first<t; it++)
+ result+=it->second;
-//---------------------------------------------------------
-// toggleTrackInfo
-//---------------------------------------------------------
+ return result;
+}
+
+//doesn't round mathematically correct, but i don't think this
+//will be a problem, because a tick is pretty small
+int ScoreCanvas::x_to_tick(int x)
+{
+ int t=TICKS_PER_WHOLE * x/PIXELS_PER_WHOLE;
+ int min_t=0;
+
+ cout << "t="<<t<<endl;
+
+ for (std::map<int,int>::iterator it=pos_add_list.begin(); it!=pos_add_list.end() && it->first<t; it++)
+ {
+ cout << "at pos_add event at t="<<it->first<<", add="<<it->second<<endl;
+ min_t=it->first;
+ x-=it->second;
+ t=TICKS_PER_WHOLE * x/PIXELS_PER_WHOLE;
+ }
+
+ return t > min_t ? t : min_t;
+}
+
+
+#define DRAG_INIT_DISTANCE 5
+
+void ScoreCanvas::mousePressEvent (QMouseEvent* event)
+{
+ // den errechneten tick immer ABrunden!
+ // denn der "bereich" eines schlags geht von schlag_begin bis nächsterschlag_begin-1
+ // noten werden aber genau in die mitte dieses bereiches gezeichnet
+
+ int y=event->y();
+ int x=event->x()+x_pos;
+ int tick= int(x_to_tick(x) / FLO_QUANT) * FLO_QUANT;
+ //TODO quantizing must (maybe?) be done with the proper functions
+
+
+ cout << "mousePressEvent at "<<x<<"/"<<y<<"; tick="<<tick<<endl;
+
+ for (set<FloItem, floComp>::iterator it=itemlist[tick].begin(); it!=itemlist[tick].end(); it++)
+ if (it->type==FloItem::NOTE)
+ if (it->bbox().contains(x,y))
+ {
+ mouse_down_pos=event->pos();
+ mouse_operation=NO_OP;
+
+ int t=tick;
+ set<FloItem, floComp>::iterator found;
+
+ do
+ {
+ found=itemlist[t].find(FloItem(FloItem::NOTE, it->pos));
+ if (found == itemlist[t].end())
+ {
+ cout << "FATAL: THIS SHOULD NEVER HAPPEN: could not find the note's tie-destination" << endl;
+ break;
+ }
+ else
+ {
+ t+=calc_len(found->len, found->dots);
+ }
+ } while (found->tied);
+
+ int total_begin=it->begin_tick;
+ int total_end=t;
+
+ int this_begin=tick;
+ int this_end=this_begin+calc_len(it->len, it->dots);
+
+ //that's the only note corresponding to the event?
+ if (this_begin==total_begin && this_end==total_end)
+ {
+ if (x < it->x)
+ mouse_x_drag_operation=BEGIN;
+ else
+ mouse_x_drag_operation=LENGTH;
+ }
+ //that's NOT the only note?
+ else
+ {
+ if (this_begin==total_begin)
+ mouse_x_drag_operation=BEGIN;
+ else if (this_end==total_end)
+ mouse_x_drag_operation=LENGTH;
+ else
+ mouse_x_drag_operation=NO_OP;
+ }
+
+ cout << "you clicked at a note with begin at "<<it->begin_tick<<" and end at "<<t<<endl;
+ cout << "x-drag-operation will be "<<mouse_x_drag_operation<<endl;
+ cout << "pointer to part is "<<it->source_part;
+ if (!it->source_part) cout << " (WARNING! THIS SHOULD NEVER HAPPEN!)";
+ cout << endl;
+
+ dragged_event=*it->source_event;
+ dragged_event_part=it->source_part;
+ dragged_event_original_pitch=dragged_event.pitch();
+
+ setMouseTracking(true);
+
+ break;
+ }
+
+}
+
+void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)
+{
+ setMouseTracking(false);
+}
+
+#define PITCH_DELTA 5
-void ScoreEdit::toggleTrackInfo()
+void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)
{
- bool vis = midiTrackInfo->isVisible();
- infoScroll->setVisible(!vis);
- infoScroll->setEnabled(!vis);
+ int dx=event->x()-mouse_down_pos.x();
+ int dy=event->y()-mouse_down_pos.y();
+
+ int y=event->y();
+ int x=event->x()+x_pos;
+ int tick= int(x_to_tick(x) / FLO_QUANT) * FLO_QUANT;
+
+ if (mouse_operation==NO_OP)
+ {
+ if ((abs(dx)>DRAG_INIT_DISTANCE) && (mouse_x_drag_operation!=NO_OP))
+ {
+ cout << "mouse-operation is now "<<mouse_x_drag_operation<<endl;
+ mouse_operation=mouse_x_drag_operation;
+ }
+ else if (abs(dy)>DRAG_INIT_DISTANCE)
+ {
+ cout << "mouse-operation is now PITCH" << endl;
+ mouse_operation=PITCH;
+ }
+ }
+
+ int new_pitch;
+
+ switch (mouse_operation)
+ {
+ case NONE:
+ break;
+
+ case PITCH:
+ cout << "changing pitch, delta="<<dy/PITCH_DELTA<<endl;
+ new_pitch=dragged_event_original_pitch - dy/PITCH_DELTA;
+
+ if (dragged_event.pitch()!=new_pitch)
+ {
+ Event tmp=dragged_event.clone();
+ tmp.setPitch(dragged_event_original_pitch- dy/PITCH_DELTA);
+
+ audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false);
+ dragged_event=tmp;
+
+ song_changed(0);
+ }
+
+ break;
+
+ case BEGIN:
+ if (dragged_event.tick() != tick)
+ {
+ Event tmp=dragged_event.clone();
+ tmp.setTick(tick);
+
+ audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false);
+ dragged_event=tmp;
+
+ song_changed(0);
+ }
+
+ break;
+
+ case LENGTH:
+ tick+=FLO_QUANT;
+ if (dragged_event.tick()+dragged_event.lenTick() != tick)
+ {
+ Event tmp=dragged_event.clone();
+ tmp.setLenTick(tick-dragged_event.tick());
+
+ audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false);
+ dragged_event=tmp;
+
+ song_changed(0);
+ }
+
+ break;
+ }
}
+
+void ScoreCanvas::scroll_event(int x)
+{
+ cout << "SCROLL EVENT: x="<<x<<endl;
+ x_pos=x;
+ redraw();
+}
+
+
+// TODO: testen: kommen die segfaults von muse oder von mir? [ von mir ]
+// TODO: testen, ob das noten-splitten korrekt arbeitet [ scheint zu klappen ]
+// TODO: testen, ob shift immer korrekt gesetzt wird [ scheint zu klappen ]
+
+//the following assertions are made:
+// pix_quarter.width() == pix_half.width()
+
+
+// pix->width()-1 + 1/2*pix->width() + SHIFT + ADD_SPACE
+// 10-1+5+3+3=20 <- um so viel wird der taktstrich verschoben
+// um das doppelte (20*2=40) werden die kleinsten schläge gegeneinander versetzt
+
+
+
+// bei änderung
+// takt- oder tonartänderung:
+// alles ab der betreffenden position löschen
+// alles ab dort neu berechnen
+// notenänderung:
+// alle von der note betroffenen takte löschen und neuberechnen
+// aus erstem betroffenen takt müssen tie-infos gesichert werden
+// im takt nach dem letzten betroffenen müssen die tie-infos
+// geupdated werden. ggf. löschen ist unnötig, da ties nur wandern,
+// aber nicht verschwinden oder neu dazukommen werden.
+
+
+//hint: recalculating event- and itemlists "from zero"
+// could happen in realtime, as it is pretty fast.
+// however, this adds unneccessary cpu usage.
+// it is NO problem to recalc the stuff "from zero"
+// every time something changes.
+
+
+
+
+
+//TODO WICHTIG TÖDLICH:
+// bei parse_note_len: BUG (siehe auch bug.mpt)
+// die anfangszeit wird in absoluten ticks statt
+// ticks seit taktbeginn gegeben -> fehler1
+// außerdem funzt die funktion nicht richtig, wenn
+// der takt nicht 4/4 ist!
+
+
+// TODO FINDMICH: tonart aus muses eventliste in meine übernehmen!
+
+// TODO: schöne funktionen fürs takt- und tonart-vorzeichen zeichnen
+// (mit längenangabe!)
+
+
+// TODO: notenschlüssel zeichen!
+// TODO: balken bei 8teln und 16teln etc
+// TODO: die ItemList als map< pos_t , der_rest_t > umändern
+
+//TODO: ausweichen bei ganzen noten!
+
+
+
+//TODO: while dragging notes:
+// send the correct events
+// do undo() stuff
+// etc.
+
+//TODO: support inserting and deleting notes
+//TODO: when a note gets resized so that len=0, erase it
+// but watch out for quantisation stuff then!
+// (when the start is slightly before the beat, len is 2 instead of 0)
+//TODO: deal with double notes?
diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h
index 767dc463..340d8c02 100644
--- a/muse2/muse/midiedit/scoreedit.h
+++ b/muse2/muse/midiedit/scoreedit.h
@@ -1,8 +1,8 @@
//=========================================================
// MusE
// Linux Music Editor
-// $Id: pianoroll.h,v 1.5.2.4 2009/11/16 11:29:33 lunar_shuttle Exp $
-// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+// scoreedit.cpp
+// (C) Copyright 2011 Florian Jung (florian.a.jung@web.de)
//=========================================================
#ifndef __SCOREEDIT_H__
@@ -12,6 +12,8 @@
#include <QResizeEvent>
#include <QLabel>
#include <QKeyEvent>
+#include <QPainter>
+#include <QPixmap>
#include <values.h>
#include "noteinfo.h"
@@ -19,6 +21,16 @@
#include "midieditor.h"
#include "tools.h"
#include "event.h"
+#include "view.h"
+
+#include <set>
+#include <map>
+#include <list>
+
+using std::set;
+using std::pair;
+using std::map;
+using std::list;
class MidiPart;
class TimeLabel;
@@ -47,155 +59,413 @@ class MidiTrackInfo;
class QScrollArea;
//---------------------------------------------------------
-// PianoRoll
+// ScoreEdit
//---------------------------------------------------------
-class ScoreEdit : public MidiEditor {
- Event selEvent;
- MidiPart* selPart;
- int selTick;
-
- //enum { CMD_EVENT_COLOR, CMD_CONFIG_QUANT, CMD_LAST };
- //int menu_ids[CMD_LAST];
- //Q3PopupMenu *menuEdit, *menuFunctions, *menuSelect, *menuConfig, *menuPlugins;
-
-
- QMenu *menuEdit, *menuFunctions, *menuSelect, *menuConfig, *eventColor, *menuPlugins;
- MidiTrackInfo *midiTrackInfo;
- Track* selected;
-
- QAction* editCutAction;
- QAction* editCopyAction;
- QAction* editPasteAction;
- QAction* editDelEventsAction;
-
- QAction* selectAllAction;
- QAction* selectNoneAction;
- QAction* selectInvertAction;
- QAction* selectInsideLoopAction;
- QAction* selectOutsideLoopAction;
- QAction* selectPrevPartAction;
- QAction* selectNextPartAction;
-
- QAction* evColorBlueAction;
- QAction* evColorPitchAction;
- QAction* evColorVelAction;
-
- QAction* funcOverQuantAction;
- QAction* funcNoteOnQuantAction;
- QAction* funcNoteOnOffQuantAction;
- QAction* funcIterQuantAction;
- QAction* funcConfigQuantAction;
- QAction* funcGateTimeAction;
- QAction* funcModVelAction;
- QAction* funcCrescendoAction;
- QAction* funcTransposeAction;
- QAction* funcThinOutAction;
- QAction* funcEraseEventAction;
- QAction* funcNoteShiftAction;
- QAction* funcMoveClockAction;
- QAction* funcCopyMeasureAction;
- QAction* funcEraseMeasureAction;
- QAction* funcDelMeasureAction;
- QAction* funcCreateMeasureAction;
- QAction* funcSetFixedLenAction;
- QAction* funcDelOverlapsAction;
-
-
- int tickOffset;
- int lenOffset;
- int pitchOffset;
- int veloOnOffset;
- int veloOffOffset;
- bool deltaMode;
-
- NoteInfo* info;
- QToolButton* srec;
- QToolButton* midiin;
-
- Toolbar1* toolbar;
- Splitter* splitter;
- Splitter* hsplitter;
- Splitter* ctrlLane;
-
- QToolButton* speaker;
- QToolBar* tools;
- EditToolBar* tools2;
-
- int colorMode;
-
- static int _quantInit, _rasterInit;
- static int _widthInit, _heightInit;
-
- static int _quantStrengthInit;
- static int _quantLimitInit;
- static bool _quantLenInit;
- static int _toInit;
- static int colorModeInit;
-
- int _quantStrength;
- int _quantLimit;
- int _to;
- bool _quantLen;
- QuantConfig* quantConfig;
- bool _playEvents;
-
- //QScrollBar* infoScroll;
- QScrollArea* infoScroll;
-
- Q_OBJECT
- void initShortcuts();
- void setEventColorMode(int);
- QWidget* genToolbar(QWidget* parent);
- virtual void closeEvent(QCloseEvent*);
- virtual void keyPressEvent(QKeyEvent*);
- virtual void resizeEvent(QResizeEvent*);
-
- private slots:
- void setSelection(int, Event&, Part*);
- void noteinfoChanged(NoteInfo::ValType, int);
- //CtrlEdit* addCtrl();
- void removeCtrl(CtrlEdit* ctrl);
- void soloChanged(bool flag);
- //void trackInfoScroll(int);
- void setRaster(int);
- void setQuant(int);
- void configQuant();
- void setQuantStrength(int val) { _quantStrength = val; }
- void setQuantLimit(int val) { _quantLimit = val; }
- void setQuantLen(bool val) { _quantLen = val; }
- void cmd(int);
- void setSteprec(bool);
- void setTo(int val) { _to = val; }
- void eventColorModeChanged(int);
- void clipboardChanged(); // enable/disable "Paste"
- void selectionChanged(); // enable/disable "Copy" & "Paste"
- void setSpeaker(bool);
- void setTime(unsigned);
- void follow(int pos);
- void songChanged1(int);
- void configChanged();
- void newCanvasWidth(int);
- void toggleTrackInfo();
- void updateTrackInfo();
-
- signals:
- void deleted(unsigned long);
-
+class ScoreEdit : public MidiEditor
+{
+ Q_OBJECT
+
+ private:
+
+
+ private slots:
+
+
+ signals:
+ void deleted(unsigned long);
+
+ public slots:
+ CtrlEdit* addCtrl() {return NULL;}; //TODO does nothing
+
+ public:
+ ScoreEdit(PartList*, QWidget* parent = 0, const char* name = 0, unsigned initPos = MAXINT);
+ ~ScoreEdit();
+ static void readConfiguration(Xml&){}; //TODO does nothing
+ static void writeConfiguration(int, Xml&){}; //TODO does nothing
+ };
+
+
+
+
+
+enum tonart_t
+{
+ SHARP_BEGIN,
+ C, // C or am, uses # for "black keys"
+ G,
+ D,
+ A,
+ E,
+ H,
+ FIS, //produces a #E (sounds like a F)
+ SHARP_END,
+ B_BEGIN,
+ C_B, // the same as C, but uses b for "black keys"
+ F,
+ ES,
+ AS,
+ DES,
+ GES, //sounds like FIS, but uses b instead of #
+ B_END
+};
+
+enum stem_t
+{
+ UPWARDS,
+ DOWNWARDS
+};
+
+enum vorzeichen_t
+{
+ B=-1,
+ NONE=0,
+ SHARP=1
+};
+
+struct note_pos_t
+{
+ int height; // 0 means "C-line", 1 "D-line" and so on
+ vorzeichen_t vorzeichen;
+
+ bool operator== (const note_pos_t& that) const
+ {
+ return (this->height==that.height) && (this->vorzeichen == that.vorzeichen);
+ }
+};
+
+bool operator< (const note_pos_t& a, const note_pos_t& b);
+
+
+class FloEvent
+{
+ public:
+ enum typeEnum { NOTE_ON = 30, NOTE_OFF = 10, BAR = 20, TIME_SIG=23, KEY_CHANGE=26 }; //the order matters!
+ typeEnum type;
+ unsigned tick;
+ Part* source_part;
+ Event* source_event;
+
+ int pitch;
+ int vel;
+ int len;
+
+ int num;
+ int denom;
+
+ tonart_t tonart;
+
+
+ FloEvent(unsigned ti, int p,int v,int l,typeEnum t, Part* part=NULL, Event* event=NULL)
+ {
+ pitch=p;
+ vel=v;
+ len=l;
+ type= t;
+ tick=ti;
+ source_event=event;
+ source_part=part;
+ }
+ FloEvent(unsigned ti, typeEnum t, int num_, int denom_)
+ {
+ type=t;
+ num=num_;
+ denom=denom_;
+ tick=ti;
+ source_event=NULL;
+ source_part=NULL;
+ }
+ FloEvent(unsigned ti, typeEnum t, tonart_t k)
+ {
+ type=t;
+ tonart=k;
+ tick=ti;
+ source_event=NULL;
+ source_part=NULL;
+ }
+};
+class FloItem
+{
+ public:
+ enum typeEnum { NOTE=21, REST=22, NOTE_END=01, REST_END=02, BAR =10, TIME_SIG=13, KEY_CHANGE=16}; //the order matters!
+ typeEnum type;
+ unsigned begin_tick;
+ Event* source_event;
+ Part* source_part;
+
+ note_pos_t pos;
+ int len;
+ int dots;
+ bool tied;
+ bool already_grouped;
+
+ int num;
+ int denom;
+
+ tonart_t tonart;
+
+ mutable stem_t stem;
+ mutable int shift;
+ mutable bool ausweich;
+ mutable bool is_tie_dest;
+ mutable int tie_from_x;
+
+ mutable int x;
+ mutable int y;
+ mutable int stem_x;
+ mutable QPixmap* pix;
+
+ QRect bbox() const;
+
+
+
+ FloItem(typeEnum t, note_pos_t p, int l=0,int d=0, bool ti=false, unsigned beg=0, Part* part=NULL, Event* event=NULL)
+ {
+ pos=p;
+ dots=d;
+ len=l;
+ type=t;
+ already_grouped=false;
+ tied=ti;
+ shift=0;
+ ausweich=false;
+ is_tie_dest=false;
+ begin_tick=beg;
+ source_event=event;
+ source_part=part;
+ }
+
+ FloItem(typeEnum t, int num_, int denom_)
+ {
+ type=t;
+ num=num_;
+ denom=denom_;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ FloItem(typeEnum t, tonart_t k)
+ {
+ type=t;
+ tonart=k;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ FloItem(typeEnum t)
+ {
+ type=t;
+
+ already_grouped=false;
+ tied=false;
+ shift=0;
+ ausweich=false;
+ is_tie_dest=false;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ FloItem()
+ {
+ already_grouped=false;
+ tied=false;
+ shift=0;
+ ausweich=false;
+ is_tie_dest=false;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ bool operator==(const FloItem& that)
+ {
+ if (this->type != that.type) return false;
+
+ switch(type)
+ {
+ case NOTE:
+ case REST:
+ case NOTE_END:
+ case REST_END:
+ return (this->pos == that.pos);
+
+ //the following may only occurr once in a set
+ //so we don't search for "the time signature with 4/4
+ //at t=0", but only for "some time signature at t=0"
+ //that's why true is returned, and not some conditional
+ //expression
+ case BAR:
+ case KEY_CHANGE:
+ case TIME_SIG:
+ return true;
+ }
+ }
+};
+struct floComp
+{
+ bool operator() (const pair<unsigned, FloEvent>& a, const pair<unsigned, FloEvent>& b )
+ {
+ if (a.first < b.first) return true;
+ if (a.first > b.first) return false;
+
+ if (a.second.type<b.second.type) return true;
+ if (a.second.type>b.second.type) return false;
+
+ return (a.second.pitch<b.second.pitch);
+ }
+ bool operator() (const FloItem& a, const FloItem& b )
+ {
+ if (a.type < b.type) return true;
+ if (a.type > b.type) return false;
+
+ switch(a.type)
+ {
+ case FloItem::NOTE:
+ case FloItem::REST:
+ case FloItem::NOTE_END:
+ case FloItem::REST_END:
+ return (a.pos < b.pos);
+
+ //the following may only occurr once in a set
+ //so we don't search for "the time signature with 4/4
+ //at t=0", but only for "some time signature at t=0"
+ //that's why true is returned, and not some conditional
+ //expression
+ case FloItem::BAR:
+ case FloItem::KEY_CHANGE:
+ case FloItem::TIME_SIG:
+ return false;
+ }
+ return (a.pos < b.pos);
+ }
+};
+
+typedef set< pair<unsigned, FloEvent>, floComp > ScoreEventList;
+typedef map< unsigned, set<FloItem, floComp> > ScoreItemList;
+
+enum clef_t
+{
+ VIOLIN,
+ BASS
+};
+
+
+struct note_len_t
+{
+ int len;
+ int dots;
+
+ note_len_t(int l, int d)
+ {
+ len=l; dots=d;
+ }
+
+ note_len_t(int l)
+ {
+ len=l; dots=0;
+ }
+};
+
+bool operator< (const note_len_t& a,const note_len_t& b);
+
+struct cumulative_t
+{
+ int count;
+ int cumul;
+
+ cumulative_t()
+ {
+ count=0;
+ cumul=0;
+ }
+
+ void add(int v)
+ {
+ count++;
+ cumul+=v;
+ }
+
+ float mean()
+ {
+ return (float)cumul/count;
+ }
+};
+
+
+class ScoreCanvas : public View
+{
+ Q_OBJECT
+ private:
+ void load_pixmaps();
+ ScoreEventList createAppropriateEventList(PartList* pl, Track* track);
+ note_pos_t note_pos_(int note, tonart_t key);
+ note_pos_t note_pos (int note, tonart_t key, clef_t clef);
+ int calc_len(int l, int d);
+ list<note_len_t> parse_note_len(int len_ticks, bool allow_dots=true, bool allow_normal=true, int begin_tick=0);
+ void draw_tie (QPainter& p, int x1, int x4, int yo, bool up=true);
+ ScoreItemList create_itemlist(ScoreEventList& eventlist);
+ void process_itemlist(ScoreItemList& itemlist);
+ void draw_pixmap(QPainter& p, int x, int y, const QPixmap& pm);
+ void draw_note_lines(QPainter& p);
+ void draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList::iterator from_it, ScoreItemList::iterator to_it);
+ void draw_items(QPainter& p, ScoreItemList& itemlist, int x1, int x2);
+ void draw_items(QPainter& p, ScoreItemList& itemlist);
+ void calc_item_pos(ScoreItemList& itemlist);
+
+ int tick_to_x(int t);
+ int x_to_tick(int x);
+ int calc_posadd(int t);
+
+ QPixmap pix_whole, pix_half, pix_quarter;
+ QPixmap pix_r1, pix_r2, pix_r4, pix_r8, pix_r16;
+ QPixmap pix_dot, pix_flag_up[4], pix_flag_down[4];
+ QPixmap pix_b, pix_sharp, pix_noacc;
+ QPixmap pix_num[10];
+
+
+ std::map<int,int> pos_add_list;
+ ScoreEventList eventlist;
+ ScoreItemList itemlist;
+ int x_pos;
+
+
+ QPoint mouse_down_pos;
+ bool mouse_down;
+ enum operation_t
+ {
+ NO_OP=0,
+ BEGIN=1,
+ LENGTH=2,
+ PITCH=3
+ };
+ operation_t mouse_operation;
+ operation_t mouse_x_drag_operation;
+
+ Part* dragged_event_part;
+ Event dragged_event;
+ int dragged_event_original_pitch;
+
+
public slots:
- virtual void updateHScrollRange();
- void execDeliveredScript(int id);
- void execUserScript(int id);
- CtrlEdit* addCtrl();
-
- public:
- ScoreEdit(PartList*, QWidget* parent = 0, const char* name = 0, unsigned initPos = MAXINT);
- ~ScoreEdit();
- virtual void readStatus(Xml&);
- virtual void writeStatus(int, Xml&) const;
- static void readConfiguration(Xml&);
- static void writeConfiguration(int, Xml&);
- };
+ void scroll_event(int);
+ void song_changed(int);
+
+
+ protected:
+ virtual void draw(QPainter& p, const QRect& rect);
+ MidiEditor* editor;
+
+ virtual void mousePressEvent (QMouseEvent* event);
+ virtual void mouseMoveEvent (QMouseEvent* event);
+ virtual void mouseReleaseEvent (QMouseEvent* event);
+
+ public:
+ ScoreCanvas(MidiEditor*, QWidget*, int, int);
+ ~ScoreCanvas(){};
+};
#endif