diff --git a/woodwind_tab_generator/woodwind_tab_generator.qml b/woodwind_tab_generator/woodwind_tab_generator.qml
index ed83426..ae5f529 100644
--- a/woodwind_tab_generator/woodwind_tab_generator.qml
+++ b/woodwind_tab_generator/woodwind_tab_generator.qml
@@ -64,18 +64,18 @@ MuseScore {
// USER SETTINGS (& defaults)
//---------------------------------------------------------
- property int userFontSize: 6
+ property int userFontSize: 11
property int userJustification: 1 // 0=left,1=center,2=right
- property real userOffsetY: 1.2
- property real userLineSpacing: 0.7
+ property real userOffsetY: 1.7
+ property real userLineSpacing: 0.5
property string userFormatString: "" // mirrors current profile's formatString
property string userFontFamily: "Menlo, Consolas, Liberation Mono, Courier New, monospace"
property bool userTransposed: false
- property int defaultFontSize: 6
+ property int defaultFontSize: 11
property int defaultJustification: 1
- property real defaultOffsetY: 1.2
- property real defaultLineSpacing: 0.7
+ property real defaultOffsetY: 1.7
+ property real defaultLineSpacing: 0.5
property string defaultFontFamily: "Menlo, Consolas, Liberation Mono, Courier New, monospace"
property bool defaultTransposed: false
@@ -85,348 +85,69 @@ MuseScore {
//---------------------------------------------------------
// FINGERING DICTIONARY
- // Last bit = plus sign indicator
//---------------------------------------------------------
//Dictionary for your woodwind's fingerings, specifying the note and the fingering pattern (for whistles: left-> right, starting from the fipple end).
//NOTE: Note specification convention here uses sharps, so e.g. a Bb whistle needs to be defined as A#
- //2 indicates a closed hole, 1 indicates a half hole, 0 indicates open hole. The last digit is a reserved section indicating how many plusses (+) should be drawn to signal overblowing.
+ //
// ○ = 0
-// ◐ = 1
-// ● = 2
-
- //Example fingering specification for high D whistle overblowing one octave to G6
-// |---------------------------------------------
-//windway -> | | | ● ● ● ○ ○ ○ |
-// |---------------------------------------------
-// "G6": " 2 2 2 0 0 0 1 " <- last bit indicates number of +'s to add (i.e. how many times to overblow). Can be >= 0
-
+// ● = 1
+// ◐ = |
+// ◐ = -
+// ○ = o
//Example fingering specification for G#5 on a high D whistle
// |---------------------------------------------
//windway -> | | | ● ● ◐ ○ ○ ○ |
// |---------------------------------------------
-// "G#5": " 2 2 1 0 0 0 0 " <- overblow bit set to zero to indicate first octave
-// | | | | | | |
-// variables in format string: $1 $2 $3 $4 $5 $6 $+ and then $note would be replaced with 'G#5'
+// "G#5": " 1 1 | 0 0 0
+// | | | | | |
+// variables in format string: $1 $2 $3 $4 $5 $6 and then $note would be replaced with 'G#5'
// These variables are replaced by the corresponding symbol or text when run.
//Can have any number of holes in the specification
//NOTE: This plugin was generated from a maker's perspective, and thus the note names correspond with the sounding pitch, and not the
// typical octave shift down presented in notations. The dictionary can easily be edited to reflect the transposition, however, if desired.
- //TODO: Add transposition checkmark which corrects notations to octave down pitch commonly used.
//Whistle definitions
property var defaultProfiles: [
- {
- name: "Low D Whistle [D4-D6] (Prefer half-holing)",
- fingeringDict: {
- "D4": "2222220",
- "D#4": "2222210",
- "E4": "2222200",
- "F4": "2222100",
- "F#4": "2222000",
- "G4": "2220000",
- "G#4": "2210000",
- "A4": "2200000",
- "A#4": "2100000",
- "B4": "2000000",
- "C5": "0220000",
- "C#5": "0000000",
- "D5": "0222221",
- "D#5": "2222211",
- "E5": "2222201",
- "F5": "2222101",
- "F#5": "2222001",
- "G5": "2220001",
- "G#5": "2210001",
- "A5": "2200001",
- "A#5": "2100001",
- "B5": "2000001",
- "C6": "0202221",
- "C#6": "0000001",
- "D6": "2222222",
- },
- formatString: "$1\n$2\n$3\n\n$4\n$5\n$6\n$+\n\n$note"
- },
- {
- "name": "Eb Whistle [Eb-D6] (Prefer haf-holing)",
- "fingeringDict": {
- "D#4": "2222220",
- "E4": "2222210",
- "F4": "2222200",
- "F#4": "2222100",
- "G4": "2222000",
- "G#4": "2220000",
- "A4": "2210000",
- "A#4": "2200000",
- "B4": "2100000",
- "C5": "2000000",
- "C#5": "1000000",
- "D5": "0000000",
- "D#5": "0222221",
- "E5": "2222211",
- "F5": "2222201",
- "F#5": "2222101",
- "G5": "2222001",
- "G#5": "2220001",
- "A5": "2210001",
- "A#5": "2200001",
- "B5": "2100001",
- "C6": "2000001",
- "C#6": "1000001",
- "D6": "0000001"
- },
- formatString: "$1\n$2\n$3\n\n$4\n$5\n$6\n$+\n\n$note"
- },
- {
- "name": "F Whistle [F4-E6] (Prefer haf-holing)",
- "fingeringDict": {
- "F4": "2222220",
- "F#4": "2222210",
- "G4": "2222200",
- "G#4": "2222100",
- "A4": "2222000",
- "A#4": "2220000",
- "B4": "2210000",
- "C5": "2200000",
- "C#5": "2100000",
- "D5": "2000000",
- "D#5": "1000000",
- "E5": "0000000",
- "F5": "0222221",
- "F#5": "2222211",
- "G5": "2222201",
- "G#5": "2222101",
- "A5": "2222001",
- "A#5": "2220001",
- "B5": "2210001",
- "C6": "2200001",
- "C#6": "2100001",
- "D6": "2000001",
- "D#6": "1000001",
- "E6": "0000001"
- },
- formatString: "$1\n$2\n$3\n\n$4\n$5\n$6\n$+\n\n$note"
- },
- {
- "name": "G Whistle [G4-F#6] (Prefer haf-holing)",
- "fingeringDict": {
- "G4": "2222220",
- "G#4": "2222210",
- "A4": "2222200",
- "A#4": "2222100",
- "B4": "2222000",
- "C5": "2220000",
- "C#5": "2210000",
- "D5": "2200000",
- "D#5": "2100000",
- "E5": "2000000",
- "F5": "1000000",
- "F#5": "0000000",
- "G5": "0222221",
- "G#5": "2222211",
- "A5": "2222201",
- "A#5": "2222101",
- "B5": "2222001",
- "C6": "2220001",
- "C#6": "2210001",
- "D6": "2200001",
- "D#6": "2100001",
- "E6": "2000001",
- "F6": "1000001",
- "F#6": "0000001"
- },
- formatString: "$1\n$2\n$3\n\n$4\n$5\n$6\n$+\n\n$note"
- },
- {
- name: "Custom Chromatic G Whistle [G4-G#6] (9 holes)",
- fingeringDict: {
- "G4": "2222222220",
- "G#4": "2222222200",
- "A4": "2222222000",
- "A#4": "2222220000",
- "B4": "2222200000",
- "C5": "2222000000",
- "C#5": "2220000000",
- "D5": "2202000000",
- "D#5": "2022200000",
- "E5": "2020000000",
- "F5": "0220000000",
- "F#5": "0000000000",
- "G5": "2222222221",
- "G#5": "2222222201",
- "A5": "2222222001",
- "A#5": "2222220001",
- "B5": "2222200001",
- "C6": "2222000001",
- "C#6": "2220000001",
- "D6": "2200000001",
- "D#6": "2222222202",
- "E6": "2222222002",
- "F6": "2222220002",
- "F#6": "0222200002",
- "G6": "2222222222",
- "G#6": "0222222222"
- },
- formatString: "$1 \n$2\n$3\n$4\n$5\n\n$6\n$7\n$8\n$9\n$+\n$note"
- },
- {
- "name": "Bb Whistle [Bb4-A6] (Prefer haf-holing)",
- "fingeringDict": {
- "A#4": "2222220",
- "B4": "2222210",
- "C5": "2222200",
- "C#5": "2222100",
- "D5": "2222000",
- "D#5": "2220000",
- "E5": "2210000",
- "F5": "2200000",
- "F#5": "2100000",
- "G5": "2000000",
- "G#5": "1000000",
- "A5": "0000000",
- "A#5": "0222221",
- "B5": "2222211",
- "C6": "2222201",
- "C#6": "2222101",
- "D6": "2222001",
- "D#6": "2220001",
- "E6": "2210001",
- "F6": "2200001",
- "F#6": "2100001",
- "G6": "2000001",
- "G#6": "1000001",
- "A6": "0000001"
- },
- formatString: "$1\n$2\n$3\n\n$4\n$5\n$6\n$+\n\n$note"
- },
- {
- "name": "C Whistle [C4-C6] (Prefer cross-fingering)",
- "fingeringDict": {
- "C4": "2222220",
- "C#4": "2222210",
- "D4": "2222200",
- "D#4": "2222100",
- "E4": "2222000",
- "F4": "2220000",
- "F#4": "2210000",
- "G4": "2200000",
- "G#4": "2022220",
- "A4": "2000000",
- "A#4": "0220000",
- "B4": "0000000",
- "C5": "0222221",
- "C#5": "2222211",
- "D5": "2222201",
- "D#5": "2222101",
- "E5": "2222001",
- "F5": "2220001",
- "F#5": "2202201",
- "G5": "2200001",
- "G#5": "2020001",
- "A5": "2000001",
- "A#5": "0202221",
- "B5": "0000001",
- "C6": "0222222",
- },
- formatString: "$1\n$2\n$3\n\n$4\n$5\n$6\n$+\n\n$note"
- },
{
"name": "Soprano Recorder",
"fingeringDict": {
- "C4": "222222220",
- "C#4": "222222210",
- "D4": "222222200",
- "D#4": "222222100",
- "E4": "222222000",
- "F4": "222200000",
- "F#4": "222100000",
- "G4": "222000000",
- "G#4": "221000000",
- "A4": "220000000",
- "A#4": "210000000",
- "B4": "200000000",
- "C5": "000222221",
- "C#5": "002222211",
- "D5": "002222201",
- "D#5": "002222101",
- "E5": "002222001",
- "F5": "002220001",
- "F#5": "002210001",
- "G5": "002200001",
- "G#5": "002100001",
- "A5": "002000001",
- "A#5": "001000001",
- "B5": "000000001",
+ "C4": "11111111",
+ "C#4": "1111111|",
+ "D4": "11111110",
+ "D#4": "111111|o",
+ "E4": "111111oo",
+ "F4": "11110011",
+ "F#4": "1111011o",
+ "G4": "111100oo",
+ "G#4": "111011|o",
+ "A4": "111000oo",
+ "A#4": "110110oo",
+ "B4": "110000oo",
+ "C5": "101000oo",
+ "C#5": "011000oo",
+ "D5": "001000oo",
+ "D#5": "0011111o",
+ "E5": "-11111oo",
+ "F5": "-111101o",
+ "F#5": "-11101oo",
+ "G5": "-11100oo",
+ "G#5": "-11010oo",
+ "A5": "-11000oo",
+ "A#5": "-110011|",
+ "B5": "-11011oo",
+ "C6": "-10011oo",
+ "C#6": "-1011011",
+ "D6": "-1011011",
+ "D#6": "-011011o",
},
- formatString: "$note\n\n$1\n-\n$2\n$3\n$4\n-\n$5\n$6\n$7\n$8\n$+"
+ formatString: "$note\n\n$1\n—\n$2\n$3\n$4\n—\n$5\n$6\n$7\n$8"
},
- {
- name: "High D Whistle [D5-D7] (Prefer half-holing)",
- fingeringDict: {
- "D5": "2222220",
- "D#5": "2222210",
- "E5": "2222200",
- "F5": "2222100",
- "F#5": "2222000",
- "G5": "2220000",
- "G#5": "2210000",
- "A5": "2200000",
- "A#5": "2100000",
- "B5": "2000000",
- "C6": "0220000",
- "C#6": "0000000",
- "D6": "0222221",
- "D#6": "2222211",
- "E6": "2222201",
- "F6": "2222101",
- "F#6": "2222001",
- "G6": "2220001",
- "G#6": "2210001",
- "A6": "2200001",
- "A#6": "2100001",
- "B6": "2000001",
- "C7": "0202221",
- "C#7": "0000001",
- "D7": "2222222",
- },
- formatString: "$1\n$2\n$3\n\n$4\n$5\n$6\n$+\n\n$note"
- },
- {
- // OCARINA. from hole 1 to 12 they are:
- //$1 LThumb, $2 Lindex, $3 LMiddle, $4 Lring, $5 LPinky $6 LSubhole ->
- // -> $7 RThumb, $8 RIndex, $9 RMiddle, $10 RRing, $11 RPinky, $12 RSubhole
- //Requires centered text
- name: "Alto C Ocarina [A4-F6] (12 hole)",
- "fingeringDict": {
- "A4": "2222222222220",
- "A#4": "2222222222200",
- "B4": "2222202222020",
- "C5": "2222202222200",
- "C#5": "2222202222020",
- "D5": "2222202222000",
- "D#5": "2222202220020",
- "E5": "2222202220000",
- "F5": "2222202200000",
- "F#5": "2222202002000",
- "G5": "2222202000000",
- "G#5": "2220202002000",
- "A5": "2220202000000",
- "A#5": "2200202002000",
- "B5": "2200202000000",
- "C6": "2000202000000",
- "C#6": "0000202002000",
- "D6": "0000202000000",
- "D#6": "0000200002000",
- "E6": "0000200000000",
- "F6": "0000000000000"
- },
- formatString: " $11\n $5 $10\n $4 $12$9\n $3 $8\n $2$6 \n\n $1 $7\n$note"
- }
]
// Runtime copy of profiles (loaded/saved via preferences)
@@ -680,100 +401,86 @@ MuseScore {
}
//---------------------------------------------------------
- // BUILD ASCII DIAGRAM
+ // BUILD UTF-8 DIAGRAM
//---------------------------------------------------------
//Build fingering text using binary representation of the fingering for a note.
- //The last bit is the plus bit, indicating the first octave (0) or the second octave (1), to be annotated with a +
function buildFingeringText(binaryString, formatString, noteName) {
- if (!binaryString || binaryString.length < 2)
+ const open = "0"
+ const closed = "1"
+ const half_ver = "|"
+ const half_hor = "-"
+ const open_split = "o"
+ if (!binaryString || binaryString.length < 1)
return "Invalid fingering pattern. Length is wrong"
- if (!formatString || typeof formatString !== "string")
- return "ERR"
+ if (!formatString || typeof formatString !== "string")
+ return "ERR"
- var holeCount = binaryString.length - 1
- var plusBit = binaryString[binaryString.length - 1]
+ var holeCount = binaryString.length
- //-------------------------------------------------
- // Validate allowed characters
- //-------------------------------------------------
+ //-------------------------------------------------
+ // Validate allowed characters
+ //-------------------------------------------------
- for (var i = 0; i < holeCount; i++) {
- if (binaryString[i] !== "0" &&
- binaryString[i] !== "1" &&
- binaryString[i] !== "1" &&
- binaryString[i] !== "2" &&
- binaryString[i] !== "3")
- return "Invalid Fingering Pattern Value. Must be one of 0,1,2"
- }
+ for (var i = 0; i < holeCount; i++) {
+ if (binaryString[i] !== open &&
+ binaryString[i] !== closed &&
+ binaryString[i] !== half_ver &&
+ binaryString[i] !== half_hor &&
+ binaryString[i] !== open_split)
+ return "Invalid Fingering Pattern Value. Check the config in the .qml file!"
+ }
- var plusInt = parseInt(plusBit)
- if (isNaN(plusInt) || plusInt < 0 || plusInt.toString() !== plusBit) {
- return "Invalid Plus Bit: must be a positive integer (0, 1, 2, ...)"
- }
- //-------------------------------------------------
- // Clone format string
- //-------------------------------------------------
+ //-------------------------------------------------
+ // Clone format string
+ //-------------------------------------------------
- var output = formatString
+ var output = formatString
- //-------------------------------------------------
- // Replace note placeholder ($note) with note name
- //-------------------------------------------------
+ //-------------------------------------------------
+ // Replace note placeholder ($note) with note name
+ //-------------------------------------------------
- if (noteName) {
- while (output.indexOf("$note") !== -1) {
- output = output.replace("$note", noteName)
- }
- }
+ if (noteName) {
+ while (output.indexOf("$note") !== -1) {
+ output = output.replace("$note", noteName)
+ }
+ }
- //-------------------------------------------------
- // Replace numbered placeholders ($1 … $N)
- //-------------------------------------------------
+ //-------------------------------------------------
+ // Replace numbered placeholders ($1 … $N)
+ //-------------------------------------------------
- for (var i = holeCount - 1; i >= 0; i--) {
- var symbol
- if (binaryString[i] === "2")
- symbol = String.fromCharCode(0x25CF) // Closed hole - custom font
- else if (binaryString[i] === "1")
- symbol = String.fromCharCode(0x25D0) // Half hole - custom font
- else if (binaryString[i] == "3")
- symbol = String.fromCharCode(0x25D2) // Bottom half hole
- else if (binaryString[i] == "4")
- symbol = String.fromCharCode(0x29B6) // Open Hold with line
- else
- symbol = String.fromCharCode(0x25CB) // Open Hole - custom font
+ for (var i = holeCount - 1; i >= 0; i--) {
+ var symbol
+ if (binaryString[i] === closed)
+ symbol = String.fromCharCode(0x25CF) // closed hole
+ if (binaryString[i] === half_ver)
+ symbol = String.fromCharCode(0x25D1) // Half hole, covered on the side
+ if (binaryString[i] == half_hor)
+ symbol = String.fromCharCode(0x25D2) // Half hole, covered on the bottom
+ if (binaryString[i] == open_split)
+ symbol = String.fromCharCode(0x29B6) // Open Hole with line
+ // symbol = String.fromCharCode(0x25CB) + String.fromCharCode(0x20D2)
+ if (binaryString[i] == open)
+ symbol = String.fromCharCode(0x25CB) // Open Hole
- var token = "$" + (i+1)
- while (output.indexOf(token) !== -1) {
- output = output.replace(token, symbol)
- }
- }
+ var token = "$" + (i+1)
+ while (output.indexOf(token) !== -1) {
+ output = output.replace(token, symbol)
+ }
+ }
- var plusCount = parseInt(plusBit)
- var plusSymbol = "+".repeat(plusCount)
- if (plusCount === 0) {
- plusSymbol = ""
- }
+ //-------------------------------------------------
+ // Final validation
+ //-------------------------------------------------
- //-------------------------------------------------
- // Replace plus placeholder ($+) with number of plusses based on plus bit
- //-------------------------------------------------
+ if (output.indexOf("$") !== -1) {
+ console.log("Warning: Unreplaced placeholders in:", output)
+ }
- while (output.indexOf("$+") !== -1) {
- output = output.replace("$+", plusSymbol)
- }
-
- //-------------------------------------------------
- // Final validation
- //-------------------------------------------------
-
- if (output.indexOf("$") !== -1) {
- console.log("Warning: Unreplaced placeholders in:", output)
- }
-
- return output
+ return output
}
//---------------------------------------------------------
@@ -954,15 +661,13 @@ MuseScore {
var text = newElement(Element.STAFF_TEXT)
if (!dict[noteName]) {
- text.text = "☒"
+ diagram = noteName + "\n☒"
console.log("Note not in dictionary:", noteName)
} else {
var diagram = buildFingeringText(dict[noteName], userFormatString, noteName)
-
- text.text = "" + diagram + "";
-
console.log("Note:", noteName, "Diagram:", diagram.replace(/\n/g, "\\n"))
}
+ text.text = "" + diagram + "";
cursor.add(text)
formatText(text)
@@ -1041,7 +746,8 @@ MuseScore {
// Build the full font stack dynamically
function getFontStack() {
- return "WhistleSymbols" + ", " + userFontFamily;
+ // return "WhistleSymbols" + ", " + userFontFamily;
+ return userFontFamily
}
@@ -1662,7 +1368,7 @@ MuseScore {
}
Label {
- text: "Use placeholders like $1, $2, ..., for the holes, \n$+ for the plus indicator and $note for the note (e.g. G#5)"
+ text: "Use placeholders like $1, $2, ..., for the holes and $note for the note (e.g. G#5)"
font.pixelSize: 10
color: textColor
}