1
+ //=============================================================================
2
+ // MuseScore
3
+ // Music Composition & Notation
4
+ //
5
+ // Harmonica Tabs Plugin
6
+ //
7
+ // Copyright (C) 2015 Ross Melin
8
+ //
9
+ // This program is free software; you can redistribute it and/or modify
10
+ // it under the terms of the GNU General Public License version 2
11
+ // as published by the Free Software Foundation and appearing in
12
+ // the file LICENCE.GPL
13
+ //=============================================================================
14
+
15
+ import QtQuick 2.2
16
+ import QtQuick.Controls 1.1
17
+ import QtQuick.Layouts 1.1
18
+ import MuseScore 1.0
19
+
20
+ MuseScore {
21
+ version: " 2.0"
22
+ description: " Harmonica Tab plugin"
23
+ menuPath: " Plugins.Harmonica Tablature"
24
+ pluginType: " dialog"
25
+
26
+ id: window
27
+ width: 280
28
+ height: 180
29
+ ColumnLayout {
30
+ id: column
31
+ anchors .margins : 10
32
+ anchors .top : parent .top
33
+ anchors .left : parent .left
34
+ anchors .right : parent .right
35
+ height: 90
36
+
37
+ ComboBox {
38
+ currentIndex: 9
39
+ model: ListModel {
40
+ id: keylist
41
+ property var key
42
+ ListElement { text: " Low A" ; harpkey: 45 }
43
+ ListElement { text: " Low C" ; harpkey: 48 }
44
+ ListElement { text: " Low D" ; harpkey: 50 }
45
+ ListElement { text: " Low F" ; harpkey: 53 }
46
+ ListElement { text: " G" ; harpkey: 55 }
47
+ ListElement { text: " Ab" ; harpkey: 56 }
48
+ ListElement { text: " A" ; harpkey: 57 }
49
+ ListElement { text: " Bb" ; harpkey: 58 }
50
+ ListElement { text: " B" ; harpkey: 59 }
51
+ ListElement { text: " C" ; harpkey: 60 }
52
+ ListElement { text: " Db" ; harpkey: 61 }
53
+ ListElement { text: " D" ; harpkey: 62 }
54
+ ListElement { text: " Eb" ; harpkey: 63 }
55
+ ListElement { text: " E" ; harpkey: 64 }
56
+ ListElement { text: " F" ; harpkey: 65 }
57
+ ListElement { text: " F#" ; harpkey: 66 }
58
+ ListElement { text: " High G" ; harpkey: 67 }
59
+ }
60
+ width: 100
61
+ onCurrentIndexChanged: {
62
+ console .debug (keylist .get (currentIndex).text + " , " + keylist .get (currentIndex).harpkey )
63
+ keylist .key = keylist .get (currentIndex).harpkey
64
+ }
65
+ }
66
+ ComboBox {
67
+ currentIndex: 0
68
+ model: ListModel {
69
+ id: harp
70
+ property var tuning
71
+ ListElement { text: " Richter (Blues Harp)" ; tuning: 1 }
72
+ ListElement { text: " Richter half valved" ; tuning: 2 }
73
+ ListElement { text: " Country" ; tuning: 3 }
74
+ ListElement { text: " Standard Chromatic" ; tuning: 4 }
75
+ }
76
+ width: 100
77
+ onCurrentIndexChanged: {
78
+ console .debug (harp .get (currentIndex).text + " , " + harp .get (currentIndex).tuning )
79
+ harp .tuning = harp .get (currentIndex).tuning
80
+ }
81
+ }
82
+ ComboBox {
83
+ currentIndex: 1
84
+ model: ListModel {
85
+ id: placetext
86
+ property var position
87
+ ListElement { text: " Higher" ; position: - 2 }
88
+ ListElement { text: " Above staff" ; position: 0 }
89
+ ListElement { text: " Below staff" ; position: 10 }
90
+ ListElement { text: " Lower" ; position: 12 }
91
+ }
92
+ width: 100
93
+ onCurrentIndexChanged: {
94
+ console .debug (placetext .get (currentIndex).text + " , " + placetext .get (currentIndex).position )
95
+ placetext .position = placetext .get (currentIndex).position
96
+ }
97
+ }
98
+ }
99
+ RowLayout {
100
+ anchors .horizontalCenter : parent .horizontalCenter
101
+ anchors .top : column .bottom
102
+ height: 70
103
+ Button {
104
+ id: okButton
105
+ text: " Ok"
106
+ onClicked: {
107
+ apply ()
108
+ Qt .quit ()
109
+ }
110
+ }
111
+ Button {
112
+ id: closeButton
113
+ text: " Close"
114
+ onClicked: { Qt .quit () }
115
+ }
116
+
117
+ }
118
+
119
+ function tabNotes (notes , text ) {
120
+
121
+ var richter = [" +1" , " -1b" , " -1" , " +1o" , " +2" , " -2bb" , " -2b" , " -2" , " -3bbb" , " -3bb" , " -3b" , " -3" ,
122
+ " +4" , " -4b" , " -4" , " +4o" , " +5" , " -5" , " +5o" , " +6" , " -6b" , " -6" , " +6o" , " -7" ,
123
+ " +7" , " -7o" , " -8" , " +8b" , " +8" , " -9" , " +9b" , " +9" , " -9o" , " -10" , " +10bb" , " +10b" ,
124
+ " +10" ]; // Standard Richter tuning with overbends
125
+
126
+
127
+ var richterValved = [" +1" , " -1b" , " -1" , " +2b" , " +2" , " -2bb" , " -2b" , " -2" , " -3bbb" , " -3bb" , " -3b" , " -3" ,
128
+ " +4" , " -4b" , " -4" , " +5b" , " +5" , " -5" , " +6b" , " +6" , " -6b" , " -6" , " -7b" , " -7" ,
129
+ " +7" , " -8b" , " -8" , " +8b" , " +8" , " -9" , " +9b" , " +9" , " -10b" , " -10" , " +10bb" , " +10b" ,
130
+ " +10" ];
131
+ richterValved[- 2 ] = " +1bb" ; richterValved[- 1 ] = " +1b" ; // Two notes below the key at blow 1
132
+
133
+ var country = [" +1" , " -1b" , " -1" , " +1o" , " +2" , " -2bb" , " -2b" , " -2" , " +2o" , " -3bb" , " -3b" , " -3" ,
134
+ " +4" , " -4b" , " -4" , " +4o" , " +5" , " -5b" , " -5" , " +6" , " -6b" , " -6" , " +6o" , " -7" ,
135
+ " +7" , " -7o" , " -8" , " +8b" , " +8" , " -9" , " +9b" , " +9" , " -9o" , " -10" , " +10bb" , " +10b" ,
136
+ " +10" ];
137
+
138
+ var standardChromatic = [" +1" , ' +1s' , " -1" , " +2" , " -2" , " -2s" , " +3" , " +3s" , " -3" , " -3s" ," -4" ,
139
+ " +4" , " +4s" , " -5" , " -5s" , " +6" , " -6" , " -6s" , " +7" , " +7s" , " -7" , " -7s" , " -8" ,
140
+ " +8" , " +8s" , " -9" , " -9s" , " +10" , " -10" , " -10s" , " +11" , " +11s" , " -11" , " -11s" , " -12" ,
141
+ " +12" , " +12s" , " -12" ];
142
+
143
+ var tuning = richter
144
+ switch (harp .tuning ) {
145
+ case 1 : tuning = richter; break ;
146
+ case 2 : tuning = richterValved; break ;
147
+ case 3 : tuning = country; break ;
148
+ case 4 : tuning = standardChromatic; break ;
149
+ default : tuning = richter; break ;
150
+ }
151
+
152
+
153
+ var harpkey = keylist .key
154
+ console .log (" harpkey set to " + keylist .key )
155
+
156
+
157
+ for (var i = 0 ; i < notes .length ; i++ ) {
158
+ var sep = " \n " ; // change to "," if you want them horizontally
159
+ if ( i > 0 )
160
+ text .text = sep + text .text ;
161
+
162
+ if (typeof notes[i].pitch === " undefined" ) // just in case
163
+ return
164
+ if (typeof tuning[notes[i].pitch - harpkey] === " undefined" )
165
+ text .text = " X" ;
166
+ else
167
+ text .text = tuning[notes[i].pitch - harpkey] + text .text ;
168
+ }
169
+ }
170
+
171
+ function applyToSelection (func ) {
172
+ if (typeof curScore === ' undefined' )
173
+ Qt .quit ();
174
+ var cursor = curScore .newCursor ();
175
+ var startStaff;
176
+ var endStaff;
177
+ var endTick;
178
+ var fullScore = false ;
179
+ var textposition = placetext .position
180
+ console .log (" textposition set to " + placetext .position )
181
+ cursor .rewind (1 );
182
+ if (! cursor .segment ) { // no selection
183
+ fullScore = true ;
184
+ startStaff = 0 ; // start with 1st staff
185
+ endStaff = curScore .nstaves - 1 ; // and end with last
186
+ } else {
187
+ startStaff = cursor .staffIdx ;
188
+ cursor .rewind (2 );
189
+ if (cursor .tick == 0 ) {
190
+ // this happens when the selection includes
191
+ // the last measure of the score.
192
+ // rewind(2) goes behind the last segment (where
193
+ // there's none) and sets tick=0
194
+ endTick = curScore .lastSegment .tick + 1 ;
195
+ } else {
196
+ endTick = cursor .tick ;
197
+ }
198
+ endStaff = cursor .staffIdx ;
199
+ }
200
+ console .log (startStaff + " - " + endStaff + " - " + endTick)
201
+
202
+ for (var staff = startStaff; staff <= endStaff; staff++ ) {
203
+ for (var voice = 0 ; voice < 4 ; voice++ ) {
204
+ cursor .rewind (1 ); // beginning of selection
205
+ cursor .voice = voice;
206
+ cursor .staffIdx = staff;
207
+
208
+ if (fullScore) // no selection
209
+ cursor .rewind (0 ); // beginning of score
210
+
211
+ while (cursor .segment && (fullScore || cursor .tick < endTick)) {
212
+ if (cursor .element && cursor .element .type == Element .CHORD ) {
213
+ var text = newElement (Element .STAFF_TEXT );
214
+
215
+ var graceChords = cursor .element .graceNotes ;
216
+ for (var i = 0 ; i < graceChords .length ; i++ ) {
217
+ // iterate through all grace chords
218
+ var notes = graceChords[i].notes ;
219
+ tabNotes (notes, text);
220
+ // there seems to be no way of knowing the exact horizontal pos.
221
+ // of a grace note, so we have to guess:
222
+ text .pos .x = - 2.5 * (graceChords .length - i);
223
+ text .pos .y = textposition;
224
+ cursor .add (text);
225
+ // new text for next element
226
+ text = newElement (Element .STAFF_TEXT );
227
+ }
228
+
229
+ var notes = cursor .element .notes ;
230
+ tabNotes (notes, text);
231
+ text .pos .y = textposition;
232
+
233
+ if ((voice == 0 ) && (notes[0 ].pitch > 83 ))
234
+ text .pos .x = 1 ;
235
+ cursor .add (text);
236
+ } // end if CHORD
237
+ cursor .next ();
238
+ } // end while segment
239
+ } // end for voice
240
+ } // end for staff
241
+ Qt .quit ();
242
+ } // end applyToSelection()
243
+
244
+ function apply () {
245
+ curScore .startCmd ()
246
+ applyToSelection (tabNotes)
247
+ curScore .endCmd ()
248
+ }
249
+
250
+ onRun: {
251
+ if (typeof curScore === ' undefined' )
252
+ Qt .quit ();
253
+ }
254
+ }
0 commit comments