Harmonica tablature for Musescore 2

• Apr 19, 2015 - 23:20

Greetings, and many thanks to the developers and contributors for this project.
Since I found no reference to anyone porting Harmonica Tabs to version 2 of Musescore I decided to have a try at it myself. Beginning with the NameNotes plugin I was able to come up with this.

//
// Harmonica Tabs Plugin
//
// Copyright (C) 2015 Ross Melin
// Based on Note Names Plugin
// Copyright (C) 2012 Werner Schweer
// Copyright (C) 2013, 2014 Joachim Schmitz
// Copyright (C) 2014 Jörn Eichler
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================

import QtQuick 2.0
import MuseScore 1.0

MuseScore {
version: "2.0"
description: "Harmonica Tab plugin"
menuPath: "Plugins.Harmonica.Diatonic.Richter.C"

function tabNotes (notes, text) {
for (var i = 0; i < notes.length; i++) {
var sep = "\n"; // change to "," if you want them horizontally

var harpkey = 60 // C4 (MIDI pitch value)
var richter = ["+1", "-1b", "-1", "+1o", "+2", "-2bb", "-2b", "-2", "-3bbb", "-3bb", "-3b", "-3",
"+4", "-4b", "-4", "+4o", "+5", "-5", "+5o", "+6", "-6b", "-6", "+6o", "-7",
"+7", "-7o", "-8", "+8b", "+8", "-9", "+9b", "+9", "-9o", "-10", "+10bb", "+10b",
"+10" ]; //Standard Richter tuning with overbends

var tuning = richter

if ( i > 0 )
text.text = sep + text.text;

if (typeof notes[i].pitch === "undefined") // just in case
return
if (typeof tuning[notes[i].pitch - harpkey] === "undefined")
text.text = "X";
else
text.text = tuning[notes[i].pitch - harpkey] + text.text;

} // end for note
}

onRun: {
if (typeof curScore === 'undefined')
Qt.quit();
var cursor = curScore.newCursor();
var startStaff;
var endStaff;
var endTick;
var fullScore = false;
cursor.rewind(1);
if (!cursor.segment) { // no selection
fullScore = true;
startStaff = 0; // start with 1st staff
endStaff = curScore.nstaves - 1; // and end with last
} else {
startStaff = cursor.staffIdx;
cursor.rewind(2);
if (cursor.tick == 0) {
// this happens when the selection includes
// the last measure of the score.
// rewind(2) goes behind the last segment (where
// there's none) and sets tick=0
endTick = curScore.lastSegment.tick + 1;
} else {
endTick = cursor.tick;
}
endStaff = cursor.staffIdx;
}
console.log(startStaff + " - " + endStaff + " - " + endTick)

for (var staff = startStaff; staff <= endStaff; staff++) {
for (var voice = 0; voice < 4; voice++) {
cursor.rewind(1); // beginning of selection
cursor.voice = voice;
cursor.staffIdx = staff;

if (fullScore) // no selection
cursor.rewind(0); // beginning of score

while (cursor.segment && (fullScore || cursor.tick < endTick)) {
if (cursor.element && cursor.element.type == Element.CHORD) {
var text = newElement(Element.STAFF_TEXT);

var graceChords = cursor.element.graceNotes;
for (var i = 0; i < graceChords.length; i++) {
// iterate through all grace chords
var notes = graceChords[i].notes;
tabNotes(notes, text);
// there seems to be no way of knowing the exact horizontal pos.
// of a grace note, so we have to guess:
text.pos.x = -2.5 * (graceChords.length - i);
switch (voice) {
case 0: text.pos.y = -1; break;
case 1: text.pos.y = 10; break;
case 2: text.pos.y = -2; break;
case 3: text.pos.y = 12; break;
}

cursor.add(text);
// new text for next element
text = newElement(Element.STAFF_TEXT);
}

var notes = cursor.element.notes;
tabNotes(notes, text);

switch (voice) {
case 0: text.pos.y = -1; break;
case 1: text.pos.y = 10; break;
case 2: text.pos.y = -2; break;
case 3: text.pos.y = 12; break;
}
if ((voice == 0) && (notes[0].pitch > 83))
text.pos.x = 1;
cursor.add(text);
} // end if CHORD
cursor.next();
} // end while segment
} // end for voice
} // end for staff
Qt.quit();
} // end onRun
}

