summaryrefslogtreecommitdiffstats
path: root/src/gui/rulers/RawNoteRuler.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 18:37:05 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 18:37:05 +0000
commit145364a8af6a1fec06556221e66d4b724a62fc9a (patch)
tree53bd71a544008c518034f208d64c932dc2883f50 /src/gui/rulers/RawNoteRuler.cpp
downloadrosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz
rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/gui/rulers/RawNoteRuler.cpp')
-rw-r--r--src/gui/rulers/RawNoteRuler.cpp573
1 files changed, 573 insertions, 0 deletions
diff --git a/src/gui/rulers/RawNoteRuler.cpp b/src/gui/rulers/RawNoteRuler.cpp
new file mode 100644
index 0000000..cc7d6e4
--- /dev/null
+++ b/src/gui/rulers/RawNoteRuler.cpp
@@ -0,0 +1,573 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "RawNoteRuler.h"
+
+#include "misc/Debug.h"
+#include "base/BaseProperties.h"
+#include "base/Composition.h"
+#include "base/NotationTypes.h"
+#include "base/NotationQuantizer.h"
+#include "base/RulerScale.h"
+#include "base/Segment.h"
+#include "DefaultVelocityColour.h"
+#include "gui/general/GUIPalette.h"
+#include <klocale.h>
+#include <qcolor.h>
+#include <qpainter.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qtooltip.h>
+#include <qwidget.h>
+
+
+namespace Rosegarden
+{
+
+RawNoteRuler::RawNoteRuler(RulerScale *rulerScale,
+ Segment *segment,
+ double xorigin,
+ int height,
+ QWidget *parent,
+ const char *name) :
+ QWidget(parent, name),
+ m_xorigin(xorigin),
+ m_height(height),
+ m_currentXOffset(0),
+ m_width( -1),
+ m_segment(segment),
+ m_rulerScale(rulerScale)
+{
+ setBackgroundColor(GUIPalette::getColour(GUIPalette::RawNoteRulerBackground));
+ QToolTip::add(this,"");
+}
+
+RawNoteRuler::~RawNoteRuler()
+{
+ QToolTip::remove(this);
+ // nothing else
+}
+
+void
+RawNoteRuler::slotScrollHoriz(int x)
+{
+ int w = width(), h = height();
+ int dx = x - ( -m_currentXOffset);
+ if (dx == 0)
+ return ;
+ m_currentXOffset = -x;
+
+ if (dx > w*3 / 4 || dx < -w*3 / 4) {
+ update();
+ return ;
+ }
+
+ if (dx > 0) { // moving right, so the existing stuff moves left
+ bitBlt(this, 0, 0, this, dx, 0, w - dx, h);
+ repaint(w - dx, 0, dx, h);
+ } else { // moving left, so the existing stuff moves right
+ bitBlt(this, -dx, 0, this, 0, 0, w + dx, h);
+ repaint(0, 0, -dx, h);
+ }
+}
+
+QSize
+RawNoteRuler::sizeHint() const
+{
+ double width =
+ m_rulerScale->getBarPosition(m_rulerScale->getLastVisibleBar()) +
+ m_rulerScale->getBarWidth(m_rulerScale->getLastVisibleBar()) +
+ m_xorigin;
+
+ QSize res(std::max(int(width), m_width), m_height);
+
+ return res;
+}
+
+QSize
+RawNoteRuler::minimumSizeHint() const
+{
+ double firstBarWidth = m_rulerScale->getBarWidth(0) + m_xorigin;
+ QSize res = QSize(int(firstBarWidth), m_height);
+ return res;
+}
+
+std::pair<timeT, timeT>
+RawNoteRuler::getExtents(Segment::iterator i)
+{
+ const Quantizer *q =
+ m_segment->getComposition()->getNotationQuantizer();
+
+ timeT u0 = (*i)->getAbsoluteTime();
+ timeT u1 = u0 + (*i)->getDuration();
+
+ timeT q0 = q->getQuantizedAbsoluteTime(*i);
+ timeT q1 = q0 + q->getQuantizedDuration(*i);
+
+ timeT t0 = std::min(u0, q0);
+ timeT t1 = std::max(u1, q1);
+
+ return std::pair<timeT, timeT>(t0, t1);
+}
+
+Segment::iterator
+RawNoteRuler::addChildren(Segment *s,
+ Segment::iterator to,
+ timeT rightBound,
+ EventTreeNode *node)
+{
+ Segment::iterator i = node->node;
+
+ std::pair<timeT, timeT> iex = getExtents(i);
+ Segment::iterator j = i;
+ Segment::iterator rightmost = to;
+
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ RG_DEBUG << "addChildren called for extents " << iex.first << "->" << iex.second << ", rightBound " << rightBound << endl;
+#endif
+
+ for (++j; j != to && s->isBeforeEndMarker(j); ) {
+
+ if (!(*j)->isa(Note::EventType)) {
+ ++j;
+ continue;
+ }
+ std::pair<timeT, timeT> jex = getExtents(j);
+
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ RG_DEBUG << "addChildren: event at " << (*j)->getAbsoluteTime() << ", extents " << jex.first << "->" << jex.second << endl;
+#endif
+
+ if (jex.first == jex.second) {
+ ++j;
+ continue;
+ }
+ if (jex.first >= iex.second || jex.first >= rightBound)
+ break;
+
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ RG_DEBUG << "addChildren: adding" << endl;
+#endif
+
+ EventTreeNode *subnode = new EventTreeNode(j);
+
+ Segment::iterator subRightmost = addChildren(s, to, rightBound, subnode);
+ if (subRightmost != to)
+ rightmost = subRightmost;
+ else
+ rightmost = j;
+
+ node->children.push_back(subnode);
+ j = s->findTime(jex.second);
+ }
+
+ return rightmost;
+}
+
+void
+RawNoteRuler::buildForest(Segment *s,
+ Segment::iterator from,
+ Segment::iterator to)
+{
+ for (EventTreeNode::NodeList::iterator i = m_forest.begin();
+ i != m_forest.end(); ++i) {
+ delete *i;
+ }
+ m_forest.clear();
+
+ timeT endTime = (s->isBeforeEndMarker(to) ? (*to)->getAbsoluteTime() :
+ s->getEndMarkerTime());
+
+ for (Segment::iterator i = from; i != to && s->isBeforeEndMarker(i); ) {
+
+ if (!(*i)->isa(Note::EventType)) {
+ ++i;
+ continue;
+ }
+
+ std::pair<timeT, timeT> iex = getExtents(i);
+
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ RG_DEBUG << "buildForest: event at " << (*i)->getAbsoluteTime() << ", extents " << iex.first << "->" << iex.second << endl;
+#endif
+
+ if (iex.first == iex.second) {
+ ++i;
+ continue;
+ }
+ if (iex.first >= endTime)
+ break;
+
+ EventTreeNode *node = new EventTreeNode(i);
+ Segment::iterator rightmost = addChildren(s, to, iex.second, node);
+ m_forest.push_back(node);
+
+ if (rightmost != to) {
+ i = rightmost;
+ ++i;
+ } else {
+ i = s->findTime(iex.second);
+ }
+
+#ifdef DEBUG_RAW_NOTE_RULER
+ RG_DEBUG << "findTime " << iex.second << " returned iterator at " << (i == s->end() ? -1 : (*i)->getAbsoluteTime()) << endl;
+#endif
+
+ }
+}
+
+void
+RawNoteRuler::dumpSubtree(EventTreeNode *node, int depth)
+{
+ if (!node)
+ return ;
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ for (int i = 0; i < depth; ++i)
+ std::cerr << " ";
+ if (depth > 0)
+ std::cerr << "->";
+ std::cerr << (*node->node)->getAbsoluteTime() << ","
+ << (*node->node)->getDuration() << " [";
+ long pitch = 0;
+ if ((*node->node)->get
+ <Int>(PITCH, pitch)) {
+ std::cerr << pitch << "]" << std::endl;
+ }
+ else {
+ std::cerr << "no-pitch]" << std::endl;
+ }
+ for (EventTreeNode::NodeList::iterator i = node->children.begin();
+ i != node->children.end(); ++i) {
+ dumpSubtree(*i, depth + 1);
+ }
+#endif
+ (void)depth; // avoid warnings
+}
+
+void
+RawNoteRuler::dumpForest(EventTreeNode::NodeList *forest)
+{
+#ifdef DEBUG_RAW_NOTE_RULER
+ std::cerr << "\nFOREST:\n" << std::endl;
+
+ for (unsigned int i = 0; i < forest->size(); ++i) {
+
+ std::cerr << "\nTREE " << i << ":\n" << std::endl;
+ dumpSubtree((*forest)[i], 0);
+ }
+
+ std::cerr << std::endl;
+#endif
+
+ (void)forest; // avoid warnings
+}
+
+int
+RawNoteRuler::EventTreeNode::getDepth()
+{
+ int subchildrenDepth = 0;
+ for (NodeList::iterator i = children.begin();
+ i != children.end(); ++i) {
+ int subchildDepth = (*i)->getDepth();
+ if (subchildDepth > subchildrenDepth)
+ subchildrenDepth = subchildDepth;
+ }
+ return subchildrenDepth + 1;
+}
+
+int
+RawNoteRuler::EventTreeNode::getChildrenAboveOrBelow(bool below, int p)
+{
+ long pitch(p);
+ if (pitch < 0)
+ (*node)->get
+ <Int>(BaseProperties::PITCH, pitch);
+
+ int max = 0;
+
+ for (NodeList::iterator i = children.begin();
+ i != children.end(); ++i) {
+ int forThisChild = (*i)->getChildrenAboveOrBelow(below, pitch);
+ long thisChildPitch = pitch;
+ (*(*i)->node)->get
+ <Int>(BaseProperties::PITCH, thisChildPitch);
+ if (below ? (thisChildPitch < pitch) : (thisChildPitch > pitch)) {
+ ++forThisChild;
+ }
+ if (forThisChild > max)
+ max = forThisChild;
+ }
+
+ return max;
+}
+
+void
+RawNoteRuler::drawNode(QPainter &paint, DefaultVelocityColour &vc,
+ EventTreeNode *node, double height, double yorigin)
+{
+ int depth = node->getDepth();
+ int above = node->getChildrenAboveOrBelow(false);
+
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ int below = node->getChildrenAboveOrBelow(true);
+
+ NOTATION_DEBUG << "RawNoteRuler::drawNode: children above: "
+ << above << ", below: " << below << endl;
+#endif
+
+ int toFit = depth;
+
+ double heightPer = double(height) / toFit;
+ if (heightPer > m_height / 4)
+ heightPer = m_height / 4;
+ if (heightPer < 2)
+ heightPer = 2;
+
+ double myOrigin = yorigin + (heightPer * above);
+ long myPitch = 60;
+ (*node->node)->get
+ <Int>(BaseProperties::PITCH, myPitch);
+
+ long velocity = 100;
+ (*node->node)->get
+ <Int>(BaseProperties::VELOCITY, velocity);
+ QColor colour = vc.getColour(velocity);
+
+ timeT start = (*node->node)->getAbsoluteTime();
+ timeT end = (*node->node)->getDuration() + start;
+
+ double u0 = m_rulerScale->getXForTime(start);
+ double u1 = m_rulerScale->getXForTime(end);
+
+ u0 += m_currentXOffset + m_xorigin;
+ u1 += m_currentXOffset + m_xorigin;
+
+ start = m_segment->getComposition()->getNotationQuantizer()->
+ getQuantizedAbsoluteTime(*node->node);
+ end = start + m_segment->getComposition()->getNotationQuantizer()->
+ getQuantizedDuration(*node->node);
+
+ double q0 = m_rulerScale->getXForTime(start);
+ double q1 = m_rulerScale->getXForTime(end);
+
+ q0 += m_currentXOffset + m_xorigin;
+ q1 += m_currentXOffset + m_xorigin;
+
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ NOTATION_DEBUG << "RawNoteRuler: (" << int(start) << "," << myOrigin
+ << ") -> (" << int(end) << "," << myOrigin << ")" << endl;
+#endif
+
+ int qi0 = int(q0);
+ int ui0 = int(u0);
+ int qi1 = int(q1);
+ int ui1 = int(u1);
+ // int qiw = int(q1-q0) - 1;
+ int uiw = int(u1 - u0) - 1;
+ // int iy = int(myOrigin + (height - heightPer) / 2);
+ int iy = int(myOrigin);
+ int ih = int(heightPer);
+
+#ifdef DEBUG_RAW_NOTE_RULER
+
+ NOTATION_DEBUG << "RawNoteRuler: height " << height << ", heightPer "
+ << heightPer << ", iy " << iy << endl;
+#endif
+
+ paint.setPen(colour);
+ paint.setBrush(colour);
+ paint.drawRect(ui0 + 1, iy + 1, uiw, ih - 1);
+
+ paint.setPen(GUIPalette::getColour(GUIPalette::RawNoteRulerForeground));
+ paint.setBrush(GUIPalette::getColour(GUIPalette::RawNoteRulerForeground));
+ paint.drawLine(qi0, iy, qi1 - 1, iy);
+ paint.drawLine(qi0, iy + ih, qi1 - 1, iy + ih);
+ paint.drawLine(ui0, iy + 1, ui0, iy + ih - 1);
+ paint.drawLine(ui1 - 1, iy + 1, ui1 - 1, iy + ih - 1);
+
+ for (EventTreeNode::NodeList::iterator i = node->children.begin();
+ i != node->children.end(); ++i) {
+
+ long nodePitch = myPitch;
+ (*(*i)->node)->get
+ <Int>(BaseProperties::PITCH, nodePitch);
+
+ if (nodePitch < myPitch) {
+
+ drawNode(paint, vc, *i,
+ height - heightPer - myOrigin, myOrigin + heightPer);
+
+ } else {
+
+ drawNode(paint, vc, *i,
+ myOrigin - yorigin, yorigin);
+ }
+ }
+}
+
+void
+RawNoteRuler::paintEvent(QPaintEvent* e)
+{
+ if (!m_segment || !m_segment->getComposition())
+ return ;
+
+ // Tooltips
+ {
+ QToolTip::remove(this);
+ TrackId trackId = m_segment->getTrack();
+ Track *track =
+ m_segment->getComposition()->getTrackById(trackId);
+ int trackPosition = -1;
+ if (track)
+ trackPosition = track->getPosition();
+
+ QToolTip::add(this,i18n("Track #%1, Segment \"%2\" (runtime id %3)")
+ .arg(trackPosition + 1)
+ .arg(m_segment->getLabel())
+ .arg(m_segment->getRuntimeId()));
+ }
+
+ // START_TIMING;
+
+ QPainter paint(this);
+ paint.setClipRegion(e->region());
+ paint.setClipRect(e->rect().normalize());
+
+ QRect clipRect = paint.clipRegion().boundingRect();
+
+ timeT from = m_rulerScale->getTimeForX
+ (clipRect.x() - m_currentXOffset - 100 - m_xorigin);
+ timeT to = m_rulerScale->getTimeForX
+ (clipRect.x() + clipRect.width() - m_currentXOffset + 100 - m_xorigin);
+
+ paint.setPen(GUIPalette::getColour(GUIPalette::RawNoteRulerForeground));
+ paint.setBrush(GUIPalette::getColour(GUIPalette::RawNoteRulerForeground));
+ paint.drawLine(0, 0, width(), 0);
+
+ // draw the extent of the segment using its color
+
+ QColor brushColor = GUIPalette::convertColour(m_segment->getComposition()->
+ getSegmentColourMap().getColourByIndex(m_segment->getColourIndex()));
+ paint.setPen(brushColor);
+ paint.setBrush(brushColor);
+ int x0 = int(m_rulerScale->getXForTime(m_segment->getStartTime()) +
+ m_currentXOffset + m_xorigin);
+ int x1 = int(m_rulerScale->getXForTime(m_segment->getEndTime()) +
+ m_currentXOffset + m_xorigin);
+ paint.drawRect(x0, 1, x1-x0+1, height()-1);
+
+ // draw the bar divisions
+
+ int firstBar = m_segment->getComposition()->getBarNumber(from);
+ int lastBar = m_segment->getComposition()->getBarNumber(to);
+ std::vector<int> divisions;
+
+ for (int barNo = firstBar; barNo <= lastBar; ++barNo) {
+
+ bool isNew = false;
+ TimeSignature timeSig =
+ m_segment->getComposition()->getTimeSignatureInBar(barNo, isNew);
+ if (isNew || barNo == firstBar) {
+ timeSig.getDivisions(3, divisions);
+ if (timeSig == TimeSignature()) // special case for 4/4
+ divisions[0] = 2;
+ }
+
+ timeT barStart = m_segment->getComposition()->getBarStart(barNo);
+ timeT base = timeSig.getBarDuration();
+ timeT barEnd = barStart + base;
+
+ paint.setPen(GUIPalette::getColour(GUIPalette::RawNoteRulerForeground));
+ paint.setBrush(GUIPalette::getColour(GUIPalette::RawNoteRulerForeground));
+
+ int x = int(m_rulerScale->getXForTime(barStart) +
+ m_currentXOffset + m_xorigin);
+ paint.drawLine(x, 1, x, m_height);
+
+ for (int depth = 0; depth < 3; ++depth) {
+
+ int grey = depth * 60 + 60;
+ paint.setPen(QColor(grey, grey, grey));
+ paint.setBrush(QColor(grey, grey, grey));
+
+ base /= divisions[depth];
+ timeT t(barStart + base);
+ while (t < barEnd) {
+ if ((t - barStart) % (base * divisions[depth]) != 0) {
+ int x = int(m_rulerScale->getXForTime(t) +
+ m_currentXOffset + m_xorigin);
+ paint.drawLine(x, 1, x, m_height);
+ }
+ t += base;
+ }
+ }
+ }
+
+ // PRINT_ELAPSED("RawNoteRuler::paintEvent: drawing bar lines and divisions");
+
+#ifdef DEBUG_RAW_NOTE_RULER
+ NOTATION_DEBUG << "RawNoteRuler: from is " << from << ", to is " << to << endl;
+#endif
+
+ Segment::iterator i = m_segment->findNearestTime(from);
+ if (i == m_segment->end())
+ i = m_segment->begin();
+
+ // somewhat experimental, as is this whole class
+ Segment::iterator j = m_segment->findTime(to);
+ buildForest(m_segment, i, j);
+
+ // PRINT_ELAPSED("RawNoteRuler::paintEvent: buildForest");
+
+ dumpForest(&m_forest);
+
+ // PRINT_ELAPSED("RawNoteRuler::paintEvent: dumpForest");
+
+ for (EventTreeNode::NodeList::iterator fi = m_forest.begin();
+ fi != m_forest.end(); ++fi) {
+
+ // Each tree in the forest should represent a note that starts
+ // at a time when no other notes are playing (at least of
+ // those that started no earlier than the paint start time).
+ // Each node in that tree represents a note that starts
+ // playing during its parent node's note, or at the same time
+ // as it.
+
+ drawNode(paint, *DefaultVelocityColour::getInstance(), *fi, m_height - 3, 2);
+
+ }
+
+ // PRINT_ELAPSED("RawNoteRuler::paintEvent: complete");
+}
+
+}
+#include "RawNoteRuler.moc"