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