From 75129a6ed74a8a7e81d536797b18a71bbed6a2e3 Mon Sep 17 00:00:00 2001
From: SeeLook <945374+SeeLook@users.noreply.github.com>
Date: Fri, 23 Aug 2019 21:35:12 +0200
Subject: [PATCH] Added audible and visible countdown before playing and
 listening. Added countdown item to displaying digits according to metronome
 beats. Rearranged Tempo Bar to quickly set/unset countdown and audible
 ticking. Fixed determining tempo and beat when melody is read from XML.

---
 changes                                   |   1 +
 fonts/nootka.ttf                          | Bin 34796 -> 35252 bytes
 spare_parts/nootka.sfd                    | 116 ++++++++++-
 spare_parts/scalable/glyphs/countdown.svg | 134 +++++++++++++
 src/libs/core/music/tmelody.cpp           |  26 ++-
 src/libs/core/music/tmelody.h             |  13 +-
 src/libs/core/music/tmeter.cpp            |   6 +-
 src/libs/core/music/tmeter.h              |  34 +++-
 src/libs/sound/tabstractplayer.cpp        |  34 ++--
 src/libs/sound/tabstractplayer.h          |  16 +-
 src/libs/sound/trtaudioout.cpp            |  31 +--
 src/libs/sound/trtaudioout.h              |   6 +-
 src/libs/sound/tsound.cpp                 |  69 +++++--
 src/libs/sound/tsound.h                   |  37 +++-
 src/main/texamexecutor.cpp                |  25 +--
 src/main/texamexecutor.h                  |   4 +-
 src/main/tmainscoreobject.cpp             |   4 +-
 src/nootka.qrc                            |   1 +
 src/qml/about/AboutPage.qml               |   2 +-
 src/qml/exam/ExamExecutor.qml             |   2 +-
 src/qml/sound/CountdownItem.qml           |  54 ++++++
 src/qml/sound/PitchView.qml               |   5 +-
 src/qml/sound/TempoBar.qml                | 222 +++++++++++++---------
 src/qml/sound/TempoMenu.qml               |  16 +-
 24 files changed, 663 insertions(+), 195 deletions(-)
 create mode 100644 spare_parts/scalable/glyphs/countdown.svg
 create mode 100644 src/qml/sound/CountdownItem.qml

diff --git a/changes b/changes
index 7c0aad0c3..eab150adc 100644
--- a/changes
+++ b/changes
@@ -2,6 +2,7 @@
   Nootka says: I speak Italian
      - added Italian translation
      - metronome can tick audibly, also during pitch detection
+     - audible and/or visible countdown before playing and listening
      - added support for scientific octave numbers in note names
      - read/save melody title, composer, tempo, beat
      - level can consist set of melodies loaded from files
