/* Copyright © 2024 yonah_ag
*
* This program is free software; you can redistribute it or modify it under
* the terms of the GNU General Public License version 3 as published by the
* Free Software Foundation and appearing in the accompanying LICENSE file.
*
* Description
* -----------
*
*/
import MuseScore 3.0
import QtQuick 2.2
import QtQuick.Controls 1.5
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.3
// import QtQuick.Controls.Styles 1.3
// import Qt.labs.settings 1.0
// import FileIO 3.0
MuseScore
{
description: "Bow Direction";
requiresScore: true;
version: "0.4.1";
menuPath: "Plugins.Bow Direction";
pluginType: "dialog"; // "dock";
property var noteName : [ "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
property var bowText : "xdup45678r"
property var mTick : []
property var mBow : []
property var tinfo : ""
// =======================================================================================================================
function mapAll()
{
infoWin.visible = true;
var ix=0; var tick; var info;
var elm; var etyp
var zunk; // unknown element
var zsys; // parent is system
tinfo = "
";
tinfo += "All Elements
";
tinfo += "
";
tinfo += " index | Track | Element Name | SegTick "
tinfo += " | Details | ^Parent^ | ^^Parent^^ |
";
cmd('select-all')
var selected = curScore.selection.elements;
for (var ee in selected) {
elm = selected[ee];
// if (elm.track > 0) break;
zunk = false;
zsys = false;
etyp = elm.type;
switch (etyp) {
case Element.NOTE:
if (elm.noteType==0) {
tick = elm.parent.parent.tick;
info = noteName[(elm.pitch % 12)];
if (elm.tieForward) info += " ~f";
if (elm.tieBack) info += " ~b";
}
else {
tick = elm.parent.parent.parent.tick + " *"; // grace note
info = noteName[(elm.pitch % 12)] + " *";
}
break;
case Element.STEM:
case Element.HOOK:
case Element.ACCIDENTAL:
case Element.ARPEGGIO:
tick = "";
info = "";
break;
case Element.REST:
case Element.BAR_LINE:
case Element.DYNAMIC:
case Element.HARMONY:
case Element.TEMPO_TEXT:
case Element.CLEF:
tick = elm.parent.tick;
switch (etyp) {
case Element.REST:
info = elm.duration.str;
break;
case Element.DYNAMIC:
info = "v = " + elm.velocity;
break;
case Element.HARMONY:
info = elm.text;
break;
default:
info = "";
}
break;
case Element.ARTICULATION:
case Element.LYRICS:
if (etyp==Element.ARTICULATION) {
info = elm.symbol;
if (info==2652) {
info = "Down bow";
}
else if (info==2677) {
info = "Up bow";
}
}
else {
info = elm.text;
}
tick = elm.parent.parent.tick;
break;
case Element.STAFF_TEXT:
tick = elm.parent.tick;
info = elm.text.substring(0,20);
break;
case Element.NOTEDOT:
tick = elm.parent.parent.parent.tick;
info = "";
break;
case Element.BREATH:
tick = elm.parent.tick;
info = elm.symbol;
break;
case Element.BEAM:
case Element.TIE:
case Element.SLUR:
case Element.TEXTLINE:
case Element.VIBRATO:
zsys = true;
tick = "";
info = "";
break;
default:
tick = "";
info = "";
zunk = true;
}
++ix;
tinfo += "" + ix + " ";
tinfo += " | " + elm.track;
tinfo += " | " + elm.type + " - " + elm.name + " ";
tinfo += " | " + tick + " ";
tinfo += " | " + info + " ";
if (zunk)
tinfo += " | | ";
else if (zsys)
tinfo += " | System | ";
else {
tinfo += " | " + elm.parent.name + " ";
tinfo += " | " + elm.parent.parent.name + " ";
}
tinfo += " |
";
}
curScore.selection.clear();
tinfo += "
";
popInfo.text = tinfo;
}
// =======================================================================================================================
function mapBow()
{
infoWin.visible = true;
var ix=0;
var tick; var info;
var elm; var etyp; var zelm;
var zunk; // unknown element
var zsys; // parent is system
tinfo = "";
tinfo += "Bowing Elements
";
tinfo += "
";
tinfo += " index | Track | Element Name | SegTick "
tinfo += " | Details | ^Parent^ | ^^Parent^^ |
";
cmd('select-all')
var selected = curScore.selection.elements;
for (var ee in selected) {
elm = selected[ee];
if (elm.track > 0) break;
zunk = false;
zsys = false;
etyp = elm.type;
switch (etyp) {
case Element.NOTE:
zelm = true;
if (elm.noteType==0) {
tick = elm.parent.parent.tick;
info = noteName[(elm.pitch % 12)];
if (elm.tieForward) info += " ~f";
if (elm.tieBack) info += " ~b";
}
else {
tick = elm.parent.parent.parent.tick + " *"; // grace note
info = noteName[(elm.pitch % 12)] + " *";
}
break;
case Element.REST:
zelm = true;
tick = elm.parent.tick;
info = elm.duration.str;
break;
case Element.ARTICULATION:
info = elm.symbol;
zelm = false;
if (info==2652) {
info = "Down bow";
tick = elm.parent.parent.tick;
zelm = true;
}
else if (info==2677) {
info = "Up bow";
tick = elm.parent.parent.tick;
zelm = true;
}
break;
case Element.STAFF_TEXT:
info = elm.text;
zelm = (info == "pizz." || info == "arco");
if (zelm) tick = elm.parent.tick;
break;
case Element.BREATH:
zelm = true;
tick = elm.parent.tick;
info = elm.symbol;
break;
case Element.TIE:
case Element.SLUR:
zelm = true;
zsys = true;
tick = "";
info = "";
break;
default:
zelm = false;
}
if (zelm) {
++ix;
tinfo += "" + ix + " ";
tinfo += " | " + elm.track;
tinfo += " | " + elm.name + " ";
tinfo += " | " + tick + " ";
tinfo += " | " + info + " ";
if (zsys)
tinfo += " | System | ";
else {
tinfo += " | " + elm.parent.name + " ";
tinfo += " | " + elm.parent.parent.name + " ";
}
tinfo += " |
";
}
}
curScore.selection.clear();
tinfo += "
";
popInfo.text = tinfo;
}
// =======================================================================================================================
function mapTick()
{
var ix; var ibow;
var tick; var info;
var elm; var etyp;
if (inpMapType.currentIndex==2) infoBow.visible = true;
cmd('select-all')
var selected = curScore.selection.elements;
mTick.length = 0;
mBow.length = 0;
ix = -1;
ibow = 1;
for (var ee in selected) {
elm = selected[ee];
if (elm.track > 0) break;
etyp = elm.type;
switch (etyp) {
case Element.NOTE:
if (elm.noteType==0) {
if (elm.tieBack) ibow = 3-ibow;
ix++;
mTick.push(tick = elm.parent.parent.tick);
mBow.push(ibow);
if (ibow<3) ibow = 3-ibow;
}
break;
case Element.REST:
ix++;
mTick.push(elm.parent.tick);
mBow.push(9);
ibow = 1;
break;
case Element.ARTICULATION:
info = elm.symbol;
if (info==2652) {
mBow[ix]=1;
ibow = 2;
}
else if (info==2677) {
mBow[ix]=2;
ibow = 1;
}
break;
case Element.STAFF_TEXT:
info = elm.text;
if (info=="pizz.") {
ibow = 3;
}
else if (info=="arco") {
ibow = 1;
}
break;
case Element.BREATH:
tick = elm.parent.tick;
ibow =1;
break;
// case Element.TIE: // handled via note tieBack property
// break;
}
}
curScore.selection.clear();
if (inpMapType.currentIndex==2) {
tinfo = "";
tinfo += "Bow @ Tick
";
tinfo += "
";
tinfo += " SegTick | Bow |
";
for (var ee = 0; ee < mTick.length; ee++)
{
tinfo += ""+mTick[ee]+" ";
tinfo += " | "+bowText.substring(mBow[ee],mBow[ee]+1)+" |
";
}
tinfo += "
";
popBow.text = tinfo;
}
else {
curScore.startCmd();
var cur = curScore.newCursor();
var tob; // text object
for (var ee = 0; ee < mTick.length; ee++)
{
cur.rewindToTick(mTick[ee]);
tob = newElement(Element.STAFF_TEXT);
tob.text = bowText.substring(mBow[ee],mBow[ee]+1);
tob.color = "#0000D0";
tob.placement = Placement.ABOVE;
tob.align = 8;
tob.fontFace = "FreeSans";
// tob.offsetX = 0.5;
tob.offsetY = -5;
tob.fontSize = 8;
tob.fontStyle = 0; // 0:Normal, 1:Bold
tob.autoplace = true;
cur.add(tob);
}
curScore.endCmd();
}
}
// =======================================================================================================================
function mapScore()
{
console.time("Process");
switch (inpMapType.currentIndex) {
case 0:
mapAll();
break;
case 1:
mapBow();
break;
case 2:
case 3:
mapTick();
break;
default:
tinfo = "Unknown processing option!";
}
tinfo = "";
console.timeEnd("Process");
}
// =======================================================================================================================
onRun: {}
width: 300;
height: 50;
RowLayout { id: uiRow1
x: 15; y:15
Label { id: lblRow2
Layout.preferredWidth: 50
color: "#000000"
text: "Process"
}
ComboBox {
id: inpMapType
model: ["Map all elements", "Map bowing elements", "Map bow @ tick", "Add bow text to score"]
Layout.leftMargin: 0
Layout.preferredWidth: 175
currentIndex: 0
}
Button { id: btnMapIt
Layout.leftMargin: 0
Layout.preferredWidth: 40
Layout.preferredHeight: 24
text: "Go"
onClicked: mapScore();
}
}
ApplicationWindow {
id: infoWin
x: 20; y: 50
width: 550; height: 900
title: "Score Map"
visible: false
TextArea {
id: popInfo
width: infoWin.width; height: infoWin.height
textMargin: 15
textFormat: TextEdit.RichText
readOnly: true
wrapMode: TextEdit.Wrap
text: "Processing..."
}
}
ApplicationWindow {
id: infoBow
x: 20; y: 50
width: 200; height: 900
title: "Bowing"
visible: false
TextArea {
id: popBow
width: infoBow.width; height: infoBow.height
textMargin: 15
textFormat: TextEdit.RichText
readOnly: true
wrapMode: TextEdit.Wrap
text: "Processing..."
}
}
}