Quantcast
Channel: MuseScore
Viewing all articles
Browse latest Browse all 74

Introducing the new QML based plugin framework

$
0
0

Before explaining the new plugin framework, let's define what problems we faced with the plugin subsystem in MuseScore 1.2.

One problem is the binding to the qt library. The code to enable this is very huge and consists of > 1100 files with > 297000 lines of code. This is not maintainable for the MuseScore team. It seems that qt does not maintain this anymore and it will not be available for the next major Qt version.

Another problem is that the MuseScore class hierarchy cannot be exposed easily to the current JavaScript engine. Every MuseScore class must be wrapped by a special proxy class. This also is a big maintenance issue and makes it difficult and expensive to make more elements of MuseScore available for scripting.

New QML based framework

After some hacking and testing i want to come up with a new solution: using the Qt qml system to make MuseScore scriptable.

Qml is a declarative language with the syntax of JavaScript which can contain java script parts which are executed on gui events. Without any further bindings Qml contains all to create modern dynamic guis.

The most important point is that the needed bindings to MuseScore internals are much easier. It is possible to expose the original class hierarchy of MuseScore to the scripting engine.

Caveats are that the new system has some overhead as all score elements now inherit from QObject and incorporate the Qt meta object system.

I hope the new system can offer the same functionality than the old plugin system so that porting of existing plugins is easy. Otherwise its a chance to think again on how the interface can be designed to implement simple things as easy as possible. One of the design goals should be that it should not be possible to crash MuseScore with scripting and it should be not possible to create corrupted scores.

The first version of the new plugin system is available for testing in the nightly builds.

//===============================================================
//      "colornotes" example in qml:
//===============================================================

import QtQuick 1.0
import MuseScore 1.0

MuseScore {
       menuPath: "Plugins.colornotes"

       onRun: {
             console.log("hello colornotes");

             var colors = [
                "#e21c48", "#f26622", "#f99d1c",
                "#ffcc33", "#fff32b", "#bcd85f",
                "#62bc47", "#009c95", "#0071bb",
                "#5e50a1", "#8d5ba6", "#cf3e96"
                ];

             if (typeof curScore === 'undefined')
                   return;
             var cursor = curScore.newCursor();
             for (var track = 0; track < curScore.ntracks; ++track) {
                   cursor.track = track;
                   cursor.rewind(0);  // set cursor to first chord/rest

                   while (cursor.segment) {
                         if (cursor.element && cursor.element.type == MScore.CHORD) {
                               var notes = cursor.element.notes;
                               for (var i = 0; i < notes.length; i++) {
                                     var note = notes[i];
                                     note.color = colors[note.pitch % 12];
                                     }
                               }
                         cursor.next();
                         }
                   }
             Qt.quit()
             }
       }

//========================================
// the "old" java script version:
//========================================

var colors = [new QColor(226,28,72),new QColor(242,102,34),new
QColor(249,157,28),
new QColor(255,204,51),new QColor(255,243,43),new QColor(188,216,95),
new QColor(98,188,71),new QColor(0,156,149),new QColor(0,113,187),
new QColor(94,80,161),new QColor(141,91,166),new QColor(207,62,150)];

function init()
       {
       }

function run()
       {
       if (typeof curScore === 'undefined')
             return;
       var cursor = new Cursor(curScore);
       for (var staff = 0; staff < curScore.staves; ++staff) {
             cursor.staff = staff;
             for (var v = 0; v < 4; v++) {
                   cursor.voice = v;
                   cursor.rewind();  // set cursor to first chord/rest

                   while (!cursor.eos()) {
                         if (cursor.isChord()) {
                               var chord = cursor.chord();
                               var n     = chord.notes;
                               for (var i = 0; i < n; i++) {
                                     var note   = chord.note(i);
                                     note.color = new QColor(colors[note.pitch % 12]);
                                     }
                               }
                         cursor.next();
                         }
                   }
             }
       }

var mscorePlugin = {
       menu: 'Plugins.Color Notes',
       init: init,
       run:  run
       };

mscorePlugin;
#----------------------------------------------

Viewing all articles
Browse latest Browse all 74

Trending Articles