471 lines
19 KiB
C++
471 lines
19 KiB
C++
//=============================================================================
|
|
// MusE Score
|
|
// Linux Music Score Editor
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 2009 Werner Schweer and others
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//=============================================================================
|
|
|
|
#include "piano.h"
|
|
|
|
namespace Ms {
|
|
|
|
QPixmap* Piano::octave;
|
|
QPixmap* Piano::mk1;
|
|
QPixmap* Piano::mk2;
|
|
QPixmap* Piano::mk3;
|
|
QPixmap* Piano::mk4;
|
|
|
|
//---------------------------------------------------------
|
|
// Piano
|
|
//---------------------------------------------------------
|
|
|
|
Piano::Piano(QWidget* parent)
|
|
: QWidget(parent)
|
|
{
|
|
setMouseTracking(true);
|
|
_ymag = 1.0;
|
|
setAttribute(Qt::WA_NoSystemBackground);
|
|
setAttribute(Qt::WA_StaticContents);
|
|
setMouseTracking(true);
|
|
|
|
/*
|
|
0 1 2 3 4 5 6 7 8 9 10
|
|
c-2 c-1 C0 C1 C2 C3 C4 C5 C6 C7 C8 - G8
|
|
|
|
Grid ve:
|
|
|
|
+------------+ ------------------------------
|
|
11 | |
|
|
| b | 7
|
|
+------+ |
|
|
10 | a# +-----+ ..............................
|
|
+------+ a |
|
|
9 | | 6
|
|
+------+ |
|
|
8 | g# +-----+ ..............................
|
|
+------+ g |
|
|
7 | | 5
|
|
+------+ |
|
|
6 | f# +-----+ ..............................
|
|
+------+ f |
|
|
5 | | 4
|
|
| |
|
|
+------------+ ------------------------------
|
|
4 | |
|
|
| e | 3
|
|
+------+ |
|
|
3 | d# +-----+ ..............................
|
|
+------+ d |
|
|
2 | | 2
|
|
+------+ |
|
|
1 | c# +-----+ ..............................
|
|
+------+ c |
|
|
| | 1
|
|
0 | |
|
|
+------------+ ------------------------------
|
|
*/
|
|
|
|
static const char *oct_xpm[] = {
|
|
// w h colors
|
|
"40 91 2 1",
|
|
". c #f0f0f0",
|
|
"# c #000000",
|
|
// x
|
|
"####################################### ",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 10
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", //------------------------
|
|
"#######################................#",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"####################################### ", // 7
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"#######################................#", //------------------------
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 6
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", //------------------------
|
|
"#######################................#",
|
|
"########################...............#",
|
|
"########################...............#", // 7
|
|
"####################################### ",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"#######################................#", //------------------------
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 6
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", //------------------------
|
|
"#######################................#",
|
|
"########################...............#",
|
|
"########################...............#", // 7
|
|
"####################################### ",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"#######################................#", //------------------------
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 10
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
"####################################### ", //----------------------
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 9
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", //------------------------
|
|
"#######################................#",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"####################################### ", // 7
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"#######################................#", //------------------------
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 6
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", //--------------------------
|
|
"#######################................#",
|
|
"########################...............#",
|
|
"########################...............#", // 7
|
|
"####################################### ",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"#######################................#", //------------------------
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 10
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
};
|
|
|
|
static const char *mk1_xpm[] = {
|
|
"40 13 2 1",
|
|
". c #ff0000",
|
|
"# c none",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
"#######################................#",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"####################################### ",
|
|
};
|
|
|
|
static const char *mk2_xpm[] = {
|
|
"40 13 2 1",
|
|
". c #ff0000",
|
|
"# c none",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"#######################................#", //------------------------
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", // 6
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#", //--------------------------
|
|
"#######################................#",
|
|
"########################...............#",
|
|
"########################...............#", // 7
|
|
"####################################### ",
|
|
};
|
|
|
|
static const char *mk3_xpm[] = {
|
|
"40 13 2 1",
|
|
". c #ff0000",
|
|
"# c none",
|
|
"########################...............#",
|
|
"########################...............#",
|
|
"#######################................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
".......................................#",
|
|
"########################################",
|
|
};
|
|
|
|
static const char *mk4_xpm[] = {
|
|
"40 13 2 1",
|
|
"# c #ff0000",
|
|
". c none",
|
|
"........................................",
|
|
"........................................",
|
|
"........................................",
|
|
"#######################.................",
|
|
"########################................",
|
|
"########################................",
|
|
"########################................",
|
|
"########################................",
|
|
"########################................",
|
|
"#######################.................",
|
|
"........................................",
|
|
"........................................",
|
|
"........................................",
|
|
};
|
|
|
|
if (octave == 0) {
|
|
octave = new QPixmap(oct_xpm);
|
|
mk1 = new QPixmap(mk1_xpm);
|
|
mk2 = new QPixmap(mk2_xpm);
|
|
mk3 = new QPixmap(mk3_xpm);
|
|
mk4 = new QPixmap(mk4_xpm);
|
|
}
|
|
yRange = keyHeight * 75;
|
|
curPitch = -1;
|
|
_ypos = 0;
|
|
curKeyPressed = -1;
|
|
_orientation = PianoOrientation::VERTICAL;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// pitch2y
|
|
// y = 0 == origin of rCanvasA
|
|
//---------------------------------------------------------
|
|
|
|
int Piano::pitch2y(int pitch) const
|
|
{
|
|
static int tt[] = {
|
|
12, 19, 25, 32, 38, 51, 58, 64, 71, 77, 84, 90
|
|
};
|
|
int y = (75 * keyHeight) - (tt[pitch % 12] + (7 * keyHeight) * (pitch / 12));
|
|
if (y < 0)
|
|
y = 0;
|
|
return lrint(y - _ypos / _ymag);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// y2pitch
|
|
// y = 0 == origin of rCanvasA
|
|
//---------------------------------------------------------
|
|
|
|
int Piano::y2pitch(int y) const
|
|
{
|
|
y = lrint((y + _ypos) / _ymag);
|
|
static const int total = (10 * 7 + 5) * keyHeight; // 75 steps
|
|
y = total - y;
|
|
int oct = (y / (7 * keyHeight)) * 12;
|
|
static const char kt[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
1, 1, 1, 1, 1, 1, 1,
|
|
2, 2, 2, 2, 2, 2,
|
|
3, 3, 3, 3, 3, 3, 3,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
6, 6, 6, 6, 6, 6, 6,
|
|
7, 7, 7, 7, 7, 7,
|
|
8, 8, 8, 8, 8, 8, 8,
|
|
9, 9, 9, 9, 9, 9,
|
|
10, 10, 10, 10, 10, 10, 10,
|
|
11, 11, 11, 11, 11, 11, 11, 11, 11, 11
|
|
};
|
|
int pitch = kt[y % 91] + oct;
|
|
if (pitch < 0 || pitch > 127)
|
|
pitch = -1;
|
|
return pitch;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// paint
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::paintEvent(QPaintEvent* event)
|
|
{
|
|
QPainter p(this);
|
|
const QRect& rr = event->rect();
|
|
QRect r;
|
|
if (_orientation == PianoOrientation::HORIZONTAL) {
|
|
int w = keyHeight * 52;
|
|
p.translate(w, 0);
|
|
p.rotate(90.0);
|
|
r.setWidth(rr.height());
|
|
r.setHeight(rr.width());
|
|
r.setX(0);
|
|
r.setY(0);
|
|
}
|
|
else
|
|
r = rr;
|
|
p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
|
|
int d = int(_ymag)+1;
|
|
qreal x = qreal(r.x());
|
|
qreal y = 0.0;
|
|
qreal h = (r.height()+d) / _ymag;
|
|
QPointF offset(x, _ypos / _ymag + keyHeight * 2 + y);
|
|
|
|
p.scale(1.0, _ymag);
|
|
p.drawTiledPixmap(QRectF(x, y, qreal(r.width()), h), *octave, offset);
|
|
|
|
if (curPitch != -1) {
|
|
int py = pitch2y(curPitch);
|
|
QPixmap* pm;
|
|
switch(curPitch % 12) {
|
|
case 0:
|
|
case 5:
|
|
pm = mk3;
|
|
break;
|
|
case 2:
|
|
case 7:
|
|
case 9:
|
|
pm = mk2;
|
|
break;
|
|
case 4:
|
|
case 11:
|
|
pm = mk1;
|
|
break;
|
|
default:
|
|
pm = mk4;
|
|
break;
|
|
}
|
|
p.drawPixmap(0, py, *pm);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setYpos
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::setYpos(int val)
|
|
{
|
|
if (_ypos != val) {
|
|
_ypos = val;
|
|
update();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setMag
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::setMag(double, double ym)
|
|
{
|
|
if (_ymag != ym) {
|
|
_ymag = ym;
|
|
update();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setPitch
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::setPitch(int val)
|
|
{
|
|
if (curPitch != val) {
|
|
curPitch = val;
|
|
update();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mousePressEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
curKeyPressed = y2pitch(event->pos().y());
|
|
emit keyPressed(curKeyPressed);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseReleaseEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::mouseReleaseEvent(QMouseEvent*)
|
|
{
|
|
emit keyReleased(curKeyPressed);
|
|
curKeyPressed = -1;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseMoveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::mouseMoveEvent(QMouseEvent* event)
|
|
{
|
|
int pitch = y2pitch(event->pos().y());
|
|
if (pitch != curPitch) {
|
|
curPitch = pitch;
|
|
emit pitchChanged(curPitch);
|
|
if ((curKeyPressed != -1) && (curKeyPressed != pitch)) {
|
|
emit keyReleased(curKeyPressed);
|
|
curKeyPressed = pitch;
|
|
emit keyPressed(curKeyPressed);
|
|
}
|
|
update();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// leaveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::leaveEvent(QEvent*)
|
|
{
|
|
if (curPitch != -1) {
|
|
curPitch = -1;
|
|
emit pitchChanged(-1);
|
|
update();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setOrientation
|
|
//---------------------------------------------------------
|
|
|
|
void Piano::setOrientation(PianoOrientation o)
|
|
{
|
|
_orientation = o;
|
|
update();
|
|
}
|
|
}
|
|
|