diff --git a/fonts/nootka.ttf b/fonts/nootka.ttf
index caef7dd707d3bea8e20a5b03401803d132eb9b7b..65f5c3a604d35a43354d0b74767153f6cdc2e21d 100644
GIT binary patch
delta 919
zcmaJ<OH31C5T1YAEp4}S*>>rJUAvFATLiT&ZK?P|Q30d)egrj<22oV7jSvMBQxnmO
z8b$Y_F&g!z@nEb6qUhOpFhozriw9o^k7(3H>THRRgYn<Y{`1W@^Ucn`|ECMo1D(nP
z0RSf)2NQI)wr=h?5x;g2VDvIZ#kLhITOk4l&LP&;ZHhK@9@xSFkY2=H-Tj%|h2poX
z0Mth`d-vf%85C+5z&wS#d2ePQS1O@0j2ijYy?w)bMmoP@J$(+K<3?{!CcoQx{7Ea4
zpU@h6F=G8rcVmMP;!tn@;L!a?&Pl{i(d52tcV=uVzZ12;B7dnrGn9jI%SPnd5z7ZN
z{XIgWX98f;9DwBKTy|ja;<JDq;56!ymh!MTaOc@`!@Jl;pFvu0!Y>DyTwdie_E#tO
ze<^(^wb0j1UW8Vlj3_QFGWkj^u$_L5{15tiS!#xxdAFA%?fP0WiySTXk)^~;zlH_+
zU22q!>5Zl=Gha#tUItzS9tLg{@0rGltc)wqmA9%{4XH!wE%kkHPjDi%H8d5T3{Pn|
zba8}!yew~l1x7>a4gRJSWZ@W`g)4Z3K`xnYOj{}}EQzEOL`fmSCzXt7LDf<bDWgP#
z*W>k6^A+X1>O|P^s(*)qY9xgq(J)gN(dtRc0Ka4~Id2FVGVWw~Gqi%Lmi`YS%~?W-
z+2OD+ZoIRD+@2mAsrC68#>LH&n&d@Zzh70OiLl1=9H+|jR=gu!iX3ZJ6t5>5UA47E
z4QcX1pO0ZgAzquWjr(hCHjbOEiGn*R)zvj^h{ia<#aB9=mAp$h^2a?SxZF-$ZkIrj
zm|K#3G{e~9%L~&_I!@LJqQ_e!v#jWE!^U>T?NX%K_2E!3Sih7$l9m+*RUt{Kx#5t9
z7k6<sTQ#qF*d%MUZn4=}ju)${Dk~jpJS?jy)7u0O!w3T7@CyI%ic8v7H<Nb#%&GGf
kaqGT<XpY63VtTAFpx-RikT!jyAo8#FsXfN!`TO?$1e8j_8vp<R

delta 535
zcmdlondwbGQ#}JC0|NseLjwadLxP)Ih;LIp=RyXC_6tB!8Fv>~HwJZvTp)i1kgw(+
ztZx*V9rBNXfiVNfPe{&9Ea+eVa|Qzg(-R=(N-ir=U{GYLWME+V0F-A*Pb@C@{~u^F
zL;C_CpCdh|GHnODavK8!YYPK|_nVB=#QGGTEw}FiCEozCSq4yqJ&}bAXn_iluac2l
zQnBU%-!vfq1Q5&Q<R>SliPQisWcdP=pOBkaQNXaBEeI&*0pu&>CFZ6|8>jAJU<fQ=
zU@-YwkY8N#wBVH(14A3o!HgDQ&jLNXWzt;#cz&C&4DtcYFMt{uE;tJaf#{n-9ligb
z|94_xWfli=IT)BgqCf!D#4PdOi6M%m87Tjkg%xZRL=Hl_gGJmY`!UKg=5EembYPsk
zfvJ<Rf3g*GKCijFiQFZ*i*h^V<})x(E@ZLT{EoSfQAXj5BA23;qL<=4#S=<AN<B)C
zlxtL^RKBT7seaqs!@AdT^Is1Sdq(%kZXJCR?4@~`1_l-eVA{~a7)rZM{?<|K$p{Q*
oCa?>5fX)$PkOT7=8Qg$kEI<*EKR_`J!XN;qZ@er7)5yLD0D}{PYXATM

diff --git a/spare_parts/nootka.sfd b/spare_parts/nootka.sfd
index f01780544..f56e594ff 100644
--- a/spare_parts/nootka.sfd
+++ b/spare_parts/nootka.sfd
@@ -1,4 +1,4 @@
-SplineFontDB: 3.0
+SplineFontDB: 3.2
 FontName: nootka
 FullName: nootka
 FamilyName: nootka
@@ -21,7 +21,7 @@ OS2Version: 0
 OS2_WeightWidthSlopeOnly: 0
 OS2_UseTypoMetrics: 1
 CreationTime: 1411211154
-ModificationTime: 1563219981
+ModificationTime: 1566554742
 PfmFamily: 17
 TTFWeight: 500
 TTFWidth: 5
@@ -103,7 +103,7 @@ Grid
  2000 300.199996948 l 1024
   Named: "middle"
 EndSplineSet
-BeginChars: 65539 71
+BeginChars: 65539 72
 
 StartChar: .notdef
 Encoding: 65536 -1 0
@@ -6152,5 +6152,115 @@ SplineSet
  442.142578125 443.8828125 l 1,73,-1
 EndSplineSet
 EndChar
+
+StartChar: uni0190
+Encoding: 400 400 71
+Width: 1499
+VWidth: 0
+Flags: W
+HStem: -2.27637 99.5225<1127.07 1190.37 1246.07 1309.37 1360.01 1423.31> -2.27637 88.4648<777.233 971.173> 201.645 93.625<514.765 744.034> 232.891 85.5156<828.785 967.168> 322.093 21G<96.2373 137.13 418.241 450.998 786.572 809.617> 448.892 89.9385<828.686 971.579> 504.086 20G<202.886 319.436> 642.491 92.8867<481.318 603.454>
+VStem: 208.118 111.317<-2.27637 406.871> 618.71 110.58<513.241 628.411> 987.283 109.104<339.478 433.563> 995.392 116.479<109.645 206.638> 1113.38 91.4141<9.89172 85.8389> 1232.38 91.4141<9.89172 85.8389> 1346.32 91.4131<9.89172 85.8389>
+LayerCount: 2
+Fore
+SplineSet
+319.435546875 -2.2763671875 m 1,0,-1
+ 208.118164062 -2.2763671875 l 1,1,-1
+ 208.118164062 302.188476562 l 2,2,3
+ 208.118164062 321.35546875 208.118164062 321.35546875 208.854492188 352.318359375 c 0,4,5
+ 210.330078125 383.280273438 210.330078125 383.280273438 211.067382812 406.87109375 c 1,6,7
+ 207.380859375 402.448242188 207.380859375 402.448242188 194.84765625 390.65234375 c 0,8,9
+ 183.052734375 379.59375 183.052734375 379.59375 172.732421875 370.748046875 c 2,10,-1
+ 112.28125 322.092773438 l 1,11,-1
+ 58.4658203125 389.177734375 l 1,12,-1
+ 228.022460938 524.0859375 l 1,13,-1
+ 319.435546875 524.0859375 l 1,14,-1
+ 319.435546875 -2.2763671875 l 1,0,-1
+744.034179688 201.64453125 m 1,15,-1
+ 376.170898438 201.64453125 l 1,16,-1
+ 376.170898438 279.05078125 l 1,17,-1
+ 508.129882812 412.483398438 l 2,18,19
+ 547.939453125 453.767578125 547.939453125 453.767578125 572.266601562 481.04296875 c 0,20,21
+ 596.594726562 509.056640625 596.594726562 509.056640625 607.65234375 531.173828125 c 0,22,23
+ 618.709960938 554.026367188 618.709960938 554.026367188 618.709960938 579.828125 c 0,24,25
+ 618.709960938 611.528320312 618.709960938 611.528320312 601.017578125 627.008789062 c 0,26,27
+ 584.0625 642.491210938 584.0625 642.491210938 554.573242188 642.491210938 c 0,28,29
+ 524.348632812 642.491210938 524.348632812 642.491210938 495.59765625 628.484375 c 128,-1,30
+ 466.84765625 614.477539062 466.84765625 614.477539062 435.147460938 588.673828125 c 1,31,-1
+ 374.697265625 660.18359375 l 1,32,33
+ 397.549804688 680.087890625 397.549804688 680.087890625 422.614257812 697.04296875 c 0,34,35
+ 448.416992188 713.999023438 448.416992188 713.999023438 481.590820312 724.3203125 c 0,36,37
+ 515.501953125 735.377929688 515.501953125 735.377929688 562.68359375 735.377929688 c 0,38,39
+ 614.287109375 735.377929688 614.287109375 735.377929688 651.1484375 716.209960938 c 0,40,41
+ 688.745117188 697.780273438 688.745117188 697.780273438 708.6484375 665.34375 c 0,42,43
+ 729.290039062 633.643554688 729.290039062 633.643554688 729.290039062 593.098632812 c 0,44,45
+ 729.290039062 549.603515625 729.290039062 549.603515625 711.59765625 513.48046875 c 0,46,47
+ 694.642578125 477.358398438 694.642578125 477.358398438 661.467773438 441.97265625 c 0,48,49
+ 629.03125 406.586914062 629.03125 406.586914062 582.587890625 363.829101562 c 2,50,-1
+ 514.764648438 300.4296875 l 1,51,-1
+ 514.764648438 295.26953125 l 1,52,-1
+ 744.034179688 295.26953125 l 1,53,-1
+ 744.034179688 201.64453125 l 1,15,-1
+1096.38769531 413.505859375 m 0,54,55
+ 1096.38769531 358.953125 1096.38769531 358.953125 1063.21386719 326.515625 c 0,56,57
+ 1030.77734375 294.080078125 1030.77734375 294.080078125 982.858398438 282.284179688 c 1,58,-1
+ 982.858398438 280.071289062 l 1,59,60
+ 1046.25878906 272.701171875 1046.25878906 272.701171875 1078.6953125 241.73828125 c 0,61,62
+ 1111.87011719 210.775390625 1111.87011719 210.775390625 1111.87011719 158.43359375 c 0,63,64
+ 1111.87011719 112.7265625 1111.87011719 112.7265625 1089.015625 75.8671875 c 0,65,66
+ 1066.90039062 39.744140625 1066.90039062 39.744140625 1019.71972656 18.365234375 c 0,67,68
+ 973.275390625 -2.2763671875 973.275390625 -2.2763671875 899.555664062 -2.2763671875 c 0,69,70
+ 814.040039062 -2.2763671875 814.040039062 -2.2763671875 747.692382812 26.474609375 c 1,71,-1
+ 747.692382812 120.836914062 l 1,72,73
+ 781.603515625 103.880859375 781.603515625 103.880859375 818.462890625 95.03515625 c 0,74,75
+ 856.060546875 86.1884765625 856.060546875 86.1884765625 887.760742188 86.1884765625 c 0,76,77
+ 947.47265625 86.1884765625 947.47265625 86.1884765625 971.063476562 106.830078125 c 0,78,79
+ 995.391601562 127.471679688 995.391601562 127.471679688 995.391601562 165.068359375 c 0,80,81
+ 995.391601562 187.185546875 995.391601562 187.185546875 984.333984375 201.9296875 c 0,82,83
+ 973.275390625 217.41015625 973.275390625 217.41015625 945.26171875 224.782226562 c 0,84,85
+ 917.985351562 232.890625 917.985351562 232.890625 868.59375 232.890625 c 2,86,-1
+ 828.78515625 232.890625 l 1,87,-1
+ 828.78515625 318.40625 l 1,88,-1
+ 869.331054688 318.40625 l 2,89,90
+ 917.985351562 318.40625 917.985351562 318.40625 943.049804688 327.251953125 c 0,91,92
+ 968.8515625 336.8359375 968.8515625 336.8359375 977.69921875 352.318359375 c 0,93,94
+ 987.283203125 368.536132812 987.283203125 368.536132812 987.283203125 389.177734375 c 0,95,96
+ 987.283203125 417.19140625 987.283203125 417.19140625 969.58984375 432.672851562 c 0,97,98
+ 952.633789062 448.891601562 952.633789062 448.891601562 912.087890625 448.891601562 c 0,99,100
+ 874.490234375 448.891601562 874.490234375 448.891601562 846.4765625 435.622070312 c 0,101,102
+ 819.201171875 423.08984375 819.201171875 423.08984375 800.033203125 410.556640625 c 1,103,-1
+ 748.4296875 487.2265625 l 1,104,105
+ 779.392578125 509.341796875 779.392578125 509.341796875 820.674804688 524.0859375 c 0,106,107
+ 862.6953125 538.830078125 862.6953125 538.830078125 920.197265625 538.830078125 c 0,108,109
+ 1001.29003906 538.830078125 1001.29003906 538.830078125 1048.47070312 505.65625 c 0,110,111
+ 1096.38769531 473.219726562 1096.38769531 473.219726562 1096.38769531 413.505859375 c 0,54,55
+1113.3828125 47.853515625 m 0,112,113
+ 1113.3828125 75.1298828125 1113.3828125 75.1298828125 1126.65332031 86.1884765625 c 128,-1,114
+ 1139.92285156 97.24609375 1139.92285156 97.24609375 1158.35253906 97.24609375 c 0,115,116
+ 1177.51953125 97.24609375 1177.51953125 97.24609375 1190.79003906 86.1884765625 c 0,117,118
+ 1204.796875 75.1298828125 1204.796875 75.1298828125 1204.796875 47.853515625 c 0,119,120
+ 1204.796875 21.314453125 1204.796875 21.314453125 1190.79003906 9.51953125 c 0,121,122
+ 1177.51953125 -2.2763671875 1177.51953125 -2.2763671875 1158.35253906 -2.2763671875 c 0,123,124
+ 1139.92285156 -2.2763671875 1139.92285156 -2.2763671875 1126.65332031 9.51953125 c 128,-1,125
+ 1113.3828125 21.314453125 1113.3828125 21.314453125 1113.3828125 47.853515625 c 0,112,113
+1232.37890625 47.853515625 m 0,126,127
+ 1232.37890625 75.1298828125 1232.37890625 75.1298828125 1245.64941406 86.1884765625 c 128,-1,128
+ 1258.91796875 97.24609375 1258.91796875 97.24609375 1277.34765625 97.24609375 c 0,129,130
+ 1296.515625 97.24609375 1296.515625 97.24609375 1309.78613281 86.1884765625 c 0,131,132
+ 1323.79296875 75.1298828125 1323.79296875 75.1298828125 1323.79296875 47.853515625 c 0,133,134
+ 1323.79296875 21.314453125 1323.79296875 21.314453125 1309.78613281 9.51953125 c 0,135,136
+ 1296.515625 -2.2763671875 1296.515625 -2.2763671875 1277.34765625 -2.2763671875 c 0,137,138
+ 1258.91796875 -2.2763671875 1258.91796875 -2.2763671875 1245.64941406 9.51953125 c 128,-1,139
+ 1232.37890625 21.314453125 1232.37890625 21.314453125 1232.37890625 47.853515625 c 0,126,127
+1346.3203125 47.853515625 m 0,140,141
+ 1346.3203125 75.1298828125 1346.3203125 75.1298828125 1359.58984375 86.1884765625 c 128,-1,142
+ 1372.86035156 97.24609375 1372.86035156 97.24609375 1391.29003906 97.24609375 c 0,143,144
+ 1410.45703125 97.24609375 1410.45703125 97.24609375 1423.7265625 86.1884765625 c 0,145,146
+ 1437.73339844 75.1298828125 1437.73339844 75.1298828125 1437.73339844 47.853515625 c 0,147,148
+ 1437.73339844 21.314453125 1437.73339844 21.314453125 1423.7265625 9.51953125 c 0,149,150
+ 1410.45703125 -2.2763671875 1410.45703125 -2.2763671875 1391.29003906 -2.2763671875 c 0,151,152
+ 1372.86035156 -2.2763671875 1372.86035156 -2.2763671875 1359.58984375 9.51953125 c 128,-1,153
+ 1346.3203125 21.314453125 1346.3203125 21.314453125 1346.3203125 47.853515625 c 0,140,141
+EndSplineSet
+EndChar
 EndChars
 EndSplineFont
diff --git a/spare_parts/scalable/glyphs/countdown.svg b/spare_parts/scalable/glyphs/countdown.svg
new file mode 100644
index 000000000..2e95f4312
--- /dev/null
+++ b/spare_parts/scalable/glyphs/countdown.svg
@@ -0,0 +1,134 @@
+<?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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="1100"
+   height="1000"
+   id="svg2"
+   inkscape:version="0.92.4 5da689c313, 2019-01-14"
+   sodipodi:docname="countdown.svg"
+   inkscape:export-filename="/home/tom/DEVELOP/QT4/nootka/unused-picts/proto/note.png"
+   inkscape:export-xdpi="300.09186"
+   inkscape:export-ydpi="300.09186">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1600"
+     inkscape:window-height="1163"
+     id="namedview8"
+     showgrid="false"
+     inkscape:zoom="0.67396115"
+     inkscape:cx="714.56967"
+     inkscape:cy="507.66913"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2"
+     showguides="true"
+     inkscape:guide-bbox="true">
+    <sodipodi:guide
+       orientation="1,0"
+       position="348.68479,854.64867"
+       id="guide5187"
+       inkscape:locked="false" />
+    <sodipodi:guide
+       orientation="0,1"
+       position="-83.090843,500.02882"
+       id="guide2996"
+       inkscape:locked="false" />
+  </sodipodi:namedview>
+  <defs
+     id="defs4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     aria-label="1"
+     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.33857802"
+     id="text848"
+     transform="matrix(2.953529,0,0,2.953529,-600.69664,-518.44485)">
+    <path
+       d="m 276.63674,418.3493 h -28.992 v -79.296 q 0,-4.992 0.192,-13.056 0.384,-8.064 0.576,-14.208 -0.96,1.152 -4.224,4.224 -3.072,2.88 -5.76,5.184 l -15.744,12.672 -14.016,-17.472 44.16,-35.136 h 23.808 z"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:192px;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Bold';stroke-width:0.33857802"
+       id="path910"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     aria-label="2"
+     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.33857802"
+     id="text848-0"
+     transform="matrix(2.953529,0,0,2.953529,-571.73401,-518.44485)">
+    <path
+       d="m 377.41522,365.23938 h -95.808 v -20.16 l 34.368,-34.752 q 10.368,-10.752 16.704,-17.856 6.336,-7.296 9.216,-13.056 2.88,-5.952 2.88,-12.672 0,-8.256 -4.608,-12.288 -4.416,-4.032 -12.096,-4.032 -7.872,0 -15.36,3.648 -7.488,3.648 -15.744,10.368 l -15.744,-18.624 q 5.952,-5.184 12.48,-9.6 6.72,-4.416 15.36,-7.104 8.832,-2.88 21.12,-2.88 13.44,0 23.04,4.992 9.792,4.8 14.976,13.248 5.376,8.256 5.376,18.816 0,11.328 -4.608,20.736 -4.416,9.408 -13.056,18.624 -8.448,9.216 -20.544,20.352 l -17.664,16.512 v 1.344 h 59.712 z"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:192px;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Bold';stroke-width:0.33857802"
+       id="path913"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     aria-label="3"
+     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.33857802"
+     id="text848-06"
+     transform="matrix(2.953529,0,0,2.953529,-548.44231,-518.44485)">
+    <path
+       d="m 461.29773,310.06129 q 0,14.208 -8.64,22.656 -8.448,8.448 -20.928,11.52 v 0.576 q 16.512,1.92 24.96,9.984 8.64,8.064 8.64,21.696 0,11.904 -5.952,21.504 -5.76,9.408 -18.048,14.976 -12.096,5.376 -31.296,5.376 -22.272,0 -39.552,-7.488 v -24.576 q 8.832,4.416 18.432,6.72 9.792,2.304 18.048,2.304 15.552,0 21.696,-5.376 6.336,-5.376 6.336,-15.168 0,-5.76 -2.88,-9.6 -2.88,-4.032 -10.176,-5.952 -7.104,-2.112 -19.968,-2.112 h -10.368 v -22.272 h 10.56 q 12.672,0 19.2,-2.304 6.72,-2.496 9.024,-6.528 2.496,-4.224 2.496,-9.6 0,-7.296 -4.608,-11.328 -4.416,-4.224 -14.976,-4.224 -9.792,0 -17.088,3.456 -7.104,3.264 -12.096,6.528 l -13.44,-19.968 q 8.064,-5.76 18.816,-9.6 10.944,-3.84 25.92,-3.84 21.12,0 33.408,8.64 12.48,8.448 12.48,24 z"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:192px;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Bold';stroke-width:0.33857802"
+       id="path916"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     aria-label="."
+     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.33857802"
+     id="text848-2"
+     transform="matrix(2.953529,0,0,2.953529,-560.3183,-518.44485)">
+    <path
+       d="m 469.74505,405.29329 q 0,-7.104 3.456,-9.984 3.456,-2.88 8.256,-2.88 4.992,0 8.448,2.88 3.648,2.88 3.648,9.984 0,6.912 -3.648,9.984 -3.456,3.072 -8.448,3.072 -4.8,0 -8.256,-3.072 -3.456,-3.072 -3.456,-9.984 z"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';stroke-width:0.33857802"
+       id="path919"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     aria-label="."
+     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.33857802"
+     id="text848-2-8"
+     transform="matrix(2.953529,0,0,2.953529,-560.3183,-518.44485)">
+    <path
+       d="m 500.73684,405.29329 q 0,-7.104 3.456,-9.984 3.456,-2.88 8.256,-2.88 4.992,0 8.448,2.88 3.648,2.88 3.648,9.984 0,6.912 -3.648,9.984 -3.456,3.072 -8.448,3.072 -4.8,0 -8.256,-3.072 -3.456,-3.072 -3.456,-9.984 z"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';stroke-width:0.33857802"
+       id="path922"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     aria-label="."
+     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.33857802"
+     id="text848-2-2"
+     transform="matrix(2.953529,0,0,2.953529,-560.3183,-518.44485)">
+    <path
+       d="m 530.41213,405.29329 q 0,-7.104 3.456,-9.984 3.456,-2.88 8.256,-2.88 4.992,0 8.448,2.88 3.648,2.88 3.648,9.984 0,6.912 -3.648,9.984 -3.456,3.072 -8.448,3.072 -4.8,0 -8.256,-3.072 -3.456,-3.072 -3.456,-9.984 z"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';stroke-width:0.33857802"
+       id="path925"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/src/libs/core/music/tmelody.cpp b/src/libs/core/music/tmelody.cpp
index f1ab5d45c..0bce9a2f5 100644
--- a/src/libs/core/music/tmelody.cpp
+++ b/src/libs/core/music/tmelody.cpp
@@ -151,15 +151,21 @@ bool Tmelody::fromXml(QXmlStreamReader& xml) {
   m_measures.clear();
   m_meter->setMeter(Tmeter::NoMeter);
   setTempo(0); // reset tempo, try to read from XML
+  int barNr = 0;
   while (xml.readNextStartElement()) {
 /** [measure] */
     if (xml.name() == QLatin1String("measure")) {
-      int nr = xml.attributes().value(QStringLiteral("number")).toInt();
-      m_measures << Tmeasure(nr);
+      int tmpBarNr = xml.attributes().value(QStringLiteral("number")).toInt();
+      barNr++;
+      if (tmpBarNr != barNr) {
+        qDebug() << "[Tmelody] Something wrong with measure numbers!" << barNr << "was expected, but" << tmpBarNr << "was read.\n"
+                 << "Better check integrity of this music XML file!";
+      }
+      m_measures << Tmeasure(barNr);
       while (xml.readNextStartElement()) {
 /** [attributes] */
         if (xml.name() == QLatin1String("attributes")) {
-          if (nr == 1) {
+          if (barNr == 1) {
             Tclef::EclefType clef1 = Tclef::NoClef, clef2 = Tclef::NoClef;
             int staffCnt = 1;
             while (xml.readNextStartElement()) {
@@ -283,8 +289,8 @@ bool Tmelody::fromXml(QXmlStreamReader& xml) {
                           else
                             qDebug() << "[Tmelody] Metronome beat with dot only supports quarter. Ignore dot then!";
                         }
-                        int quarterTempo = tempoWillBe / Tmeter::beatTempoFactor(beatWillBe);
-                        if (nr == 1 || tempo() == 0) { // read metronome tempo but only for 1st bar or if not yet set
+                        int quarterTempo = Tmeter::quarterTempo(tempoWillBe, beatWillBe);
+                        if (barNr == 1 || tempo() == 0) { // read metronome tempo but only for 1st bar or if not yet set
                           if (quarterTempo >= 40 && quarterTempo <= 180) {
                               setTempo(tempoWillBe);
                               setBeat(beatWillBe);
@@ -310,15 +316,15 @@ bool Tmelody::fromXml(QXmlStreamReader& xml) {
         else
             xml.skipCurrentElement();
       }
-      if (lastMeasure().number() != m_measures.size()) {
-        qDebug() << "[Tmelody] Wrong measure number" << lastMeasure().number() << m_measures.size();
-      }
     } else
         xml.skipCurrentElement();
 
   }
-  if (tempo() == 0)
-    setTempo(120);
+  if (tempo() == 0) {
+    setBeat(m_meter->optimalBeat());
+    setTempo(qRound(60.0 * Tmeter::beatTempoFactor(m_beat)));
+    qDebug() << "[Tmelody] Tempo was not read from this melody file. Set it to" << m_tempo << "with beat" << m_beat;
+  }
   return ok;
 }
 
diff --git a/src/libs/core/music/tmelody.h b/src/libs/core/music/tmelody.h
index 19df2ece5..080d26668 100644
--- a/src/libs/core/music/tmelody.h
+++ b/src/libs/core/music/tmelody.h
@@ -34,8 +34,7 @@ class TnoteStruct;
 
 /**
  * Class describing a musical melody - sequence of notes (Tchunk)
- * Also it is able to save/load a melody into/from MusicXML structure
- * Default tempo of a melody is 120 bpm.
+ * Also it is able to save/load a melody into/from MusicXML structure.
  */
 class NOOTKACORE_EXPORT Tmelody
 {
@@ -71,6 +70,16 @@ public:
   int tempo() const { return m_tempo; }
   void setTempo(int tmp) { m_tempo = tmp; }
 
+      /**
+       * Tempo of quarter notes (per minute), independent on beat unit
+       */
+  int quarterTempo() const { return Tmeter::quarterTempo(m_tempo, m_beat); }
+
+      /**
+       * Set both tempo and beat at once
+       */
+  void setMetronome(int mTempo, Tmeter::EbeatUnit beatUnit) { setTempo(mTempo); setBeat(beatUnit); }
+
   Tmeter::EbeatUnit beat() const { return m_beat; }
   void setBeat(Tmeter::EbeatUnit bu) { m_beat = bu; }
 
diff --git a/src/libs/core/music/tmeter.cpp b/src/libs/core/music/tmeter.cpp
index fc2767863..da99067c9 100644
--- a/src/libs/core/music/tmeter.cpp
+++ b/src/libs/core/music/tmeter.cpp
@@ -89,7 +89,7 @@ int Tmeter::countTo() const {
     case Meter_7_8: return 7;
     case Meter_9_8:
     case Meter_12_8: return 3;
-    default: return 2;
+    default: return 4;
   }
 }
 
@@ -191,8 +191,10 @@ void Tmeter::fillMeterGroups(QList<quint8>& durationList) {
 
 
 Tmeter::EbeatUnit Tmeter::optimalBeat(Tmeter::Emeter m) {
-  if (m <= Meter_7_4) // all time signatures with quarter
+  if (m <= Meter_7_4) // all time signatures with quarter, also when no meter NoMeter
     return BeatQuarter;
+  if (m == Meter_6_8 || m == Meter_9_8 || m == Meter_12_8)
+    return BeatQuarterDot;
   return BeatEighth;
 }
 
diff --git a/src/libs/core/music/tmeter.h b/src/libs/core/music/tmeter.h
index f98817bb5..482533315 100644
--- a/src/libs/core/music/tmeter.h
+++ b/src/libs/core/music/tmeter.h
@@ -49,13 +49,13 @@ public:
   Q_INVOKABLE void setMeter(Tmeter::Emeter m) { m_meter = m; }
 
       /**
-      * Returns upper digit of time signature
-      */
+       * Returns upper digit of time signature
+       */
   Q_INVOKABLE int upper() const;
 
       /**
-      * Returns lower digit of time signature
-      */
+       * Returns lower digit of time signature
+       */
   Q_INVOKABLE int lower() const;
 
       /**
@@ -65,10 +65,10 @@ public:
   Q_INVOKABLE QString symbol() const;
 
       /**
-      * Returns numeric value representing duration of single measure,
-      * which is based on Trhythm calculation (RVALUE)
-      * 3/4 is 72, 4/4 is 96 (RVALUE), etc. 
-      */
+       * Returns numeric value representing duration of single measure,
+       * which is based on Trhythm calculation (RVALUE)
+       * 3/4 is 72, 4/4 is 96 (RVALUE), etc. 
+       */
   Q_INVOKABLE int duration() const;
 
       /**
@@ -80,8 +80,8 @@ public:
   bool fromXml(QXmlStreamReader& xml);
 
       /**
-      * Prints current meter to std out with given text
-      */
+       * Prints current meter to std out with given text
+       */
   Q_INVOKABLE void debug(const QString& text = QString());
 
   bool operator==(const Tmeter& m) const { return meter() == m.meter(); }
@@ -114,6 +114,20 @@ public:
        */
   Q_INVOKABLE static qreal beatTempoFactor(Tmeter::EbeatUnit bu);
 
+      /**
+       * Tempo of quarter notes (per minute), independent on beat unit
+       */
+  static int quarterTempo(int beatTempo, Tmeter::EbeatUnit beatUnit) {
+    return qRound(static_cast<qreal>(beatTempo) / beatTempoFactor(beatUnit));
+  }
+
+      /**
+       * Tempo of quarter notes (per minute), independent on beat unit
+       */
+  static int quarterTempo(int beatTempo, int beatUnit) {
+    return Tmeter::quarterTempo(beatTempo, static_cast<EbeatUnit>(beatUnit));
+  }
+
 private:
   Emeter        m_meter;
 };
diff --git a/src/libs/sound/tabstractplayer.cpp b/src/libs/sound/tabstractplayer.cpp
index 2be8e896a..90f379108 100644
--- a/src/libs/sound/tabstractplayer.cpp
+++ b/src/libs/sound/tabstractplayer.cpp
@@ -63,17 +63,22 @@ void TplayerThread::run() {
                       GLOB->transposition(), static_cast<int>(m_player->p_audioParams->a440diff));
       m_listToPlay = nullptr;
   } else if (m_melodyToPlay) { // melody (from Tmelody)
-      for (int n = 0; n < m_melodyToPlay->length(); ++n) { // TODO: !! Where is beat unit of melody !!!!!!
+      qreal rateFactor = m_player->p_oggScale->sampleRate() / 1000.0;
+      if (m_player->p_countdownDur > 0)
+        playList() << TsingleSound(CNTDWN_ID, REST_NR, qRound(((m_player->p_countdownDur / 24.0) * (60000.0 / m_melodyToPlay->quarterTempo())) * rateFactor));
+      for (int n = 0; n < m_melodyToPlay->length(); ++n) {
         const Tnote& tmpN = m_melodyToPlay->note(n)->p();
-        int samplesDuration = qRound(((tmpN.duration() > 0 ? tmpN.duration() / 24.0 : 1.0) * (60000.0 / m_melodyToPlay->tempo())) * (m_player->p_oggScale->sampleRate() / 1000.0));
+        int samplesDur =
+          qRound(((tmpN.duration() > 0 ? tmpN.duration() / 24.0 : 1.0) * (60000.0 / m_melodyToPlay->quarterTempo())) * rateFactor);
         if (tmpN.rtm.tie() > Trhythm::e_tieStart) { // append duration if tie is continued or at end
           if (playList().isEmpty())
             continue; // do not start playing in the middle of tied notes
-            playList().last().samplesCount += samplesDuration;
+            playList().last().samplesCount += samplesDur;
         } else
           playList() << TsingleSound(n,
-                                    tmpN.isValid() ? tmpN.chromatic() + GLOB->transposition() + m_transposition + m_player->p_audioParams->a440diff : REST_NR,
-                                    samplesDuration);
+                                     tmpN.isValid() ? tmpN.chromatic() + GLOB->transposition() + m_transposition + m_player->p_audioParams->a440diff : REST_NR,
+                                     samplesDur
+                                    );
       }
       m_melodyToPlay = nullptr;
   }
@@ -93,11 +98,11 @@ void TplayerThread::preparePlayList(QList<Tnote>* notes, int tempo, int firstNot
     const Tnote& tmpN = notes->at(n);
     int samplesDuration = qRound(((tmpN.duration() > 0 ? tmpN.duration() / 24.0 : 1.0) * (60000.0 / tempo)) * (sampleRate / 1000.0));
     if (tmpN.rtm.tie() > Trhythm::e_tieStart) { // append duration if tie is continued or at end
-      if (playList().isEmpty())
-        continue; // do not start playing in the middle of tied notes
+        if (playList().isEmpty())
+          continue; // do not start playing in the middle of tied notes
         playList().last().samplesCount += samplesDuration;
     } else
-      playList() << TsingleSound(n, tmpN.isValid() ? tmpN.chromatic() + transposition + a440diff : REST_NR, samplesDuration);
+        playList() << TsingleSound(n, tmpN.isValid() ? tmpN.chromatic() + transposition + a440diff : REST_NR, samplesDuration);
   }
 }
 
@@ -120,6 +125,7 @@ unsigned int            TabstractPlayer::p_beatPeriod = 0;
 unsigned int            TabstractPlayer::p_beatBytes = 7984; // beat file frames number (initial, finally obtained from file)
 unsigned int            TabstractPlayer::p_beatOffset = 0;
 bool                    TabstractPlayer::p_lastNotePlayed = false;
+int                     TabstractPlayer::p_ticksCountBefore = 0;
 
 
 TabstractPlayer::TabstractPlayer(QObject* parent) :
@@ -164,12 +170,13 @@ bool TabstractPlayer::playNotes(QList<Tnote>* notes, int tempo, int firstNote, i
 }
 
 
-bool TabstractPlayer::playMelody(Tmelody* melody, int transposition) {
+bool TabstractPlayer::playMelody(Tmelody* melody, int transposition, int countdownDur) {
   if (!p_playable)
     return false;
   m_playThreaad->wait();
   m_playThreaad->setMelodyToPlay(melody);
   m_playThreaad->setTransposition(transposition);
+  p_countdownDur = countdownDur;
   m_playThreaad->start();
   return true;
 }
@@ -181,7 +188,7 @@ bool TabstractPlayer::playMelody(Tmelody* melody, int transposition) {
  * But of course, read it once, and store decoded data in array.
  * TODO: consider to save decoded data somewhere into cache.
  */
-void TabstractPlayer::runMetronome(unsigned int beatTempo) {
+void TabstractPlayer::setMetronome(unsigned int beatTempo) {
   if (!m_beatArray) {
     auto stdFile = fopen(Tpath::sound("beat").toStdString().c_str(), "r");
     if(!stdFile) {
@@ -215,7 +222,7 @@ void TabstractPlayer::runMetronome(unsigned int beatTempo) {
     ov_clear(&oggFile);
   }
   p_beatOffset = 0;
-  p_beatPeriod = beatTempo ? (44100 * 60) / beatTempo : 0;
+  p_beatPeriod = beatTempo ? (44100 * 60) / beatTempo : 0; //FIXME what if sample rate is 48000Hz?
 }
 
 
@@ -238,3 +245,8 @@ void TabstractPlayer::setTickDuringPlay(bool tdp) {
     // TODO wait for busy callback to avoid cracks
     p_audioParams->audibleMetro = tdp;
 }
+
+
+bool TabstractPlayer::doTicking() const {
+  return p_audioParams && (p_audioParams->audibleMetro || p_audioParams->countBefore);
+}
diff --git a/src/libs/sound/tabstractplayer.h b/src/libs/sound/tabstractplayer.h
index dbf143667..03ca7888f 100644
--- a/src/libs/sound/tabstractplayer.h
+++ b/src/libs/sound/tabstractplayer.h
@@ -133,7 +133,7 @@ public:
 
   bool playNote(int noteNr);
   bool playNotes(QList<Tnote>* notes, int tempo, int firstNote = 0, int countdownDur = 0);
-  bool playMelody(Tmelody* melody, int transposition = 0);
+  bool playMelody(Tmelody* melody, int transposition = 0, int countdownDur = 0);
 
   enum EplayerType { e_audio, e_midi };
 
@@ -149,7 +149,7 @@ public:
        */
   int playingNoteId() const { return p_playingNoteId; }
 
-  void runMetronome(unsigned int beatTempo);
+  void setMetronome(unsigned int beatTempo);
   void stopMetronome();
   qint16 getBeatsample(unsigned int sampleNr) const { return m_beatArray[sampleNr]; }
 
@@ -159,6 +159,17 @@ public:
   bool tickDuringPlay() const;
   void setTickDuringPlay(bool tdp);
 
+      /**
+       * Number of metronome ticks before melody will be played.
+       * Also before audio input will be processed (pitch detection started).
+       * It counts down, so becomes null when done,
+       * so has to be set every time it is needed.
+       */
+  static int ticksCountBefore() { return p_ticksCountBefore; }
+  static void setTicksCountBefore(int tcb) { p_ticksCountBefore = tcb; }
+
+  bool doTicking() const;
+
 signals:
   void playingStarted();
 
@@ -202,6 +213,7 @@ protected:
   static unsigned int          p_beatBytes; /**< Number of bytes in single beat sample */
   static unsigned int          p_beatOffset; /**< Callback position in beat period */
   static bool                  p_lastNotePlayed; /**< @p TRUE set in callback only when last note just has been played */
+  static int                   p_ticksCountBefore; /**<   Number of metronome ticks before playing melody or sniffing */
 
 private:
   TplayerThread               *m_playThreaad;
diff --git a/src/libs/sound/trtaudioout.cpp b/src/libs/sound/trtaudioout.cpp
index 054d6e9ad..70ce70153 100755
--- a/src/libs/sound/trtaudioout.cpp
+++ b/src/libs/sound/trtaudioout.cpp
@@ -55,6 +55,7 @@ TaudioOUT*              TaudioOUT::instance = nullptr;
 
 
 #define CROSS_SMP (2200) // 50ms
+#define INVALID_NOTE_NR (-100)
 
 
 /**
@@ -79,16 +80,16 @@ bool TaudioOUT::outCallBack(void* outBuff, unsigned int nBufferFrames, const RtA
 //       qDebug() << "[trtaudioout] Stream underflow detected!";
 
   bool endState = true;
-  if (!instance->playList().isEmpty() && p_playingNoteNr < instance->playList().size()) {
+  if (!instance->playList().isEmpty() && p_playingNoteNr < instance->playList().size() && p_ticksCountBefore == 0) {
       TsingleSound& playingSound = instance->playList()[p_playingNoteNr];
       auto out = static_cast<qint16*>(outBuff);
       bool unfinished = true;
       qint16 sample = 0;
       for (int i = 0; i < nBufferFrames / instance->ratioOfRate; i++) {
         if (p_posInNote >= playingSound.samplesCount) {
-          p_prevNote = playingSound.number == REST_NR ? -100 : playingSound.number;
+          p_prevNote = playingSound.number == REST_NR || p_posInOgg > 61740 ? INVALID_NOTE_NR : playingSound.number;
           p_shiftOfPrev = 0;
-          p_lastPosOfPrev = p_posInNote;
+          p_lastPosOfPrev = p_posInOgg; // < 61740 ? p_posInNote : 0;
           p_playingNoteNr++;
           if (p_playingNoteNr < instance->playList().size()) {
               p_posInOgg = 0;
@@ -122,13 +123,13 @@ bool TaudioOUT::outCallBack(void* outBuff, unsigned int nBufferFrames, const RtA
           }
           p_posInOgg++;
         }
-        if (unfinished && p_prevNote > -100 && p_shiftOfPrev < CROSS_SMP) { // fade out previous note, and mix it with the current one
+        if (unfinished && p_prevNote > INVALID_NOTE_NR && p_shiftOfPrev < CROSS_SMP) { // fade out previous note, and mix it with the current one
           qint16 sample2 = instance->oggScale->getNoteSample(p_prevNote, p_lastPosOfPrev + p_shiftOfPrev);
           sample2 = static_cast<qint16>(static_cast<qreal>(sample2) * (static_cast<qreal>(CROSS_SMP - p_shiftOfPrev) / 2200.0));
           sample = mix(sample, sample2);
           p_shiftOfPrev++;
           if (p_shiftOfPrev == CROSS_SMP)
-            p_prevNote = -100;
+            p_prevNote = INVALID_NOTE_NR;
         }
         qint16 beatSample = 0;
         if (instance->tickDuringPlay() && p_beatPeriod) {
@@ -149,13 +150,12 @@ bool TaudioOUT::outCallBack(void* outBuff, unsigned int nBufferFrames, const RtA
       }
       instance->m_callBackIsBussy = false;
       endState = p_playingNoteNr >= instance->playList().size();
-  } else { // flush buffer with zeros if no sound will be played
-//       auto out = static_cast<qint32*>(outBuff); // 4 bytes for both channels at once
+  } else { // if no sound will be played: flush buffer with zeros or play a tick
       auto out = static_cast<qint16*>(outBuff);
       qint16 beatSample = 0;
       for (int i = 0; i < nBufferFrames / instance->ratioOfRate; i++) {
         beatSample = 0;
-        if (instance->tickDuringPlay() && p_beatPeriod) {
+        if (p_beatPeriod && ((instance->tickBeforePlay() && p_ticksCountBefore > 0) || instance->tickDuringPlay())) {
           if (p_beatOffset < p_beatBytes)
             beatSample = instance->getBeatsample(p_beatOffset);
           p_beatOffset++;
@@ -165,16 +165,19 @@ bool TaudioOUT::outCallBack(void* outBuff, unsigned int nBufferFrames, const RtA
               p_lastNotePlayed = false;
               p_beatPeriod = 0;
             }
+            if (p_ticksCountBefore > 0)
+              p_ticksCountBefore--;
+            else if (!instance->tickDuringPlay())
+              p_beatPeriod = 0;
           }
         }
         for (int r = 0; r < instance->ratioOfRate; r++) {
-//           *out++ = 0; // both channels at once channel
           *out++ = beatSample; // left channel
           *out++ = beatSample; // right channel
         }
       }
       instance->m_callBackIsBussy = false;
-      endState = true;
+      endState = p_ticksCountBefore == 0 && (instance->playList().isEmpty() || p_playingNoteNr >= instance->playList().size());
   }
   if (instance->p_doEmit && !areStreamsSplit() && endState) {
     ao()->emitPlayingFinished(); // emit in duplex mode
@@ -273,7 +276,7 @@ void TaudioOUT::startPlaying() {
     //  if (loops) qDebug() << "latency:" << loops << "ms";
   }
 
-  if (p_prevNote > -100) {
+  if (p_prevNote > INVALID_NOTE_NR) {
     p_shiftOfPrev = 0;
     p_lastPosOfPrev = p_posInNote;
   }
@@ -303,6 +306,7 @@ void TaudioOUT::playingFinishedSlot() {
   if (areStreamsSplit() && state() == e_playing)
     closeStream();
 
+  p_lastNotePlayed = false;
   p_isPlaying = false;
   setPlayCallbackInvolved(false);
   emit playingFinished();
@@ -312,7 +316,7 @@ void TaudioOUT::playingFinishedSlot() {
 void TaudioOUT::stop() {
   if (m_callBackIsBussy) {
     qDebug() << "[TrtAudioOUT] Stopping when outCallBack is running. Wait 2ms!";
-    QTimer::singleShot(2, [=]{ this->stop(); });
+    QTimer::singleShot(2, this, [=]{ this->stop(); });
   }
 
   /**
@@ -330,10 +334,11 @@ void TaudioOUT::stop() {
     QTimer::singleShot(50, [=]{ this->stop(); });
     return;
   }
-  p_prevNote = -100;
+  p_prevNote = INVALID_NOTE_NR;
   p_shiftOfPrev = 0;
   p_lastPosOfPrev = 0;
   p_isPlaying = false;
+  p_ticksCountBefore = 0;
   if (areStreamsSplit() /*|| getCurrentApi() == RtAudio::LINUX_PULSE*/)
     closeStream();
   else
diff --git a/src/libs/sound/trtaudioout.h b/src/libs/sound/trtaudioout.h
index b22d87c39..c2564bc44 100755
--- a/src/libs/sound/trtaudioout.h
+++ b/src/libs/sound/trtaudioout.h
@@ -63,7 +63,7 @@ protected:
 #if defined(Q_OS_WIN)
   void ASIORestartSlot();
 #endif
-  
+
 
 protected:
   static TaudioOUT               *instance; /**< Static pointer of this class instance. */
@@ -71,8 +71,8 @@ protected:
   int                             ratioOfRate; /**< ratio of current sample rate to 44100 */
 
 private:
-  bool                          m_callBackIsBussy;
-  bool                          m_singleNotePlayed = false;
+  bool                            m_callBackIsBussy;
+  bool                            m_singleNotePlayed = false;
 
 };
 
diff --git a/src/libs/sound/tsound.cpp b/src/libs/sound/tsound.cpp
index cfb42c388..6730fb49c 100644
--- a/src/libs/sound/tsound.cpp
+++ b/src/libs/sound/tsound.cpp
@@ -94,7 +94,7 @@ void Tsound::play(const Tnote& note) {
   bool playing = true;
   if (player && note.isValid()) {
     m_stopSniffOnce = true;
-    player->runMetronome(0); // reset metronome
+    stopMetronome();
     playing = player->playNote(note.chromatic());
   }
 #if defined (Q_OS_ANDROID)
@@ -119,14 +119,14 @@ void Tsound::play(const Tnote& note) {
 }
 
 
-void Tsound::playMelody(Tmelody* mel, int transposition) {
+void Tsound::playMelody(Tmelody* mel, int transposition, int countdownDuration) {
   if (player && player->isPlayable()) {
     if (player->isPlaying()) {
         stopPlaying();
     } else {
         if (mel->length()) {
           m_stopSniffOnce = true;
-          player->playMelody(mel, transposition);
+          player->playMelody(mel, transposition, 0);
         }
     }
   }
@@ -137,10 +137,10 @@ void Tsound::playNoteList(QList<Tnote>& notes, int firstNote, int countdownDurat
   if (player) {
     if (!player->isPlaying()) {
         if (!notes.isEmpty()) {
-          player->runMetronome(m_tempo);
+          runMetronome(firstNote == 0 && tickBeforePlay() ? Tmeter(static_cast<Tmeter::Emeter>(m_currentMeter)).countTo() : 0);
           m_stopSniffOnce = true;
           player->playNotes(std::addressof(notes), // beat unit has to be converted to quarter here
-                            qRound(static_cast<qreal>(m_tempo) / Tmeter::beatTempoFactor(static_cast<Tmeter::EbeatUnit>(m_beatUnit))),
+                            Tmeter::quarterTempo(m_tempo, m_beatUnit),
                             firstNote,
                             countdownDuration);
         }
@@ -260,7 +260,6 @@ float Tsound::pitch() {
 
 void Tsound::setTempo(int t) {
   if (t != m_tempo && t > 39 && t < 181) {
-    //m_tempo = qRound(15000.0 / (qRound(15000.0 / static_cast<qreal>(t) / sniffer->chunkTime()) * sniffer->chunkTime()));
     m_tempo = t;
     emit tempoChanged();
   }
@@ -268,17 +267,27 @@ void Tsound::setTempo(int t) {
 
 
 void Tsound::setBeatUnit(int bu) {
-  if (bu != m_beatUnit) {
-    m_beatUnit = bu;
-    m_tempo *= Tmeter::beatTempoFactor(static_cast<Tmeter::EbeatUnit>(bu));
-    emit tempoChanged();
+  if (bu < 0 || bu > 3)
+      qDebug() << "[Tsound] FIXME! trying to set unsupported beat unit" << bu;
+  else {
+      if (bu != m_beatUnit) {
+        m_beatUnit = bu;
+        m_tempo *= Tmeter::beatTempoFactor(static_cast<Tmeter::EbeatUnit>(bu));
+        emit tempoChanged();
+      }
   }
 }
 
 
+void Tsound::setCurrentMeter(int curMet) {
+  m_currentMeter = curMet;
+}
+
+
+
 void Tsound::setMetronome(int t, int beat) {
   if (beat != m_beatUnit || t != m_tempo) {
-    int quarterTempo = t / Tmeter::beatTempoFactor(static_cast<Tmeter::EbeatUnit>(beat));
+    int quarterTempo = Tmeter::quarterTempo(t, beat);
     if (quarterTempo >= 40 && quarterTempo <= 180) {
       m_tempo = t;
       m_beatUnit = beat;
@@ -288,6 +297,24 @@ void Tsound::setMetronome(int t, int beat) {
 }
 
 
+void Tsound::runMetronome(int preTicksNr) {
+  if (player && !m_metronomeIsRun && player->doTicking()) {
+    player->setMetronome(m_tempo);
+    if (player->tickBeforePlay() && preTicksNr) {
+      qreal preTicksSeconds = static_cast<qreal>(preTicksNr) * (60.0 / static_cast<qreal>(Tmeter::quarterTempo(m_tempo, m_beatUnit)));
+      while (preTicksSeconds < 2.0) { // Multiple number of pre-ticks if it is to short (less than 2 sec) - to give user time to catch up
+        preTicksNr += preTicksNr;
+        preTicksSeconds += preTicksSeconds;
+      }
+      player->setTicksCountBefore(preTicksNr /** Tmeter::beatTempoFactor(static_cast<Tmeter::EbeatUnit>(m_beatUnit))*/);
+      emit countdownPrepare(preTicksNr);
+    }
+    m_metronomeIsRun = true;
+    emit metroRunningChanged();
+  }
+}
+
+
 /**
  * @p m_quantVal is expressed in @p Trhythm duration of: Sixteenth triplet -> 4 or just Sixteenth -> 6 or Eighth -> 12
  */
@@ -324,15 +351,14 @@ bool Tsound::playing() const {
 void Tsound::stopListen() {
   if (sniffer)
     sniffer->stopListening();
-  if (player)
-    player->stopMetronome();
+  stopMetronome();
 }
 
 
 void Tsound::startListen() {
   if (sniffer) {
-    if (player && player->tickDuringPlay())
-      player->runMetronome(qRound(static_cast<qreal>(m_tempo) / Tmeter::beatTempoFactor(static_cast<Tmeter::EbeatUnit>(m_beatUnit))));
+    if (!sniffer->stoppedByUser())
+      runMetronome(Tmeter(static_cast<Tmeter::Emeter>(m_currentMeter)).countTo());
     sniffer->startListening();
   }
 }
@@ -524,6 +550,7 @@ void Tsound::playingFinishedSlot() {
   }
   emit plaingFinished();
   emit playingChanged();
+  stopMetronome();
 }
 
 
@@ -541,7 +568,7 @@ void Tsound::noteFinishedSlot(const TnoteStruct& note) {
   if (note.pitch.isValid())
     m_detectedNote = note.pitch;
   if (GLOB->rhythmsEnabled()) {
-      qreal rFactor = 2500.0 / (m_tempo / Tmeter::beatTempoFactor(static_cast<Tmeter::EbeatUnit>(m_beatUnit)));
+      qreal rFactor = 2500.0 / Tmeter::quarterTempo(m_tempo, m_beatUnit);
       qreal dur = (note.duration * 1000.0) / rFactor;
       int quant = dur > 20.0 ? 12 : 6; // avoid sixteenth dots
       int normDur = qRound(dur / static_cast<qreal>(quant)) * quant;
@@ -595,3 +622,13 @@ void Tsound::selectNextNote() {
       NOO->selectPlayingNote(player->playingNoteId());
   emit playingNoteIdChanged();
 }
+
+
+void Tsound::stopMetronome() {
+  if (m_metronomeIsRun) {
+    if (player)
+      player->stopMetronome();
+    m_metronomeIsRun = false;
+    emit metroRunningChanged();
+  }
+}
diff --git a/src/libs/sound/tsound.h b/src/libs/sound/tsound.h
index 90aebcddd..77633fc94 100644
--- a/src/libs/sound/tsound.h
+++ b/src/libs/sound/tsound.h
@@ -40,10 +40,10 @@ class TaudioIN;
  * @class Tsound is a wrapper of @p TaudioIN & @p TaudioOUT classes
  * to manage them. It enables/disables them depends on @p Tglobals,
  * pauses sniffing when playback is proceeding.
- * Also it has got @p TpitchView to show volume meter & pitch detection state.
  *
  * It has single instance available through @p instance()
- * defined also as a macro @p SOUND
+ * defined also as a macro @p SOUND, also available from QML under this name.
+ * It exposes needed properties and methods to QML
  */
 class NOOTKASOUND_EXPORT Tsound : public QObject
 {
@@ -61,6 +61,7 @@ class NOOTKASOUND_EXPORT Tsound : public QObject
   Q_PROPERTY(bool tickBeforePlay READ tickBeforePlay WRITE setTickBeforePlay NOTIFY tickStateChanged)
   Q_PROPERTY(bool tickDuringPlay READ tickDuringPlay WRITE setTickDuringPlay NOTIFY tickStateChanged)
   Q_PROPERTY(int playingNoteId READ playingNoteId NOTIFY playingNoteIdChanged)
+  Q_PROPERTY(bool metroRunning READ metroRunning NOTIFY metroRunningChanged)
 
   friend class TtunerDialogItem;
 
@@ -81,7 +82,7 @@ public:
 
   Q_INVOKABLE void play(const Tnote& note);
 
-  void playMelody(Tmelody* mel, int transposition = 0);
+  void playMelody(Tmelody* mel, int transposition = 0, int countdownDuration = 0);
 
   void playNoteList(QList<Tnote>& notes, int firstNote, int countdownDuration = 0);
 
@@ -136,8 +137,24 @@ public:
   int beatUnit() const { return m_beatUnit; }
   void setBeatUnit(int bu);
 
+      /**
+       * Currently set meter in main score.
+       * Due to main score lays above sound in libraries hierarchy,
+       * main score controls it when its meter changes
+       */
+  Q_INVOKABLE int currentMeter() const { return m_currentMeter; }
+  Q_INVOKABLE void setCurrentMeter(int curMet);
+
   Q_INVOKABLE void setMetronome(int t, int beat);
 
+      /**
+       * Runs metronome routines placed in @p player but only when @p tickBeforePlay or @p tickDuringPlay are set.
+       * If @p preTicksNr is set and @p tickBeforePlay is enabled,
+       * calculates tick number to countdown before playing or listening.
+       * Emits @p countdownPrepare(int preTicksNr) to initialize QML part of pre-ticking
+       */
+  void runMetronome(int preTicksNr = 0);
+
       /**
        * Quantization value determines accuracy of detecting rhythm of played note by its duration.
        */
@@ -164,6 +181,13 @@ public:
 
   int playingNoteId() const;
 
+      /**
+       * Property about state of a metronome.
+       * It is automatically initialized when @p runMetronome() is invoked
+       * and disabled when playing and listening are not performed
+       */
+  bool metroRunning() { return m_metronomeIsRun; }
+
       /**
        * Prepares sound to exam.
        * Given notes in params are level range notes and are put to sniffer ambitus.
@@ -183,7 +207,6 @@ public:
   bool tunerMode() const { return m_tunerMode; }
   void setTunerMode(bool isTuner);
 
-
 #if !defined (Q_OS_ANDROID)
   void setDumpFileName(const QString& fName);
 #endif
@@ -202,6 +225,8 @@ signals:
   void tunerModeChanged();
   void tickStateChanged();
   void playingNoteIdChanged();
+  void metroRunningChanged();
+  void countdownPrepare(int tickCount);
 
       /**
        * When sound got initialized at the very beginning
@@ -215,6 +240,8 @@ private:
   void deleteSniffer();
   void restoreSniffer(); /**< Brings back sniffer & pitch view state as such as before settings dialog */
 
+  void stopMetronome();
+
   Tnote                   m_detectedNote; /**< detected note */
   bool                    m_examMode = false;
   bool                    m_tunerMode = false;
@@ -223,7 +250,9 @@ private:
   Tmelody                *m_playedMelody;
   int                     m_tempo;
   int                     m_beatUnit = 0; /**< corresponds with Tmeter::EbeatUnit enum. Quarter by default */
+  int                     m_currentMeter = 0;
   int                     m_quantVal;
+  bool                    m_metronomeIsRun = false;
 
   static Tsound          *m_instance;
 
diff --git a/src/main/texamexecutor.cpp b/src/main/texamexecutor.cpp
index 7495b1c87..b8d34fd8a 100644
--- a/src/main/texamexecutor.cpp
+++ b/src/main/texamexecutor.cpp
@@ -323,7 +323,9 @@ void TexamExecutor::askQuestion(bool isAttempt) {
         if (!m_level.isMelodySet() && m_level.useRhythms()) {
           mergeRhythmAndMelody(rhythms, curQ->melody());
         }
-        curQ->melody()->setTempo(SOUND->tempo());
+        // So far we don't force tempo, just adjust it to user currently set
+        // We can change melody tempo due to this melody is never write back
+        curQ->melody()->setTempo(Tmeter::quarterTempo(SOUND->tempo(), SOUND->beatUnit()) * Tmeter::beatTempoFactor(curQ->melody()->beat()));
       }
       m_melody->newMelody(curQ->answerAsSound() ? curQ->melody()->length() : 0); // prepare list to store notes played by user or clear it
       m_exam->newAttempt();
@@ -548,7 +550,7 @@ void TexamExecutor::askQuestion(bool isAttempt) {
 
 
 void TexamExecutor::checkAnswer(bool showResults) {
-  TQAunit* curQ = m_exam->curQ();
+  auto curQ = m_exam->curQ();
   m_penalty->stopQuestionTime();
   m_checkQuestAct->setEnabled(false);
   if (m_playAgainAct)
@@ -1064,10 +1066,6 @@ void TexamExecutor::prepareToExam() {
   m_glStore->prepareGlobalsToExam(m_level);
   GLOB->setRhythmsEnabled(m_level.useRhythms());
 
-
-// #if !defined (Q_OS_ANDROID) // Do not show it user Android - it sucks there
-//   SOUND->pitchView()->setVisible(GLOB->L->soundViewEnabled);
-// #endif
 //   INSTRUMENT->setVisible(GLOB->L->guitarEnabled);
   if (m_level.canBeSound()) {
     SOUND->acceptSettings();
@@ -1526,10 +1524,13 @@ QString TexamExecutor::saveExamToFile() {
 
 void TexamExecutor::repeatSound() {
   if (m_exam->curQ()->melody()) {
+      int nrTicksBefore = SOUND->tickBeforePlay() ? m_exam->curQ()->melody()->meter()->countTo() : 0;
+      SOUND->runMetronome(nrTicksBefore);
       SOUND->playMelody(m_exam->curQ()->melody(),
-                        m_exam->curQ()->melody()->key() != m_exam->curQ()->key ? m_exam->curQ()->melody()->key().difference(m_exam->curQ()->key) : 0);
-      if (SOUND->melodyIsPlaying()) // the same methods stops a melody
-        m_exam->curQ()->lastAttempt()->melodyWasPlayed(); // increase only when playing was started
+                        m_exam->curQ()->melody()->key() != m_exam->curQ()->key ? m_exam->curQ()->melody()->key().difference(m_exam->curQ()->key) : 0
+                       );
+      if (SOUND->melodyIsPlaying()) // the same method can stop a melody
+        m_exam->curQ()->lastAttempt()->melodyWasPlayed(); // so increase only when playing was started
   } else
       SOUND->play(m_exam->curQ()->qa.note);
   connectPlayingFinished();
@@ -1857,10 +1858,10 @@ TtipHandler* TexamExecutor::tipHandler() { return m_tipHandler; }
 
 
 bool TexamExecutor::showPitchView() const {
-  return m_exam == nullptr || (m_exam->count() && m_exam->curQ()->answerAsSound());
+  return m_exam && m_exam->count() && m_exam->curQ()->answerAsSound();
 }
 
 
-bool TexamExecutor::showPlayView() const {
-  return false;
+bool TexamExecutor::showRtmView() const {
+  return m_exam && m_exam->count() && (m_exam->curQ()->answerAsSound() || m_exam->curQ()->questionAsSound()) && m_level.useRhythms();
 }
diff --git a/src/main/texamexecutor.h b/src/main/texamexecutor.h
index 77a370da7..350720deb 100644
--- a/src/main/texamexecutor.h
+++ b/src/main/texamexecutor.h
@@ -57,7 +57,7 @@ class TexamExecutor : public QQuickItem
   Q_PROPERTY(TtipHandler* tipHandler READ tipHandler NOTIFY tipHandlerCreated)
   Q_PROPERTY(bool isExercise READ isExercise)
   Q_PROPERTY(bool showPitchView READ showPitchView NOTIFY questionChanged)
-  Q_PROPERTY(bool showPlayView READ showPlayView NOTIFY questionChanged)
+  Q_PROPERTY(bool showRtmView READ showRtmView NOTIFY questionChanged)
 
   friend class TexamSummary;
   friend class TnootkaCertificate;
@@ -75,7 +75,7 @@ public:
   TtipHandler* tipHandler();
 
   bool showPitchView() const;
-  bool showPlayView() const;
+  bool showRtmView() const;
 
       /**
        * Describes reason of starting executor
diff --git a/src/main/tmainscoreobject.cpp b/src/main/tmainscoreobject.cpp
index ba488a02c..4ef0f4fee 100644
--- a/src/main/tmainscoreobject.cpp
+++ b/src/main/tmainscoreobject.cpp
@@ -166,6 +166,8 @@ void TmainScoreObject::setScoreObject(TscoreObject* scoreObj) {
     }
   });
   connect(m_scoreObj, &TscoreObject::stavesHeightChanged, this, &TmainScoreObject::checkExtraStaves);
+  connect(m_scoreObj, &TscoreObject::meterChanged, this, [=]{ SOUND->setCurrentMeter(m_scoreObj->meterToInt()); });
+  SOUND->setCurrentMeter(m_scoreObj->meterToInt());
 }
 
 
@@ -547,8 +549,6 @@ void TmainScoreObject::playScoreSlot() {
     if (m_scoreObj->selectedItem() && m_scoreObj->selectedItem()->index() > 0)
       countDownDur = m_scoreObj->selectedItem()->measure()->durationBefore(m_scoreObj->selectedItem());
   }
-  if (SOUND->tickBeforePlay() && countDownDur == 0) // do not count before when playing starts in the middle of a bar
-    countDownDur += m_scoreObj->meter()->duration();
   SOUND->playNoteList(m_scoreObj->noteList(), m_scoreObj->selectedItem() ? m_scoreObj->selectedItem()->index() : 0, countDownDur);
 }
 
diff --git a/src/nootka.qrc b/src/nootka.qrc
index 09c49dfcb..1eaee0530 100644
--- a/src/nootka.qrc
+++ b/src/nootka.qrc
@@ -45,6 +45,7 @@
     <file alias="sound/TempoMenu.qml">qml/sound/TempoMenu.qml</file>
     <file alias="sound/IntonationBar.qml">qml/sound/IntonationBar.qml</file>
     <file alias="sound/TunerDialog.qml">qml/sound/TunerDialog.qml</file>
+    <file alias="sound/CountdownItem.qml">qml/sound/CountdownItem.qml</file>
 
     <file alias="score/Score.qml">qml/score/Score.qml</file>
     <file alias="score/Staff.qml">qml/score/Staff.qml</file>
diff --git a/src/qml/about/AboutPage.qml b/src/qml/about/AboutPage.qml
index ec6e09599..f018bb5cd 100644
--- a/src/qml/about/AboutPage.qml
+++ b/src/qml/about/AboutPage.qml
@@ -55,7 +55,7 @@ Tflickable {
           Also there is a new look and a layout and there are new instruments (piano, saxophone and bandoneon) along with guitars.<br>
           <br>
           For more details about news in this release take a look at 'Changes' page.<br>
-          Also <a href=\"https://sourceforge.net/p/nootka/hg/ci/default/tree/TODO\">here is a link to TODO list</a> to explain what is planed next.<br>
+          Also <a href=\"https://sourceforge.net/p/nootka/hg/ci/default/tree/TODO.md\">here is a link to TODO list</a> to explain what is planed next.<br>
           <br>
           Anyway, main purpose of this release is to check all of that and give some feedback.<br>
           So happy testing,<br>
diff --git a/src/qml/exam/ExamExecutor.qml b/src/qml/exam/ExamExecutor.qml
index 75fd5bb83..876ad8a41 100644
--- a/src/qml/exam/ExamExecutor.qml
+++ b/src/qml/exam/ExamExecutor.qml
@@ -24,7 +24,7 @@ Texecutor {
   onShowSettings: {
     if (!examSettDialog) {
       var e = Qt.createComponent("qrc:/exam/ExamSettingsDialog.qml")
-      examSettDialog =  e.createObject(executor, { "mode": isExercise ? 2 : 1 } )
+      examSettDialog = e.createObject(executor, { "mode": isExercise ? 2 : 1 } )
       examSettDialog.accepted.connect(settingsAccepted)
       examSettDialog.closed.connect(function() { examSettDialog.destroy() })
     }
diff --git a/src/qml/sound/CountdownItem.qml b/src/qml/sound/CountdownItem.qml
new file mode 100644
index 000000000..485d07310
--- /dev/null
+++ b/src/qml/sound/CountdownItem.qml
@@ -0,0 +1,54 @@
+/** This file is part of Nootka (http://nootka.sf.net)               *
+ * Copyright (C) 2019 by Tomasz Bojczuk (seelook@gmail.com)          *
+ * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses)   */
+
+import QtQuick 2.9
+
+import "../"
+
+TipRect {
+  id: cntDwnItem
+
+  property int tickCount: 0
+
+  width: row.width + Noo.fontSize() * 4; height: nootkaWindow.height / 10
+  x: height * 2; y: Noo.fontSize() / 2
+  z: 100
+  color: Qt.tint(activPal.text, Noo.alpha("#00a0a0", 100))
+  visible: counter <= tickCount && (SOUND.listening || SOUND.playing)
+
+  // private
+  property int counter: 1
+
+  Connections {
+    target: tempoBar
+    onCntChanged: counter++
+  }
+
+//   Connections {
+//     target: SOUND
+//     onMetroRunningChanged: {
+//       if (SOUND.metroRunning)
+//         counter = 1
+//     }
+//   }
+
+  Row {
+    id: row
+    anchors.centerIn: parent
+    spacing: Noo.fontSize() * 2
+    Repeater {
+      id: cntRep
+      model: tickCount
+      Text {
+        y: height * 0.07
+        color: index + 1 === counter ? activPal.highlight : activPal.base
+        text: index % tempoBar.countTo + 1
+        font { pixelSize: cntDwnItem.height * 0.8; family: "Scorek" }
+      }
+    }
+  }
+
+}
+
+
diff --git a/src/qml/sound/PitchView.qml b/src/qml/sound/PitchView.qml
index edba15446..af59e0c2c 100644
--- a/src/qml/sound/PitchView.qml
+++ b/src/qml/sound/PitchView.qml
@@ -19,15 +19,13 @@ Item {
   height: parent.height * 0.9
   width: parent.width * 0.4
 
-  visible: !executor || executor.showPitchView
-
   // protected
   property real tickWidth: Screen.pixelDensity * 0.5
   property real tickGap: tickWidth * 1.4
 
   TempoBar {
     id: tempoBar
-    visible: !GLOB.singleNoteMode && GLOB.rhythmsEnabled
+    visible: !GLOB.singleNoteMode && GLOB.rhythmsEnabled && (!executor || executor.showRtmView)
     y: parent.height * 0.05
     width: parent.width
     height: parent.height * 0.45
@@ -35,6 +33,7 @@ Item {
 
   VolumeBar {
     id: volBar
+    visible: !executor || executor.showPitchView
     y: parent.height * (tempoBar.visible ? 0.55 : 0.27)
     width: parent.width
     height: parent.height * 0.45
diff --git a/src/qml/sound/TempoBar.qml b/src/qml/sound/TempoBar.qml
index 43676cd37..9289a6366 100644
--- a/src/qml/sound/TempoBar.qml
+++ b/src/qml/sound/TempoBar.qml
@@ -18,114 +18,154 @@ Item {
   property var hArray: [ 0.6, 0, 0.3, 0, 0.6]
   property var gArray: [ "\ue1d5", "\ue1d9", "\ue1d7", "\ue1d9", "\ue1d5" ]
   property int countTo: Noo.meter(score.meter).countTo()
+  property var preCountItem: null
 
   // protected
   property var beatModel: [ "\ue1d5", "\ue1d7", "\ue1d5 \ue1e7", "\ue1d3" ]
+  property real contW: metroText.width + cntBeforeBut.width + metroRow.width + loudTickButt.width + tunerButt.width
 
-  MouseArea {
-    anchors.fill: parent
-    hoverEnabled: true
-    onEntered: Noo.setStatusTip(qsTr("Metronome"), Item.TopLeft)
-    onExited: Noo.setStatusTip("", Item.TopLeft)
-  }
-
-  RectButton {
-    id: metroText
-    forcedHeight: parent.height; yOffset: parent.height * -0.7
-    statusTip: qsTr("Tempo")
-    font { family: "Scorek"; pixelSize: parent.height * 0.7 }
-    text: beatModel[SOUND.beatUnit] + "=" + SOUND.tempo
-    onClicked: {
-      if (!tMenu) {
-        var c = Qt.createComponent("qrc:/sound/TempoMenu.qml")
-        tMenu = c.createObject(tempoBar)
+  Row {
+    width: parent.width; height: parent.height
+    spacing: (width - contW) / 4 - 1
+    RectButton {
+      id: metroText
+      forcedHeight: parent.height; yOffset: parent.height * -0.7
+      statusTip: qsTr("Tempo")
+      font { family: "Scorek"; pixelSize: parent.height * 0.7 }
+      text: beatModel[SOUND.beatUnit] + "=" + SOUND.tempo
+      onClicked: {
+        if (!tMenu) {
+          var c = Qt.createComponent("qrc:/sound/TempoMenu.qml")
+          tMenu = c.createObject(tempoBar)
+        }
+        tMenu.open()
       }
-      tMenu.open()
     }
-  }
 
-  RectButton {
-    x: metroText.width + Noo.fontSize()
-    font { family: "Nootka"; pixelSize: parent.height }
-    text: "\u018f"
-    statusTip: qsTr("Audible metronome.<br>Use earphones! Otherwise ticking will disturb proper pitch detection!")
-    checked: SOUND.tickDuringPlay
-    onClicked: SOUND.tickDuringPlay = !SOUND.tickDuringPlay
-  }
+    RectButton {
+      id: cntBeforeBut
+      enabled: !SOUND.metroRunning
+      font { family: "Nootka"; pixelSize: parent.height }
+      text: "\u0190"
+      statusTip: qsTr("Countdown before playing or listening.")
+      checked: SOUND.tickBeforePlay
+      textColor: checked ? "#00a0a0" : activPal.text
+      onClicked: SOUND.tickBeforePlay = !SOUND.tickBeforePlay
+    }
 
-  Repeater {
-    id: rep
-    model: 5
-    Rectangle {
-      readonly property color bgColor: Qt.tint(activPal.window, Noo.alpha(activPal.base, 100))
-      x: tempoBar.width / 3 + index * (parent.height) - width / 2
-      y:  parent.height * (Math.abs(0.6 - hArray[index]) / 5)
-      width: parent.height * (0.9 - (Math.abs(0.6 - hArray[index]) / 3)); height: parent.height * 0.8 + hArray[index] * parent.height
-      radius: width / 2
-      color: index === hiTick && timer.running ? (index === 0 || index === 4 ? activPal.highlight : activPal.text) : bgColor
-      rotation: (index - 2) * 30
-      visible: SOUND.tempo < 110 || index % 2 !== 1
-      Text { // rhythm
-        visible: index !== hiTick || !SOUND.listening
-        font { pixelSize: parent.height * 0.8; family: "Scorek" }
-        color: disdPal.text
-        text: gArray[index]
-        y: parent.height * -0.85
-        x: (parent.width - width) / 2
-      }
-      Text { // count
-        visible: pitchView.active && index === hiTick && (!tMenu || (tMenu.count && tMenu.tickEnable))
-        font { pixelSize: parent.height; family: "Scorek" }
-        color: activPal.base
-        text: cnt
-        y: parent.height * -1.2
-        x: (parent.width - width) / 2
+    Row {
+      id: metroRow
+      enabled: !tMenu || tMenu.enableMetronome
+      height: tempoBar.height
+      spacing: height / (SOUND.tempo < 110 ? 5 : 2)
+      Repeater {
+        id: rep
+        model: 5
+        Rectangle {
+          readonly property color bgColor: Qt.tint(activPal.window, Noo.alpha(activPal.base, 100))
+          y:  parent.height * (Math.abs(0.6 - hArray[index]) / 5)
+          width: parent.height * (0.9 - (Math.abs(0.6 - hArray[index]) / 3)); height: parent.height * 0.8 + hArray[index] * parent.height
+          radius: width / 2
+          color: index === hiTick && timer.running && enabled ? (index === 0 || index === 4 ? "#00a0a0" : activPal.text) : bgColor
+          rotation: (index - 2) * 30
+          visible: SOUND.tempo < 110 || index % 2 !== 1
+          Text { // rhythm
+            visible: !enabled || (index !== hiTick || !SOUND.metroRunning)
+            font { pixelSize: parent.height * 0.8; family: "Scorek" }
+            color: enabled ? activPal.text : disdPal.text
+            text: gArray[index]
+            y: parent.height * -0.85
+            x: (parent.width - width) / 2
+          }
+          Text { // count
+            visible: timer.running && index === hiTick  && (!tMenu || (tMenu.count && tMenu.enableMetronome))
+            font { pixelSize: parent.height; family: "Scorek" }
+            color: activPal.base
+            text: cnt
+            y: parent.height * -1.2
+            x: (parent.width - width) / 2
+          }
+        }
       }
     }
-  }
 
-  Timer {
-    id: timer
-    running: visible && pitchView.active && (!tMenu || tMenu.tickEnable)
-    repeat: true
-    interval: (SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo
-    property real elap: 0
-    property real lag: 0
-    property int phase: 0
-    onRunningChanged: {
-      if (running) {
-        cnt = 1; elap = 0; lag = 0; phase = 0; hiTick = 4
-      }
+    RectButton {
+      id: loudTickButt
+      enabled: !SOUND.metroRunning
+      font { family: "Nootka"; pixelSize: parent.height }
+      text: "\u018f"
+      statusTip: qsTr("Audible metronome.<br>Use earphones! Otherwise ticking will disturb proper pitch detection!")
+      checked: SOUND.tickDuringPlay
+      textColor: checked ? "#00a0a0" : activPal.text
+      onClicked: SOUND.tickDuringPlay = !SOUND.tickDuringPlay
     }
-    onTriggered: {
-      var currTime = new Date().getTime()
-      if (elap > 0) {
-        elap = currTime - elap
-        lag += elap - interval
+
+    Timer {
+      id: timer
+      running: visible && SOUND.metroRunning //&& (!tMenu || tMenu.tickEnable)
+      repeat: true
+      interval: (SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo
+      property real elap: 0
+      property real lag: 0
+      property int phase: 0
+      onRunningChanged: {
+        if (running) {
+          cnt = 1; elap = 0; lag = 0; phase = 0; hiTick = 4
+        }
+      }
+      onTriggered: {
+        var currTime = new Date().getTime()
+        if (elap > 0) {
+          elap = currTime - elap
+          lag += elap - interval
+        }
+        elap = currTime
+        interval = Math.max(((SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo) - lag, 1)
+        lag = 0
+        if ((phase + (SOUND.tempo < 110 ? 1 : 2)) % 4 === 0) {
+          if (cnt < countTo)
+            cnt++
+          else
+            cnt = 1
+        }
+        phase += SOUND.tempo < 110 ? 1 : 2
+        if (phase > 7) phase = 0
+        hiTick = Math.abs(phase - 4)
       }
-      elap = currTime
-      interval = Math.max(((SOUND.tempo < 110 ? 15000 : 30000) / SOUND.tempo) - lag, 1)
-      lag = 0
-      if ((phase + (SOUND.tempo < 110 ? 1 : 2)) % 4 === 0) {
-        if (cnt < countTo)
-          cnt++
-        else
-          cnt = 1
+    }
+
+    RectButton {
+      id: tunerButt
+      enabled: !executor
+      textColor: enabled ? activPal.text : disdPal.text
+      text: "440Hz"
+      font { pixelSize: parent.height * 0.8; bold: true }
+      statusTip: qsTr("Tuner")
+      onClicked: {
+        nootkaWindow.showDialog(Nootka.Tuner)
+        SOUND.startListen()
       }
-      phase += SOUND.tempo < 110 ? 1 : 2
-      if (phase > 7) phase = 0
-      hiTick = Math.abs(phase - 4)
     }
   }
 
-  RectButton {
-    x: parent.width - width * 1.1
-    text: "440Hz"
-    font { pixelSize: parent.height * 0.8; bold: true }
-    statusTip: qsTr("Tuner")
-    onClicked: {
-      nootkaWindow.showDialog(Nootka.Tuner)
-      SOUND.startListen()
+  MouseArea {
+    x: metroRow.x; y: metroRow.y; width: metroRow.width; height: metroRow.height
+    hoverEnabled: true
+    onEntered: Noo.setStatusTip(qsTr("Metronome"), Item.TopLeft)
+    onExited: Noo.setStatusTip("", Item.TopLeft)
+  }
+
+  Connections {
+    target: SOUND
+    onCountdownPrepare: {
+      if (SOUND.tickBeforePlay) {
+        if (!preCountItem) {
+          var d = Qt.createComponent("qrc:/sound/CountdownItem.qml")
+          preCountItem = d.createObject(score)
+        }
+        preCountItem.tickCount = tickCount
+        preCountItem.counter = 1
+      }
     }
   }
 }
diff --git a/src/qml/sound/TempoMenu.qml b/src/qml/sound/TempoMenu.qml
index f1cfdd8eb..73ec108e7 100644
--- a/src/qml/sound/TempoMenu.qml
+++ b/src/qml/sound/TempoMenu.qml
@@ -9,7 +9,7 @@ import ".."
 
 
 Popup {
-  property alias tickEnable: metroVisibleChB.checked
+  property alias enableMetronome: metroVisibleChB.checked
   property alias count: countChB.checked
 
   margins: Noo.fontSize()
@@ -100,16 +100,18 @@ Popup {
     }
 
     TcheckBox {
+      x: Noo.fontSize()
       id: countChB
+      enabled: metroVisibleChB.checked
       text: qsTr("Count up")
       checked: true
     }
 
-    TcheckBox {
-      id: beforeTickChB
-      text: qsTr("Tick before")
-      checked: SOUND.tickBeforePlay
-    }
+//     TcheckBox {
+//       id: beforeTickChB
+//       text: qsTr("Tick before")
+//       checked: SOUND.tickBeforePlay
+//     }
 
     ButtonGroup { buttons: radioRow.children }
     Item {
@@ -147,7 +149,7 @@ Popup {
       onClicked: {
         SOUND.setMetronome(tempoSpin.value, beatUnitTumb.currentIndex)
         SOUND.quantization = radio16.checked ? 6 : 12 // See Tsound doc for values explanation
-        SOUND.tickBeforePlay = beforeTickChB.checked
+//         SOUND.tickBeforePlay = beforeTickChB.checked
         tempoSpin.value = SOUND.tempo
         accepted()
         close()
-- 
GitLab