From 6c643a69a585bdcdfc7605899e515b545f966b44 Mon Sep 17 00:00:00 2001 From: SeeLook <945374+SeeLook@users.noreply.github.com> Date: Thu, 13 Apr 2017 21:04:13 +0200 Subject: [PATCH] Implemented piano keyboard, clicking keys adds note to the score --- picts/pianokey.png | Bin 0 -> 6615 bytes spare_parts/scalable/pianokey.svg | 190 +++++++++++++++++++++++++ src/libs/core/CMakeLists.txt | 1 + src/libs/core/instruments/tpianobg.cpp | 164 +++++++++++++++++++++ src/libs/core/instruments/tpianobg.h | 93 ++++++++++++ src/libs/core/tnootkaqml.cpp | 7 + src/libs/core/tnootkaqml.h | 1 + src/nootka.qrc | 1 + src/qml/MainWindow.qml | 26 +--- src/qml/instruments/Instrument.qml | 15 +- 10 files changed, 474 insertions(+), 24 deletions(-) create mode 100644 picts/pianokey.png create mode 100644 spare_parts/scalable/pianokey.svg create mode 100644 src/libs/core/instruments/tpianobg.cpp create mode 100644 src/libs/core/instruments/tpianobg.h diff --git a/picts/pianokey.png b/picts/pianokey.png new file mode 100644 index 0000000000000000000000000000000000000000..f67d8b9d34ea0714833aa828f2e4db79bea2d4bf GIT binary patch literal 6615 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 literal 0 HcmV?d00001 diff --git a/spare_parts/scalable/pianokey.svg b/spare_parts/scalable/pianokey.svg new file mode 100644 index 000000000..90433ab2a --- /dev/null +++ b/spare_parts/scalable/pianokey.svg @@ -0,0 +1,190 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="52.44693" + height="161.68961" + id="svg4626" + sodipodi:version="0.32" + inkscape:version="0.92.1 r" + sodipodi:docname="pianokey.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="../../picts/pianokey.png" + inkscape:export-xdpi="234.52342" + inkscape:export-ydpi="234.52342"> + <metadata + id="metadata31"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <cc:license + rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" /> + <dc:title></dc:title> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> + <cc:permits + rdf:resource="http://web.resource.org/cc/Reproduction" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/Distribution" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/Notice" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/ShareAlike" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/SourceCode" /> + </cc:License> + </rdf:RDF> + </metadata> + <sodipodi:namedview + inkscape:window-height="1039" + inkscape:window-width="1920" + inkscape:pageshadow="2" + inkscape:pageopacity="1" + guidetolerance="0.4" + gridtolerance="0.4" + objecttolerance="0.4" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#000000" + id="base" + showborder="true" + inkscape:showpageshadow="false" + showgrid="false" + inkscape:zoom="1" + inkscape:cx="-367.46148" + inkscape:cy="127.28471" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:current-layer="svg4626" + inkscape:window-maximized="1" + inkscape:pagecheckerboard="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0"> + <inkscape:grid + id="GridFromPre046Settings" + type="xygrid" + originx="-1.024" + originy="-0.95999368" + spacingx="0.10666667" + spacingy="0.10666667" + color="#3f3fff" + empcolor="#3f3fff" + opacity="0.15" + empopacity="0.38" + empspacing="5" /> + </sodipodi:namedview> + <defs + id="defs4628"> + <linearGradient + id="linearGradient5164"> + <stop + style="stop-color:#ffffff;stop-opacity:1" + offset="0" + id="stop5166" /> + <stop + style="stop-color:#000000;stop-opacity:0" + offset="1" + id="stop5168" /> + </linearGradient> + <linearGradient + id="linearGradient3230"> + <stop + style="stop-color:#000000;stop-opacity:0" + offset="0" + id="stop3232" /> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="1" + id="stop3234" /> + </linearGradient> + <linearGradient + id="linearGradient3916"> + <stop + style="stop-color:#000000;stop-opacity:0" + offset="0" + id="stop3918" /> + <stop + style="stop-color:#ffffff;stop-opacity:1" + offset="1" + id="stop3920" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3916" + id="linearGradient5141" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.200802,0,0,1.196659,-269.30906,-322.81977)" + x1="277.40338" + y1="361.15414" + x2="213.72539" + y2="295.93903" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3230" + id="linearGradient5143" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.6939249,0,0,0.92080192,-390.48322,-217.42706)" + x1="261.73914" + y1="416.65976" + x2="236.34105" + y2="392.0029" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5164" + id="linearGradient5145" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.0545831,0,0,1.0653024,-410.68998,-310.06594)" + x1="380.41821" + y1="374.1217" + x2="419.6817" + y2="367.00864" /> + </defs> + <g + id="g5135" + transform="matrix(0.9800699,0,0,0.9908495,-0.58556755,-0.07976399)"> + <rect + id="rect4280" + style="fill:url(#linearGradient5141);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.88976371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1" + y="0.093986385" + x="8.5333338" + ry="0" + rx="0" + height="142.36931" + width="37.439754" /> + <path + sodipodi:nodetypes="ccccccc" + id="path4282" + style="fill:url(#linearGradient5143);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.88976371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-opacity:1" + d="m 45.421134,143.6376 7.462077,18.02772 c 0,0.88527 -0.688754,1.59799 -1.544224,1.59799 H 3.6775574 c -0.8555013,0 -1.5442241,-0.71272 -1.5442241,-1.59799 l 7.5719281,-18.13251 c 14.6279896,-0.0205 21.4195706,0.0755 35.7158726,0.10475 z" + inkscape:connector-curvature="0" /> + <path + sodipodi:nodetypes="cccccc" + id="path4284" + style="fill:url(#linearGradient5145);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.87287581;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1" + d="M 0.73128165,0.15525114 0.59747529,159.39954 c 0,0.84667 0.29061143,1.63388 0.75798171,2.26376 L 8.012514,143.54781 C 7.9745649,95.506362 8.0807462,48.198642 7.9795583,0.15871742 5.5404702,0.16514302 3.1700124,0.15422462 0.73128165,0.15525114 Z" + inkscape:connector-curvature="0" /> + <path + sodipodi:nodetypes="cccccccc" + id="path4286" + style="fill:#ffffff;fill-opacity:0.07843137;fill-rule:evenodd;stroke:none;stroke-width:1.88976371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1" + d="m 46.717221,0.08050061 c -0.01094,0.17468052 -0.03301,0.35330778 -0.03301,0.53437776 V 143.32742 l 6.964617,18.33588 c 0.290119,-0.54256 0.462107,-1.14251 0.462107,-1.80353 V 0.16803924 c 1.1e-5,0.0469058 -0.181876,-0.0205219 -0.177416,-0.0205113 z" + inkscape:connector-curvature="0" /> + </g> +</svg> diff --git a/src/libs/core/CMakeLists.txt b/src/libs/core/CMakeLists.txt index 72a2e480e..4565eb813 100644 --- a/src/libs/core/CMakeLists.txt +++ b/src/libs/core/CMakeLists.txt @@ -40,6 +40,7 @@ set(LIB_NOOTKACORE_SRC score/tbeamobject.cpp instruments/tguitarbg.cpp + instruments/tpianobg.cpp # exam/tqatype.cpp # exam/tqaunit.cpp diff --git a/src/libs/core/instruments/tpianobg.cpp b/src/libs/core/instruments/tpianobg.cpp new file mode 100644 index 000000000..d1e71e8fe --- /dev/null +++ b/src/libs/core/instruments/tpianobg.cpp @@ -0,0 +1,164 @@ +/*************************************************************************** + * Copyright (C) 2017 by Tomasz Bojczuk * + * seelook@gmail.com * + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "tpianobg.h" +#include "tpath.h" +#include "music/tnote.h" + +#include <QtGui/qpainter.h> +#include <QtGui/qguiapplication.h> +#include <QtGui/qscreen.h> +#include <QtCore/qmath.h> +#include <QtCore/qdebug.h> + +#include "checktime.h" + + +TpianoBg::TpianoBg(QQuickItem* parent) : + QQuickPaintedItem(parent), + m_keyWidth(32.0), + m_firstOctave(-2) +{ + setAcceptHoverEvents(true); + setRenderTarget(QQuickPaintedItem::FramebufferObject); + // setPerformanceHint(QQuickPaintedItem::FastFBOResizing); + setAntialiasing(true); + setAcceptedMouseButtons(Qt::LeftButton); +} + + +TpianoBg::~TpianoBg() +{ + +} + + +void TpianoBg::setKeyWidth(qreal kw) { + if (m_keyWidth != kw) { + m_keyWidth = kw; + calculateMetrics(width()); + update(); + } +} + + +void TpianoBg::setNote(const Tnote& n) { + +} + + +void TpianoBg::setFirstOctave(int firstO) { + auto fo = static_cast<char>(firstO); + if (fo != m_firstOctave) { + + } +} + + +void TpianoBg::setReadOnly(bool ro) { + if (ro != m_readOnly) { + m_readOnly = ro; + setAcceptedMouseButtons(m_readOnly ? Qt::NoButton : Qt::LeftButton); + } +} + + +void TpianoBg::paint(QPainter* painter) { +CHECKTIME ( + int kw = qFloor(m_keyWidth); + auto keyPix = QPixmap(Tpath::img("pianokey")).scaled(qRound(m_keyWidth * 0.8), height() / 2, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + painter->setPen(QPen(Qt::black, m_keyWidth / 16, Qt::SolidLine)); + painter->setBrush(Qt::white); + for (int k = 0; k < m_keysNumber; ++k) { + painter->drawRoundedRect(m_margin + k * kw, 1, kw, height() - 2, m_keyWidth / 5, m_keyWidth / 5); + if (k % 7 != 0 && k % 7 != 3) + painter->drawPixmap(m_margin + k * kw - qRound(m_keyWidth * 0.4), kw, keyPix); + } + painter->setBrush(Qt::black); + painter->drawRect(0, 0, width(), kw); + if (m_margin > 0) { + painter->drawRect(0, kw, m_margin, height() - kw); + painter->drawRect(width() - m_margin, kw, m_margin, height() - kw); + } +) +} + +//################################################################################################# +//################### PROTECTED ############################################ +//################################################################################################# + +void TpianoBg::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) { + if (oldGeometry.width() != newGeometry.width() || oldGeometry.height() != newGeometry.height()) { + calculateMetrics(qFloor(newGeometry.width())); + update(); + } +} + + +void TpianoBg::hoverEnterEvent(QHoverEvent*) { + m_active = true; + emit activeChanged(); +} + + +void TpianoBg::hoverLeaveEvent(QHoverEvent*) { + m_active = false; + m_keyRect = QRectF(); + emit activeChanged(); + emit keyRectChanged(); +} + + +void TpianoBg::hoverMoveEvent(QHoverEvent* event) { + if (event->pos().y() > m_keyWidth) { + int kw = qFloor(m_keyWidth); + int keyNr = qFloor((event->pos().x() - m_margin) / kw); + Tnote newNote(static_cast<char>(keyNr % 7 + 1), m_firstOctave + static_cast<char>(keyNr / 7), 0); + bool isWhite = true; + if (event->pos().y() < height() / 2) { // black keys + if (keyNr % 7 != 0 && keyNr % 7 != 3) { + --newNote.note; + newNote.alter = Tnote::e_Sharp; + isWhite = false; + } + } + if (m_activeNote != newNote) { + m_activeNote.note = newNote.note; m_activeNote.octave = newNote.octave; m_activeNote.alter = newNote.alter; + if (isWhite) + m_keyRect.setRect(m_margin + keyNr * kw, m_keyWidth, m_keyWidth, height() - m_keyWidth); + else + m_keyRect.setRect(m_margin + keyNr * kw - m_keyWidth * 0.4, m_keyWidth, m_keyWidth * 0.8, height() / 2.0); + emit keyRectChanged(); + } + } +} + + +void TpianoBg::mousePressEvent(QMouseEvent* event) { + if (event->buttons() & Qt::LeftButton) { + m_note = m_activeNote; + emit noteChanged(); + } +} + + + +void TpianoBg::calculateMetrics(int newWidth) { + m_keysNumber = newWidth / qRound(m_keyWidth); + m_margin = (newWidth - m_keysNumber * qFloor(m_keyWidth)) / 2; +} diff --git a/src/libs/core/instruments/tpianobg.h b/src/libs/core/instruments/tpianobg.h new file mode 100644 index 000000000..2564af478 --- /dev/null +++ b/src/libs/core/instruments/tpianobg.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2017 by Tomasz Bojczuk * + * seelook@gmail.com * + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + * 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, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef TPIANOBG_H +#define TPIANOBG_H + + +#include <QtQuick/qquickpainteditem.h> +#include "music/tnote.h" + + +/** + * + */ +class TpianoBg : public QQuickPaintedItem +{ + + Q_OBJECT + + Q_PROPERTY(qreal keyWidth READ keyWidth WRITE setKeyWidth) + Q_PROPERTY(bool active READ active NOTIFY activeChanged) + Q_PROPERTY(QRectF keyRect READ keyRect NOTIFY keyRectChanged) + Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly) + Q_PROPERTY(Tnote note READ note WRITE setNote NOTIFY noteChanged) + Q_PROPERTY(int firstOctave READ firstOctave WRITE setFirstOctave) + +public: + explicit TpianoBg(QQuickItem* parent = nullptr); + ~TpianoBg(); + + qreal keyWidth() const { return m_keyWidth; } + void setKeyWidth(qreal kw); + + QRectF keyRect() const { return m_keyRect; } + + Tnote note() const { return m_note; } + void setNote(const Tnote& n); + + int firstOctave() const { return static_cast<int>(m_firstOctave); } + void setFirstOctave(int firstO); + + /** + * @p TRUE when mouse cursor is over + */ + bool active() const { return m_active; } + + bool readOnly() const { return m_readOnly; } + void setReadOnly(bool ro); + + void paint(QPainter* painter) override; + +signals: + void activeChanged(); + void keyRectChanged(); + void noteChanged(); + +protected: + void geometryChanged(const QRectF & newGeometry, const QRectF & oldGeometry) override; + void hoverEnterEvent(QHoverEvent*) override; + void hoverLeaveEvent(QHoverEvent*) override; + void hoverMoveEvent(QHoverEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + +private: + void calculateMetrics(int newWidth); + +private: + int m_keysNumber; + qreal m_keyWidth; + bool m_active = false; + QRectF m_keyRect; + int m_margin; + Tnote m_note, m_activeNote; + char m_firstOctave; + bool m_readOnly = false; +}; + +#endif // TPIANOBG_H diff --git a/src/libs/core/tnootkaqml.cpp b/src/libs/core/tnootkaqml.cpp index a8b8b63dc..aff990a4f 100644 --- a/src/libs/core/tnootkaqml.cpp +++ b/src/libs/core/tnootkaqml.cpp @@ -27,6 +27,7 @@ #include "score/tstaffobject.h" #include "score/tnoteobject.h" #include "instruments/tguitarbg.h" +#include "instruments/tpianobg.h" #include "taction.h" #include "music/tinstrument.h" #include "music/ttune.h" @@ -62,6 +63,7 @@ TnootkaQML::TnootkaQML(QObject* parent) : qmlRegisterType<TtickColors>("Nootka", 1, 0, "TtickColors"); qmlRegisterType<TguitarBg>("Nootka", 1, 0, "TguitarBg"); + qmlRegisterType<TpianoBg>("Nootka", 1, 0, "TpianoBg"); qmlRegisterType<Taction>("Nootka", 1, 0, "Taction"); qmlRegisterUncreatableType<TnootkaQML>("Nootka", 1, 0, "Nootka", QStringLiteral("You cannot create an instance of the TnootkaQML.")); @@ -100,6 +102,11 @@ Tnote TnootkaQML::note(int pitch, int octave, int alter, int rhythm, bool rest, } +Tnote TnootkaQML::note(const Tnote& n, int rhythm, bool rest, bool dot) { + return Tnote(n, Trhythm(static_cast<Trhythm::Erhythm>(rhythm), rest, dot, false)); +} + + QString TnootkaQML::noteName(const Tnote& n, int style, bool showOctave) { // Tnote::toText() method returns only names in user preferred according to settings // To cheat it and force note name in any given style we are resetting pointer of is7th_B diff --git a/src/libs/core/tnootkaqml.h b/src/libs/core/tnootkaqml.h index 26cc76255..1677ce085 100644 --- a/src/libs/core/tnootkaqml.h +++ b/src/libs/core/tnootkaqml.h @@ -65,6 +65,7 @@ public: Q_INVOKABLE Tclef clef(int type); Q_INVOKABLE Tmeter meter(int m); Q_INVOKABLE Tnote note(int pitch, int octave, int alter, int rhythm = 3, bool rest = false, bool dot = false); + Q_INVOKABLE Tnote note(const Tnote& n, int rhythm = 3, bool rest = false, bool dot = false); Q_INVOKABLE QString noteName(const Tnote& n, int style, bool showOctave = true); Q_INVOKABLE QString majorKeyName(int key); Q_INVOKABLE QString minorKeyName(int key); diff --git a/src/nootka.qrc b/src/nootka.qrc index ce8537f48..f89ddcfd9 100644 --- a/src/nootka.qrc +++ b/src/nootka.qrc @@ -31,6 +31,7 @@ <file alias="Instrument.qml">qml/instruments/Instrument.qml</file> <file alias="Guitar.qml">qml/instruments/Guitar.qml</file> + <file alias="Piano.qml">qml/instruments/Piano.qml</file> <file alias="TaboutNootka.qml">qml/about/TaboutNootka.qml</file> <file alias="AboutPage.qml">qml/about/AboutPage.qml</file> diff --git a/src/qml/MainWindow.qml b/src/qml/MainWindow.qml index 2f736c221..b8c43288c 100644 --- a/src/qml/MainWindow.qml +++ b/src/qml/MainWindow.qml @@ -97,9 +97,10 @@ ApplicationWindow { Instrument { id: instrument - height: nootkaWindow.height / 4 - width: nootkaWindow.width z: 1 + onNote: { + score.addNote(Noo.note(n, 2 + Math.random() * 4)) + } } } @@ -112,26 +113,7 @@ ApplicationWindow { // randNotes() // } -// Timer { -// interval: 5000 -// running: true -// repeat: true -// onTriggered: { -// score.addNote(Noo.note(1 + Math.random() * 7, -2 + Math.random() * 5, Math.min(Math.max(-2, -3 + Math.random() * 6), 2), -// 2 + Math.random() * 4)) -// var noteNr = Math.random() * 7 -// var rest = Math.floor((Math.random() * 100) % 2) -// var accid = rest ? 0 : Math.min(Math.max(-2, -3 + Math.random() * 6), 2) -// var note = Noo.note(1 + Math.random() * 7, -3 + Math.random() * 7, accid, 1 + Math.random() * 5, rest) -// score.setNote(0, noteNr, note) -// score.enableKeySign = !score.enableKeySign -// if (score.enableKeySign) -// score.setKeySignature(-7 + Math.random() * 15) -// var m = Math.pow(2, Math.floor(1 + Math.random() * 11)) -// console.log("meter " + m) -// score.meter = m -// } -// } + function randNotes() { var rest = (Math.random() * 100) > 90 // var accid = rest ? 0 : Math.min(Math.max(-2, -3 + Math.random() * 6), 2) diff --git a/src/qml/instruments/Instrument.qml b/src/qml/instruments/Instrument.qml index f46e13dce..b6777efd0 100644 --- a/src/qml/instruments/Instrument.qml +++ b/src/qml/instruments/Instrument.qml @@ -5,8 +5,19 @@ import QtQuick 2.7 Item { + id: root + property Item instrument: null - Guitar { - anchors.fill: parent + signal note(var n) + + height: nootkaWindow.height / 5 //4 + width: nootkaWindow.width + + Component.onCompleted: { + var c = Qt.createComponent("qrc:/Piano.qml") + instrument = c.createObject(root, {"anchors.fill": root}) + instrument.onNoteChanged.connect(callNote) } + + function callNote() { root.note(instrument.note) } } -- GitLab