File indexing completed on 2024-05-12 16:34:16

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2007 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 #include "Renderer.h"
0020 #include "MusicStyle.h"
0021 
0022 #include "core/Sheet.h"
0023 #include "core/Part.h"
0024 #include "core/Voice.h"
0025 #include "core/Staff.h"
0026 #include "core/VoiceBar.h"
0027 #include "core/Chord.h"
0028 #include "core/Note.h"
0029 #include "core/Clef.h"
0030 #include "core/Bar.h"
0031 #include "core/KeySignature.h"
0032 #include "core/TimeSignature.h"
0033 #include "core/StaffSystem.h"
0034 
0035 #include <QMultiMap>
0036 #include <QPainterPath>
0037 
0038 #include <climits>
0039 #include <algorithm>
0040 
0041 using namespace MusicCore;
0042 
0043 MusicRenderer::MusicRenderer(MusicStyle* style) : m_style(style), m_debug(false)
0044 {
0045 }
0046 
0047 void MusicRenderer::renderSheet(QPainter& painter, Sheet* sheet, int firstSystem, int lastSystem)
0048 {
0049     int firstBar = sheet->staffSystem(firstSystem)->firstBar();
0050     int lastBar = INT_MAX;
0051     if (lastSystem < sheet->staffSystemCount()-1) {
0052         lastBar = sheet->staffSystem(lastSystem+1)->firstBar()-1;
0053     }
0054 
0055     for (int i = 0; i < sheet->partCount(); i++) {
0056         renderPart(painter, sheet->part(i), firstBar, lastBar);
0057     }
0058     for (int i = firstSystem; i <= lastSystem && i < sheet->staffSystemCount(); i++) {
0059         StaffSystem* ss = sheet->staffSystem(i);
0060         if (ss->indent() == 0) continue;
0061         int b = ss->firstBar();
0062         Bar* bar = sheet->bar(b);
0063         qreal by = bar->position().y();
0064         qreal ind = ss->indent();
0065 
0066         for (int p = 0; p < sheet->partCount(); p++) {
0067             Part* part = sheet->part(p);
0068             for (int s = 0; s < part->staffCount(); s++) {
0069                 Staff* staff = part->staff(s);
0070                 qreal y = staff->top();
0071                 qreal dy = staff->lineSpacing();
0072 
0073                 painter.setPen(m_style->staffLinePen());
0074                 for (int l = 0; l < staff->lineCount(); l++) {
0075                     painter.drawLine(QPointF(0, by + y + l * dy), QPointF(ind, by + y + l * dy));
0076                 }
0077 
0078                 Clef* clef = ss->clef(staff);
0079                 RenderState foo;
0080                 qreal x = 15;
0081                 if (clef) {
0082                     renderClef(painter, clef, QPointF(x, by), foo, Qt::black, true);
0083                     x += clef->width() + 15;
0084                 }
0085                 KeySignature* ks = staff->lastKeySignatureChange(b);
0086                 if (ks) {
0087                     renderKeySignature(painter, ks, QPointF(x, by), foo, Qt::black, true);
0088                 }
0089             }
0090         }
0091     }
0092 }
0093 
0094 void MusicRenderer::renderPart(QPainter& painter, Part* part, int firstBar, int lastBar, const QColor& color)
0095 {
0096     if (lastBar < firstBar) return;
0097 
0098     for (int i = 0; i < part->staffCount(); i++) {
0099         renderStaff(painter, part->staff(i), firstBar, lastBar, color);
0100     }
0101     qreal firstStaff = part->staff(0)->top();
0102     int c = part->staffCount()-1;
0103     qreal lastStaff = part->staff(c)->bottom();
0104     for (int b = firstBar; b <= lastBar && b < part->sheet()->barCount(); b++) {
0105         Bar* bar = part->sheet()->bar(b);
0106         QPointF p = bar->position();
0107         painter.drawLine(QPointF(p.x() + bar->size(), p.y() + firstStaff), QPointF(p.x() + bar->size(), p.y() + lastStaff));
0108         if (m_debug) {
0109             painter.setPen(QPen(Qt::green, 0));
0110             painter.drawLine(QPointF(p.x(), p.y() + firstStaff - 3), QPointF(p.x(), p.y() + lastStaff + 3));
0111             painter.drawLine(QPointF(p.x() - bar->prefix(), p.y() + firstStaff - 3), QPointF(p.x() - bar->prefix(), p.y() + lastStaff + 3));
0112         }
0113 
0114         // check if the bar contains any elements, if not render a rest
0115         bool hasContents = false;
0116         for (int v = 0; v < part->voiceCount(); v++) {
0117             if (part->voice(v)->bar(bar)->elementCount() > 0) {
0118                 hasContents = true;
0119                 break;
0120             }
0121         }
0122 
0123         if (!hasContents) {
0124             QPointF pos = bar->position();
0125             qreal w = bar->size();
0126             for (int sid = 0; sid < part->staffCount(); sid++) {
0127                 Staff* s = part->staff(sid);
0128                 renderRest(painter, WholeNote, pos + QPointF(w/2, s->top() + s->lineSpacing()), color);
0129             }
0130         }
0131     }
0132     for (int i = 0; i < part->voiceCount(); i++) {
0133         renderVoice(painter, part->voice(i), firstBar, lastBar, color);
0134     }
0135 }
0136 
0137 void MusicRenderer::renderStaff(QPainter& painter, Staff *staff, int firstBar, int lastBar, const QColor& color)
0138 {
0139     qreal dy = staff->lineSpacing();
0140     qreal y = staff->top();
0141     for (int b = firstBar; b <= lastBar && b < staff->part()->sheet()->barCount(); b++) {
0142         Bar* bar = staff->part()->sheet()->bar(b);
0143         QPointF p = bar->position();
0144         QPointF prep = bar->prefixPosition() + QPointF(bar->prefix(), 0);
0145         painter.setPen(m_style->staffLinePen(color));
0146         for (int i = 0; i < staff->lineCount(); i++) {
0147             painter.drawLine(QPointF(p.x(), p.y() + y + i * dy), QPointF(p.x() + bar->size(), p.y() + y + i * dy));
0148         }
0149         if (bar->prefix() > 0) {
0150             QPointF q = bar->prefixPosition();
0151             for (int i = 0; i < staff->lineCount(); i++) {
0152                 painter.drawLine(QPointF(q.x(), q.y() + y + i * dy), QPointF(q.x() + bar->prefix(), q.y() + y + i * dy));
0153             }
0154         }
0155         RenderState state;
0156         for (int e = 0; e < bar->staffElementCount(staff); e++) {
0157             StaffElement* se = bar->staffElement(staff, e);
0158             if (se->startTime() == 0) {
0159                 renderStaffElement(painter, bar->staffElement(staff, e), prep, state, color);
0160             } else {
0161                 renderStaffElement(painter, bar->staffElement(staff, e), p, state, color);
0162             }
0163         }
0164     }
0165 }
0166 
0167 void MusicRenderer::renderVoice(QPainter& painter, Voice *voice, int firstBar, int lastBar, const QColor& color)
0168 {
0169     RenderState state;
0170     state.clef = 0;
0171     for (int b = firstBar; b <= lastBar && b < voice->part()->sheet()->barCount(); b++) {
0172         Bar* bar = voice->part()->sheet()->bar(b);
0173         QPointF p = bar->position();
0174         VoiceBar* vb = voice->bar(bar);
0175         for (int e = 0; e < vb->elementCount(); e++) {
0176             if (vb->element(e)->staff()) {
0177                 state.clef = vb->element(e)->staff()->lastClefChange(b, 0);
0178             }
0179             renderElement(painter, vb->element(e), voice, p, state, color);
0180         }
0181     }
0182 }
0183 
0184 void MusicRenderer::renderElement(QPainter& painter, VoiceElement* me, Voice* voice, const QPointF& pos, RenderState& state, const QColor& color)
0185 {
0186     Q_UNUSED( state ); // unused for now, but will probably be used again in the future
0187 
0188     qreal top = 0;
0189     if (me->staff()) top += me->staff()->top();
0190     if (m_debug) {
0191         painter.setPen(QPen(Qt::blue, 0));
0192         painter.drawLine(pos + QPointF(me->x(), top + me->y() - 4), pos + QPointF(me->x(), top + me->y() + me->height() + 4));
0193         painter.drawLine(pos + QPointF(me->x() + me->width(), top + me->y() - 4), pos + QPointF(me->x() + me->width(), top + me->y() + me->height() + 4));
0194 
0195         painter.drawLine(pos + QPointF(me->x() - 4, top + me->y()), pos + QPointF(me->x() + me->width() + 4, top + me->y()));
0196         painter.drawLine(pos + QPointF(me->x() - 4, top + me->y() + me->height()), pos + QPointF(me->x() + me->width() + 4, top + me->y() + me->height()));
0197 
0198         painter.setPen(QPen(Qt::red, 0));
0199         painter.drawLine(pos + QPointF(me->x() + me->beatline(), top + me->y() - 10), pos + QPointF(me->x() + me->beatline(), top + me->y() + me->height() + 10));
0200     }
0201 
0202     // TODO: make this less hacky
0203     Chord *c = dynamic_cast<Chord*>(me);
0204     if (c) renderChord(painter, c, voice, pos, color);
0205 }
0206 
0207 void MusicRenderer::renderStaffElement(QPainter& painter, MusicCore::StaffElement* se, const QPointF& pos, RenderState& state, const QColor& color)
0208 {
0209     qreal top = 0;
0210     top += se->staff()->top();
0211     if (m_debug) {
0212         painter.setPen(QPen(Qt::blue, 0));
0213         painter.drawLine(pos + QPointF(se->x(), top + se->y() - 20), pos + QPointF(se->x(), top + se->y() + 20));
0214         painter.drawLine(pos + QPointF(se->x() + se->width(), top + se->y() - 20), pos + QPointF(se->x() + se->width(), top + se->y() + 20));
0215 
0216         painter.drawLine(pos + QPointF(se->x() - 10, top + se->y()), pos + QPointF(se->x() + se->width() + 10, top + se->y()));
0217         painter.drawLine(pos + QPointF(se->x() - 10, top + se->y() + se->height()), pos + QPointF(se->x() + se->width() + 10, top + se->y() + se->height()));
0218     }
0219 
0220     Clef *cl = dynamic_cast<Clef*>(se);
0221     if (cl) renderClef(painter, cl, pos, state, color);
0222     KeySignature *ks = dynamic_cast<KeySignature*>(se);
0223     if (ks) renderKeySignature(painter, ks, pos, state, color);
0224     TimeSignature* ts = dynamic_cast<TimeSignature*>(se);
0225     if (ts) renderTimeSignature(painter, ts, pos, color);
0226 }
0227 
0228 
0229 void MusicRenderer::renderClef(QPainter& painter, Clef *c, const QPointF& pos, RenderState& state, const QColor& color, bool ignoreOwnPos)
0230 {
0231     Q_UNUSED(color);
0232     state.clef = c;
0233     Staff* s = c->staff();
0234     m_style->renderClef(painter, pos.x() + (ignoreOwnPos ? 0 : c->x()), pos.y() + s->top() + (s->lineCount() - c->line()) * s->lineSpacing(), c->shape());
0235 }
0236 
0237 void MusicRenderer::renderKeySignature(QPainter& painter, KeySignature* ks, const QPointF& pos, RenderState& state, const QColor& color, bool ignoreOwnPos)
0238 {
0239     Q_UNUSED(color);
0240     Staff * s = ks->staff();
0241     qreal curx = pos.x() + (ignoreOwnPos ? 0 : ks->x());
0242     // draw naturals for sharps
0243     int idx = 3;
0244     for (int i = 0; i < 7; i++) {
0245         if (ks->cancel(idx) > 0) {
0246             int line = 10;
0247             if (state.clef) line = state.clef->pitchToLine(idx);
0248 
0249             while (line < 0) line += 7;
0250             while (line >= 6) line -= 7;
0251             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 0 );
0252 
0253             curx += 6;
0254         }
0255         idx = (idx + 4) % 7;
0256     }
0257 
0258     // draw naturals for flats
0259     idx = 6;
0260     for (int i = 0; i < 7; i++) {
0261         if (ks->cancel(idx) < 0) {
0262             int line = 10;
0263             if (state.clef) line = state.clef->pitchToLine(idx);
0264 
0265             while (line < 0) line += 7;
0266             while (line >= 6) line -= 7;
0267 
0268             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 0 );
0269 
0270             curx += 6;
0271         }
0272         idx = (idx + 3) % 7;
0273     }
0274 
0275     // draw sharps
0276     idx = 3;
0277     for (int i = 0; i < 7; i++) {
0278         if (ks->accidentals(idx) > 0) {
0279             int line = 10;
0280             if (state.clef) line = state.clef->pitchToLine(idx);
0281 
0282             while (line < 0) line += 7;
0283             while (line >= 6) line -= 7;
0284             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 1 );
0285 
0286             curx += 6;
0287         }
0288         idx = (idx + 4) % 7;
0289     }
0290 
0291     // draw flats
0292     idx = 6;
0293     for (int i = 0; i < 7; i++) {
0294         if (ks->accidentals(idx) < 0) {
0295             int line = 10;
0296             if (state.clef) line = state.clef->pitchToLine(idx);
0297 
0298             while (line < 0) line += 7;
0299             while (line >= 6) line -= 7;
0300 
0301             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, -1 );
0302 
0303             curx += 6;
0304         }
0305         idx = (idx + 3) % 7;
0306     }
0307 }
0308 
0309 void MusicRenderer::renderTimeSignature(QPainter& painter, TimeSignature* ts, const QPointF& pos, const QColor& color)
0310 {
0311     Q_UNUSED(color);
0312     Staff* s = ts->staff();
0313     qreal hh = 0.5 * (s->lineCount() - 1) * s->lineSpacing();
0314     m_style->renderTimeSignatureNumber( painter, pos.x() + ts->x(), pos.y() + s->top() + hh, ts->width(), ts->beats());
0315     m_style->renderTimeSignatureNumber( painter, pos.x() + ts->x(), pos.y() + s->top() + 2*hh, ts->width(), ts->beat());
0316 }
0317 
0318 void MusicRenderer::renderRest(QPainter& painter, Duration duration, const QPointF& pos, const QColor& color)
0319 {
0320     m_style->renderRest(painter, pos.x(), pos.y(), duration, color);
0321 }
0322 
0323 void MusicRenderer::renderChord(QPainter& painter, Chord* chord, Voice* voice, const QPointF& ref, const QColor& color)
0324 {
0325     qreal x = chord->x();
0326     if (chord->noteCount() == 0) { // a rest
0327         Staff *s = chord->staff();
0328         renderRest(painter, chord->duration(), ref + QPointF(x, s->top() + (2 - (chord->duration() == WholeNote)) * s->lineSpacing()), color);
0329         return;
0330     }
0331     int topLine = 0, bottomLine = 0;
0332     VoiceBar* vb = chord->voiceBar();
0333     Bar* bar = vb->bar();
0334     Sheet* sheet = voice->part()->sheet();
0335     int barIdx = bar->sheet()->indexOfBar(bar);
0336     qreal topy = 1e9, bottomy = -1e9;
0337     Staff* topStaff = 0, *bottomStaff = 0;
0338 
0339     qreal mainNoteX = (chord->stemDirection() == StemUp ? chord->stemX() - 6 : chord->stemX());
0340     qreal alternateNoteX = mainNoteX + (chord->stemDirection() == StemUp ? 6 : -6);
0341     bool prevAlternate = false;
0342     qreal maxNoteX = 0;
0343 
0344     QMultiMap<Staff*, int> dots;
0345 
0346     Chord* nextChord = 0;
0347 
0348     for (int i = 0; i < chord->noteCount(); i++) {
0349         Note *n = chord->note(i);
0350         Staff * s = n->staff();
0351         Clef* clef = s->lastClefChange(barIdx);
0352         int line = 10;
0353         if (clef) line = clef->pitchToLine(n->pitch());
0354 
0355         qreal noteX = mainNoteX;
0356         if (i > 0) {
0357             int prevPitch = chord->note(i-1)->pitch();
0358             if (abs(prevPitch - n->pitch()) <= 1 && !prevAlternate) {
0359                 noteX = alternateNoteX;
0360             }
0361         }
0362         if (i < chord->noteCount()-1 && chord->stemDirection() == StemDown) {
0363             int pitch = n->pitch();
0364             int nPitch = chord->note(i+1)->pitch();
0365             if (abs(pitch - nPitch) <= 1 && !prevAlternate) {
0366                 noteX = alternateNoteX;
0367             }
0368         }
0369         prevAlternate = noteX != mainNoteX;
0370         if (noteX > maxNoteX) maxNoteX = noteX;
0371 
0372         if (line > 9) { // lines under the bar
0373             painter.setPen(m_style->staffLinePen(color));
0374             for (int i = 10; i <= line; i+= 2) {
0375                 qreal y = s->top() + i * s->lineSpacing() / 2;
0376                 painter.drawLine(ref + QPointF(noteX - 4, y), ref + QPointF(noteX + 10, y));
0377             }
0378         } else if (line < -1) { // lines above the bar
0379             painter.setPen(m_style->staffLinePen(color));
0380             for (int i = -2; i >= line; i-= 2) {
0381                 qreal y = s->top() + i * s->lineSpacing() / 2;
0382                 painter.drawLine(ref + QPointF(noteX - 4, y), ref + QPointF(noteX + 10, y));
0383             }
0384         }
0385 
0386         qreal ypos = s->top() + line * s->lineSpacing() / 2;
0387         if (ypos < topy) {
0388             topy = ypos;
0389             topLine = line;
0390             topStaff = s;
0391         }
0392         if (ypos > bottomy) {
0393             bottomy = ypos;
0394             bottomLine = line;
0395             bottomStaff = s;
0396         }
0397 
0398         m_style->renderNoteHead( painter, ref.x() + noteX, ref.y() + s->top() + line * s->lineSpacing() / 2, chord->duration(), color );
0399 
0400         // render accidentals
0401         if (n->drawAccidentals()) {
0402             m_style->renderAccidental( painter, ref.x() + x, ref.y() + /*chord->y() +*/ s->top() + line * s->lineSpacing() / 2, n->accidentals(), color );
0403         }
0404 
0405         dots.insert(s, line);
0406 
0407         if (n->isStartTie()) {
0408             // render tie for this note...
0409             if (!nextChord) {
0410                 // figure out what the next chord in this voice is
0411                 bool afterCurrent = false;
0412                 for (int e = 0; e < vb->elementCount(); e++) {
0413                     if (afterCurrent) {
0414                         nextChord = dynamic_cast<Chord*>(vb->element(e));
0415                         if (nextChord) break;
0416                     } else {
0417                         if (vb->element(e) == chord) {
0418                             afterCurrent = true;
0419                         }
0420                     }
0421                 }
0422                 if (!nextChord) {
0423                     // check the next bar
0424                     int nextBar = sheet->indexOfBar(bar)+1;
0425                     if (nextBar < sheet->barCount()) {
0426                         VoiceBar* nextVB = voice->bar(nextBar);
0427                         for (int e = 0; e < nextVB->elementCount(); e++) {
0428                             nextChord = dynamic_cast<Chord*>(nextVB->element(e));
0429                             if (nextChord) break;
0430                         }
0431                     }
0432                 }
0433             }
0434 
0435             // okay, now nextChord is the chord to which the tie should go
0436             if (nextChord) {
0437                 QPointF startPos = bar->position() + QPointF(1 + chord->x() + chord->width(), ypos);
0438                 QPointF endPos = nextChord->voiceBar()->bar()->position() + QPointF(nextChord->x() - 1, ypos);
0439                 if (bar->position().y() < nextChord->voiceBar()->bar()->position().y() - 1e-6) {
0440                     endPos = bar->position() + QPointF(bar->size(), 0);
0441                 }
0442 
0443                 endPos.setY(startPos.y());
0444                 QPointF c1a = startPos + QPointF(2, 4);
0445                 QPointF c2a = endPos + QPointF(-2, 4);
0446                 QPointF c1b = startPos + QPointF(2, 5);
0447                 QPointF c2b = endPos + QPointF(-2, 5);
0448 
0449                 QPainterPath p;
0450                 p.moveTo(startPos);
0451                 p.cubicTo(c1a, c2a, endPos);
0452                 p.cubicTo(c2b, c1b, startPos);
0453                 painter.setPen(Qt::NoPen);//m_style->slurPen(color));
0454                 painter.setBrush(QBrush(color));
0455                 painter.drawPath(p);
0456             }
0457         }
0458     }
0459 
0460     // calculate correct positioning of dots
0461     // render dots of notes
0462     painter.setPen(m_style->noteDotPen(color));
0463     foreach (Staff* s, dots.keys()) {
0464         QList<int> lines = dots.values(s);
0465         std::sort(lines.begin(), lines.end());
0466 
0467         int lastLine = INT_MIN;
0468         bool moveGroupDown = true;
0469         for (int i = 0; i < lines.size(); i++) {
0470             int line = lines[i];
0471             if (line % 2 == 0) {
0472                 line--;
0473             }
0474             if (line == lastLine) {
0475                 if (moveGroupDown) {
0476                     lines[i-1] += 2;
0477                     for (int j = i-2; j >= 0; j--) {
0478                         if (lines[j] == lines[j+1]) {
0479                             lines[j] += 2;
0480                         } else {
0481                             break;
0482                         }
0483                     }
0484                 } else {
0485                     line -= 2;
0486                 }
0487                 moveGroupDown = !moveGroupDown;
0488             }
0489             lines[i] = line;
0490             lastLine = line;
0491         }
0492 
0493         foreach (int line, lines) {
0494             qreal dotX = maxNoteX + 11;
0495             for (int i = 0; i < chord->dots(); i++) {
0496                 painter.drawPoint(ref + QPointF(dotX, s->top() + line * s->lineSpacing() / 2));
0497                 dotX += 3;
0498             }
0499         }
0500     }
0501 
0502     qreal stemLen = chord->stemLength() * 2;
0503     if (stemLen != 0.0 && stemLen != -0.0) {
0504         qreal stemX = chord->stemX();
0505         bool stemsUp = chord->stemDirection() == StemUp;
0506 
0507         painter.setPen(m_style->stemPen(color));
0508         if (stemsUp) {
0509             painter.drawLine(ref + QPointF(stemX, chord->stemEndY()),
0510                              ref + QPointF(stemX, bottomStaff->top() + bottomLine * bottomStaff->lineSpacing() / 2));
0511             if (chord->beamType(0) == BeamFlag) {
0512                 m_style->renderNoteFlags( painter, ref.x() + stemX, ref.y() + chord->stemEndY(), chord->duration(), stemsUp, color );
0513             }
0514         } else {
0515             painter.drawLine(ref + QPointF(stemX, topStaff->top() + topLine * topStaff->lineSpacing() / 2),
0516                              ref + QPointF(stemX, chord->stemEndY()));
0517             if (chord->beamType(0) == BeamFlag) {
0518                 m_style->renderNoteFlags( painter, ref.x() + stemX, ref.y() + chord->stemEndY(), chord->duration(), stemsUp, color );
0519             }
0520         }
0521 
0522         painter.setPen(QPen(Qt::NoPen));
0523         painter.setBrush(QBrush(color));
0524         for (int i = 0; i < chord->beamCount(); i++) {
0525             if (chord->beamType(i) == BeamStart) {
0526                 const Chord* endChord = chord->beamEnd(i);
0527 
0528                 QPointF beamStart(chord->stemX(), chord->stemEndY());
0529                 QPointF beamEnd(endChord->stemX(), endChord->stemEndY());
0530                 if (stemsUp) {
0531                     beamStart += QPointF(0, topStaff->lineSpacing() * i);
0532                     beamEnd += QPointF(0, topStaff->lineSpacing() * i);
0533                 } else {
0534                     beamStart -= QPointF(0, bottomStaff->lineSpacing() * i);
0535                     beamEnd -= QPointF(0, bottomStaff->lineSpacing() * i);
0536                 }
0537 
0538 
0539                 QPointF dir(0, (stemsUp ? 1 : -1) * m_style->beamLineWidth());
0540                 QPointF p[4];
0541                 p[0] = ref + beamStart;
0542                 p[1] = ref + beamEnd;
0543                 p[2] = p[1] + dir;
0544                 p[3] = p[0] + dir;
0545                 painter.drawConvexPolygon(p, 4);
0546             } else if (chord->beamType(i) == BeamForwardHook || chord->beamType(i) == BeamBackwardHook) {
0547                 QPointF beamStart(chord->stemX(), chord->stemEndY());
0548                 qreal dir = 6;
0549                 if (chord->beamType(i) == BeamBackwardHook) dir = -dir;
0550                 if (stemsUp) {
0551                     beamStart += QPointF(0, topStaff->lineSpacing() * i);
0552                 } else {
0553                     beamStart -= QPointF(0, bottomStaff->lineSpacing() * i);
0554                 }
0555 
0556                 QPointF beamEnd = beamStart + QPointF(dir, dir * chord->beamDirection());
0557 
0558                 QPointF bdir(0, (stemsUp ? 1 : -1) * m_style->beamLineWidth());
0559                 QPointF p[4];
0560                 p[0] = ref + beamStart;
0561                 p[1] = ref + beamEnd;
0562                 p[2] = p[1] + bdir;
0563                 p[3] = p[0] + bdir;
0564                 painter.drawConvexPolygon(p, 4);
0565             }
0566         }
0567 
0568     }
0569 }
0570 
0571 void MusicRenderer::renderNote(QPainter& painter, Duration duration, const QPointF& pos, qreal stemLength, const QColor& color)
0572 {
0573     m_style->renderNoteHead(painter, pos.x(), pos.y(), duration, color);
0574 
0575     if (duration <= HalfNote) {
0576         painter.setPen(m_style->stemPen(color));
0577         painter.drawLine(pos + QPointF(6, -stemLength), pos + QPointF(6, 0));
0578     }
0579     if (duration <= EighthNote) {
0580         m_style->renderNoteFlags(painter, pos.x()+6, pos.y() - stemLength, duration, true, color);
0581     }
0582 }
0583 
0584 void MusicRenderer::renderAccidental(QPainter& painter, int accidentals, const QPointF& pos, const QColor& color)
0585 {
0586     m_style->renderAccidental( painter, pos.x(), pos.y(), accidentals, color );
0587 }