annotate layer/PianoScale.cpp @ 1551:e79731086b0f

Fixes to NoteLayer, particularly to calculation of vertical scale when model unit is not Hz. To avoid inconsistency we now behave as if the unit is always Hz from the point of view of the external API and display, converting at the point where we obtain values from the events themselves. Also various fixes to editing.
author Chris Cannam
date Thu, 21 Nov 2019 14:02:57 +0000
parents f2525e6cbdf1
children
rev   line source
Chris@690 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@690 2
Chris@690 3 /*
Chris@690 4 Sonic Visualiser
Chris@690 5 An audio file viewer and annotation editor.
Chris@690 6 Centre for Digital Music, Queen Mary, University of London.
Chris@690 7 This file copyright 2006-2013 Chris Cannam and QMUL.
Chris@690 8
Chris@690 9 This program is free software; you can redistribute it and/or
Chris@690 10 modify it under the terms of the GNU General Public License as
Chris@690 11 published by the Free Software Foundation; either version 2 of the
Chris@690 12 License, or (at your option) any later version. See the file
Chris@690 13 COPYING included with this distribution for more information.
Chris@690 14 */
Chris@690 15
Chris@690 16 #include "PianoScale.h"
Chris@690 17
Chris@690 18 #include <QPainter>
Chris@690 19
Chris@690 20 #include <cmath>
Chris@690 21
Chris@690 22 #include "base/Pitch.h"
Chris@690 23
Chris@1077 24 #include "LayerGeometryProvider.h"
Chris@1276 25 #include "HorizontalScaleProvider.h"
Chris@690 26
Chris@1238 27 #include <iostream>
Chris@1238 28 using namespace std;
Chris@1238 29
Chris@690 30 void
Chris@918 31 PianoScale::paintPianoVertical(LayerGeometryProvider *v,
Chris@1266 32 QPainter &paint,
Chris@1266 33 QRect r,
Chris@1266 34 double minf,
Chris@1266 35 double maxf)
Chris@690 36 {
Chris@690 37 int x0 = r.x(), y0 = r.y(), x1 = r.x() + r.width(), y1 = r.y() + r.height();
Chris@690 38
Chris@690 39 paint.drawLine(x0, y0, x0, y1);
Chris@690 40
Chris@690 41 int py = y1, ppy = y1;
Chris@690 42 paint.setBrush(paint.pen().color());
Chris@690 43
Chris@690 44 for (int i = 0; i < 128; ++i) {
Chris@690 45
Chris@1266 46 double f = Pitch::getFrequencyForPitch(i);
Chris@1266 47 int y = int(lrint(v->getYForFrequency(f, minf, maxf, true)));
Chris@690 48
Chris@1266 49 if (y < y0 - 2) break;
Chris@1266 50 if (y > y1 + 2) {
Chris@1266 51 continue;
Chris@1266 52 }
Chris@1266 53
Chris@1266 54 int n = (i % 12);
Chris@1266 55
Chris@1266 56 if (n == 1) {
Chris@1266 57 // C# -- fill the C from here
Chris@1266 58 QColor col = Qt::gray;
Chris@1266 59 if (i == 61) { // filling middle C
Chris@1266 60 col = Qt::blue;
Chris@1471 61 col = col.lighter(150);
Chris@1266 62 }
Chris@1266 63 if (ppy - y > 2) {
Chris@1266 64 paint.fillRect(x0 + 1,
Chris@1266 65 y,
Chris@1266 66 x1 - x0,
Chris@1266 67 (py + ppy) / 2 - y,
Chris@1266 68 col);
Chris@1266 69 }
Chris@1266 70 }
Chris@1266 71
Chris@1266 72 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) {
Chris@1266 73 // black notes
Chris@1266 74 paint.drawLine(x0 + 1, y, x1, y);
Chris@1266 75 int rh = ((py - y) / 4) * 2;
Chris@1266 76 if (rh < 2) rh = 2;
Chris@1266 77 paint.drawRect(x0 + 1, y - (py-y)/4, (x1 - x0) / 2, rh);
Chris@1266 78 } else if (n == 0 || n == 5) {
Chris@1266 79 // C, F
Chris@1266 80 if (py < y1) {
Chris@1266 81 paint.drawLine(x0 + 1, (y + py) / 2, x1, (y + py) / 2);
Chris@1266 82 }
Chris@1266 83 }
Chris@1266 84
Chris@1266 85 ppy = py;
Chris@1266 86 py = y;
Chris@690 87 }
Chris@690 88 }
Chris@690 89
Chris@1238 90 void
Chris@1238 91 PianoScale::paintPianoHorizontal(LayerGeometryProvider *v,
Chris@1238 92 const HorizontalScaleProvider *p,
Chris@1238 93 QPainter &paint,
Chris@1238 94 QRect r)
Chris@1238 95 {
Chris@1238 96 int x0 = r.x(), y0 = r.y(), x1 = r.x() + r.width(), y1 = r.y() + r.height();
Chris@1238 97
Chris@1238 98 paint.drawLine(x0, y0, x1, y0);
Chris@1238 99
Chris@1238 100 int px = x0, ppx = x0;
Chris@1238 101 paint.setBrush(paint.pen().color());
Chris@1238 102
Chris@1238 103 for (int i = 0; i < 128; ++i) {
Chris@1238 104
Chris@1238 105 double f = Pitch::getFrequencyForPitch(i);
Chris@1238 106 int x = int(lrint(p->getXForFrequency(v, f)));
Chris@1238 107
Chris@1238 108 if (i == 0) {
Chris@1238 109 px = ppx = x;
Chris@1238 110 }
Chris@1238 111 if (i == 1) {
Chris@1238 112 ppx = px - (x - px);
Chris@1238 113 }
Chris@1238 114
Chris@1238 115 if (x < x0) {
Chris@1238 116 ppx = px;
Chris@1238 117 px = x;
Chris@1238 118 continue;
Chris@1238 119 }
Chris@1238 120
Chris@1238 121 if (x > x1) {
Chris@1238 122 break;
Chris@1238 123 }
Chris@1238 124
Chris@1238 125 int n = (i % 12);
Chris@1238 126
Chris@1238 127 if (n == 1) {
Chris@1238 128 // C# -- fill the C from here
Chris@1238 129 QColor col = Qt::gray;
Chris@1238 130 if (i == 61) { // filling middle C
Chris@1238 131 col = Qt::blue;
Chris@1471 132 col = col.lighter(150);
Chris@1238 133 }
Chris@1238 134 if (x - ppx > 2) {
Chris@1238 135 paint.fillRect((px + ppx) / 2 + 1,
Chris@1238 136 y0 + 1,
Chris@1238 137 x - (px + ppx) / 2 - 1,
Chris@1238 138 y1 - y0,
Chris@1238 139 col);
Chris@1238 140 }
Chris@1238 141 }
Chris@1238 142
Chris@1238 143 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) {
Chris@1238 144 // black notes
Chris@1238 145 paint.drawLine(x, y0, x, y1);
Chris@1238 146 int rw = int(lrint(double(x - px) / 4) * 2);
Chris@1238 147 if (rw < 2) rw = 2;
Chris@1238 148 paint.drawRect(x - rw/2, (y0 + y1) / 2, rw, (y1 - y0) / 2);
Chris@1238 149 } else if (n == 0 || n == 5) {
Chris@1238 150 // C, F
Chris@1238 151 if (px < x1) {
Chris@1238 152 paint.drawLine((x + px) / 2, y0, (x + px) / 2, y1);
Chris@1238 153 }
Chris@1238 154 }
Chris@1238 155
Chris@1238 156 ppx = px;
Chris@1238 157 px = x;
Chris@1238 158 }
Chris@1238 159 }
Chris@1238 160
Chris@1238 161