Like the Harmonica tab plugin for 1.3 it could be edited to create separate plugins for different harmonica keys and tunings. I would like to have one plugin with a GUI dialog to select between keys and tuning schemes. This is a little beyond my coding skills at present. I would like to inquire if anyone has interest in assisting with this.
Sincerely,
Ross Melin


Comments

In reply to by [DELETED] 5

Yes, it is the same sort of thing, and thank you very much. I have been using your plugins up til now and have edited some for a few of my own harmonicas.
Please feel free to add the above to your project.
I will look at the example UI code and see if it looks like something I could do.
Thanks again.

I have a first attempt at a harmonica tab plugin with a UI to change keys. It is based on the shape_notes plugin. I have a couple of issues I have not been able to resolve. After running the plugin and clicking "OK" it does not apply the tabs to the score, however upon running it a second time it immediately applies the key of tabs selected on the previous run. !?
The second issue is that the Edit->Undo function is not available after applying the tabs.
The file is attached here. Can someone please review it and point me in the right direction.
Thanks.

Attachment Size
harmonica_tabs_UI.qml 6.16 KB

In reply to by rdmelin

For plugins using

pluginType: "dialog"

or if you use any other thread than the one that was called with onRun to actually change the score you need to call the startCmd() end endCmd() methods of Score. Otherwise, there well be no re-layout after your changes (that's why you don't see them at first), and they won't be added to the undo stack.
In your plugin this could be done like this:

       function apply() {
        curScore.startCmd()
        applyToSelection(tabNotes) 
        curScore.endCmd()           
      }         

Lasconic's shape_notes plugin also cannot be undone. However, I don't know, why the changes are shown immediately after running it.

I have decided to try using the ComboBox control rather that CheckBoxes. Are there any plugins using this that I could study.
Here is what I have tried.

ComboBox {
currentIndex: 0
model: ListModel {
id: keylist
ListElement { text: "C"; harpkey: 60 }
ListElement { text: "A"; harpkey: 57 }
ListElement { text: "G"; harpkey: 55 }
}
width: 100
onCurrentIndexChanged: console.debug(keylist.get(currentIndex).text + ", " + keylist.get(currentIndex).harpkey)
}

Selecting "A" from the drop list logs to the console:

Debug: A, 57

But how to assign that to a variable in js?


var harpkey = keylist.get(currentIndex).harpkey

Returns error -1

94:-1: ReferenceError: currentIndex is not defined

I can usually find code examples to get a clue from, but am finding QML, QtQuick examples elusive.
Any help is appreciated.

In reply to by heuchi

OK, I managed to get it sorted.

ComboBox {
currentIndex: 0
model: ListModel {
id: keylist
property var key
ListElement { text: "C"; harpkey: 60 }
ListElement { text: "A"; harpkey: 57 }
ListElement { text: "G"; harpkey: 55 }
}
width: 100
onCurrentIndexChanged: {
console.debug(keylist.get(currentIndex).text + ", " + keylist.get(currentIndex).harpkey)
keylist.key = keylist.get(currentIndex).harpkey
}
}

Then use the "property" in the variable assignment.

var harpkey = keylist.key

So this should make a neater UI . A few drop list Combo boxes rather than long columns of Check boxes. I should have something to put up in a short while :-)

Here is an initial offering that allows the user to choose between a few harmonica tunings, several keys, and placement of tabs above or below the staff. I will add more tunings as time allows. Please try it out and report bugs, suggestions, etc.

Attachment Size
harmonica_tabs.qml 10.03 KB

Hello,
I just installed Musescore 2.0 and re-installed the plugin harmonica_tablature, using the version currently on the website (thus the new one you adapted). I can go in Plugins Menu, go to the PLugin Manager, check the harmonica_tabs plugin and create a shortcut for it (I used ctrl-H). But I can't open or use the plugin.

I'm using Ubuntu 15.04, and tried with the plugin files copied in various places:
~/.local/share/data/MuseScore/MuseScore 2/plugins
~/Documents/MuseScore2/Plugins
/usr/share/mscore-2.0/plugins
These three directories are all detected by MuseScore, but I can't use the plugins.

Any suggestion ? What did I miss ?
Thanks
Alain

Do you still have an unanswered question? Please log in first to post your question.