MuseScore

Apr 27, 2015 09:05

Продолжаю копаться в механизме плагинов MuseScore 2.0, начало см. здесь.

Была задумка сделать плагин, который выравнивал бы гитарную аппликатуру. Например, при открытии в версии 2.0 файлов, созданных в версии 1.3, вся аппликатура жутко расползается. К сожалению, задача оказалась трудно выполнимой по ряду причин.

Во-первых, это трудно реализовать по чисто объективным причинам: когда ноты расположены тесно, или аппликатурных обозначений просто слишком много (например, аккорды "гроздьями", со знаками альтерации, для которых нужны обозначения левой и правой рук, да ещё и номера струн), расставить обозначения автоматически проблематично, т.к. их расположение выбирается каждый раз по-разному, в зависимости от ситуации.

Во-вторых, имеются проблемы в объектной модели MuseScore. Мне не удалось программно определить высоту штиля у ноты (соответствующих свойств и методов, насколько я понял, не предоставляется). Отсюда вытекает, что правильно установить (расположить) аппликатурное обозначение, например, над вязкой, никак не получится. Т.е. при установке расположения аппликатурного обозначения можно ориентироваться только на саму нотную головку.

Объектная модель даже не позволяет различить стили текста у аппликатурных обозначений. Таким образом, например, обозначения номеров струн и пальцев левой руки в коде плагина формально неразличимы. Их можно различить только по косвенным (ненадёжным) признакам, таким, как размер рамки "bbox", которая имеется у любого объекта (у обозначений номеров струн такая рамка несколько больше по размерам, чем у обозначений пальцев левой руки).

В результате плагин получился довольно бесполезным, выравнивает аппликатуру криво. Однако, код плагина демонстрирует работу с выделенной частью партитуры, перебор станов, голосов, аккордовых вертикалей и нот внутри них, а также форшлагов (последние являются подчинёнными аккордовыми вертикалями, точно так же состоящими из нот).

[Код плагина]

import QtQuick 2.0
import MuseScore 1.0

MuseScore {
version: "2.0"
description: qsTr("This plugin arranges guitar fingering.")
menuPath: "Plugins.Fingering"

onRun: {
var cursor = curScore.newCursor()
var endTick
var fullScore
var startStaff, endStaff
//================================================
cursor.rewind(1) // go to start of selection (if any)
if (!cursor.segment) { // no selection
fullScore = true
startStaff = 0
endStaff = curScore.nstaves - 1
} else {
fullScore = false
startStaff = cursor.staffIdx
cursor.rewind(2)
endStaff = cursor.staffIdx
if (cursor.tick == 0) {
endTick = curScore.lastSegment.tick + 1
} else {
endTick = cursor.tick
}
}
if (fullScore) {
cursor.rewind(0) // if no selection, beginning of score
} else {
cursor.rewind(1) // go to start of selection
}
//console.log(qsTr("startStaff ") + startStaff + qsTr(" endStaff ") + endStaff)
//================================================
//curScore.startCmd()
for (var staff = startStaff; staff <= endStaff; staff++) {
//console.log(qsTr("STAFF ") + staff)
for (var voice = 0; voice < 4; voice++) {
if (fullScore) {cursor.rewind(0)} else {cursor.rewind(1)}
cursor.voice = voice
cursor.staffIdx = staff
//console.log(qsTr("VOICE ") + cursor.voice)
while (cursor.segment && (fullScore || cursor.tick < endTick)) {
if (cursor.element && cursor.element.type == Element.CHORD) {
//console.log(qsTr("CHORD ") + cursor.segment)
for (var i = 0; i < cursor.element.notes.length; i++) {
processNote(cursor.element.notes[i])
}
var graceChords = cursor.element.graceNotes
for (var i = 0; i < graceChords.length; i++) {
var notes = graceChords[i].notes;
for (var j = 0; j < notes.length; j++) {
processNote(notes[j])
}
}
}
cursor.next()
}
}
}
curScore.endCmd()
Qt.quit()
}
//================================================
function processNote(note) {
//console.log(qsTr("NOTE ") + note + qsTr(" line ") + note.line)
for (var j = 0; j < note.elements.length; j++) {
var e = note.elements[j]
if (e.type == Element.FINGERING) {
//if (e.selected)
//console.log(qsTr(fingeringType(e)))
if (fingeringType(e) == "LH_GUITAR_FINGERING"){
//console.log(note.parent.notes.length)
if (note.parent.notes.length == 1){
e.pos.x = 1
e.pos.y = 1.5
} else {
e.pos.x = 2.5
e.pos.y = 0
}
}
if (fingeringType(e) == "RH_GUITAR_FINGERING"){
//console.log(note.parent.stem.pos.x)
//console.log(note.parent.stem.bbox.height)
if (note.parent.notes.length == 1){
if (note.parent.stem.pos.x < 1){ // stem down
e.pos.x = 0.7
e.pos.y = -1.7
} else { // stem up
e.pos.x = 1.2
e.pos.y = -5.7
}
} else {
e.pos.x = 4
e.pos.y = 0
}
}
if (fingeringType(e) == "STRING_NUMBER"){
if (note.parent.notes.length == 1){
if (note.parent.stem.pos.x < 1){ // stem down
e.pos.x = 0.2
e.pos.y = 6.5
} else { // stem up
e.pos.x = 0.8
e.pos.y = 3.5
}
} else {
// undefined, not clear
}
}
}
}
}
//================================================
function fingeringType(e){
//console.log(qsTr("FINGERING TEXT ") + e.text[e.text.length - 1])
if (e.text[e.text.length - 1] == "p" || e.text[e.text.length - 1] == "i" ||
e.text[e.text.length - 1] == "m" || e.text[e.text.length - 1] == "a" ||
e.text[e.text.length - 1] == "c"){
return "RH_GUITAR_FINGERING"
} else {
//console.log(qsTr("FINGERING ") + e + (qsTr(" bbox.width ") + e.bbox.width))
if (e.bbox.width > 2){
return "STRING_NUMBER"
} else {
return "LH_GUITAR_FINGERING"
}
}
}
//================================================
}


полезные ссылки, софт

Previous post Next post
Up