Plugins for 3.x
Not to be confused with Musescore 4's VST and VSTi feature
This chapter is for MuseScore 3 plugin developers. For other versions, visit Plugin development. To fork the main program, visit the main sections in Developers' handbook.
For info on what plugins are, how to install and use them, visit Musescore 3 handbook plugin section.
Introduction
This chapter aims to provide knowledge, code snippets and work-arounds for better understanding and programming of MuseScore plugin system. Anyone working on plugins are welcomed to document their learnings and experiences. To add your input, register a musescore.org account and login, click the ⠇ to the right of the title, choose Edit. For discussion about this chapter itself visit this forum thread.
The desktop program MuseScore is mostly written in C++ utilizing Qt framework 5.9.9, developers expose a minimal collection of frequently used functions and data as API to allow plugin development beyond MuseScore's built-in features.
Languages
Web devs might not need to learn QML (Windows only), use this boilerplate plus html, css and js code to create your plugin. demo plugin
Plugins use the QML language of Qt framework, which is a declarative language that provide visual user interfaces, along with the Qt JavaScript host environment it allows interaction programming with a restricted version of javascript
Plugin creation does not require C++ knowledge
- Learn basic javascript
- Learn what declarative language means (QML is declarative, QML functions use javascript)
- Understand briefly Qt, Qt UI and QML
Capability and limitation
Dev also often utilize the poorly documented non-API cmd().
- Examples of basic functionality (non-exclusive list):
- Change a note's property such as pitch, color
- Add or remove score elements such as notes, rests, symbol, text
- Read or save tags in File > Score Properties
- Play the audio of a score or part of score
- Create a new staff (Cannot change its name afterwards)
- Create/update text and symbols eg dynamics, lyrics etc
- Create/update tempo
- Change playback speed (cmd('playback-speed-increase'))
- Mute or change volume of an instrument
- Create/update MIDI Play Event
- Conversion of a different score format to and from MuseScore
- Send and receive score data through internet
- Opens a local or online webpage inside MuseScore
- Save or load a score or any file
- Start another program on your Windows/iOS outside MuseScore
- Seems unachievable ( Please share if you find workaround, for example a suitable cmd() command )
- Run plugin when audio is playing, or detect whether audio is playing, or realtime Playback Caret/cursor position.
- Directly changing the Playback Caret (Can read Editing Caret position)
- Change instrument name (Can read, but not write)
- Navigate into content, eg title text, inside a frame (user must select the text inside manually with a mouse click first) (Can get to the frame by cmd('prev-element'))
- Add spanners such as pedal marking to a score
- Create or update key signatures in a score
- Read clef info, see https://musescore.org/en/node/357788
- Send MIDI CC
- Mimic a click on a palette item
- Add plugin as a toolbar button
- Add plugin as an item in right click context menu
- Manipulation of MuseScore's window eg minimize
- Use a non build-into-Musescore text font, see workaround post (Can use with pre setup inside qml, see snippet)
- Expose the program with new hooks or API entry points, or create localhost server / services.
Alternatives to plugin
- run Musescore with Command line
- Edit a score file as plaintext:
- save as .mscz : rename as .zip, extract, edit, zip ; or
- save as .mscx and edit.
- AutoHotkey Kit for MuseScore.
- Get data of realtime midi output or exported .midi.
- Use a non build-into-Musescore font with this workaround post.
- Install Musescore 3.x Nightly and use the (experimental) scripting/macro function to record and replay sequence of commands "Tools → Script Recorder".
- Write a plugin outside the build-in QML plugin system.
Where to begin
MuseScore Plugin writing is not rocket science, you may be suprised how easily things are done. You do not need to install anything additional, just open Musescore:
- MuseScore > Plugins > click to run any plugin bundled with the MuseScore installation.
- MuseScore > Plugins > Plugin Creator open select any one .qml and view its codes
- Copy and paste and play with these boilerplates and snippets
Workflow and external editors
Try out Makeshift REPL plugin function tester plugin.
QML files are plaintext. You can use any external text editor, eg Sublime Text, Notepad++ etc, to edit a .qml file. After you modified and saved, you need to either:
- Load (and reload) it inside Plugin Creator then press Run, or
- Restart Musescore and run from the plugin menu.
NOTE: Script running from plugin menu has its version freezed at the moment of Musescore startup.
Hot reloading (auto build) and auto-complete are absent in Plugin Creator. The developers of Musescore 4 are aware of its flaws and plan to replace it in later releases. While waiting for upgrades, to edit in external editor and reload and test in Plugin Creator:
- Inside the Plugin Creator, open an existing .qml file
- In the external text editor, edit the .qml file and save
- Press refresh in the Plugin Creator
- Press run
The best options for auto complete (QML syntax only, not auto reference or API auto complete)
- use Qt Creator
- use KDE online QML editor
- use Notepad++ and the Qt user-defined language
Quickstart boilerplates, snippets and use cases
This section gathers reusable code snippets and boilerplates to help beginners get things done without a hassle. To alleviate QML frustration see QML boilerplates. Copy and paste to your plugin, tweak it to your liking. Also check out specific use cases and notes. Feel free to add your clever codes.
Learn more
- Read this overview
- Find any plugin similar to what you have in mind and study its souce code.
- Menu name, behavior, root functions etc of plugin see api doc Plugin API, check out cautions below
- for manipulation of score elements
- study the Musescore runtime internal score structure
- Read this reference in handbook
- Use the debugger by doing the following steps
-
- Install MuseScore Nightly
- Append -e in shortcut and start
- Edit > Debugger
- Try Object Explorer plugin which exhaustively print out element info, also see this well documented code
- Try Makeshift REPL plugin function tester plugin's "Diff an element" example.
- elements has properties inherited from the Element Class, only some properties are meaningful to and used by each specific type, there is no decent way to properly knowing which property is supported by which element except digging into the source code. The alternative is easier but tedious: try them out.
- For element type, see enumeration
- Most common way to get element data are
- curScore.newCursor() to create a Cursor, transverse and find. For more info, open and study walk.qml
- curScore.newCursor() to create a Cursor, sync with current mouse selection example
- select with mouse click then get curScore.selection.elements[ ]
- listen to state.selectionChanged, get curScore.selection example
- select with curScore.selection.selectRange() , get curScore.selection example
- for manipulation of time
- api doc Tick Length values
- Cursor and segment has .tick, snippet
- for manipulation of pitch
- see use case and snippets
- api doc Note Pitch values
- api doc Tonal Pitch Class
- study the Musescore runtime internal score structure
- for tagging a score or score part with custom data
- see this snippet
- for file saving and loading
- api writeScore, readScore
- custom data in MuseScore several methods see this snippet and notes
- study the Daily Log plugin
- FileIO for OS level op, usage see Object Explorer plugin
- for instrument / staff info eg instrument name, and channel audio status
- see this snippet
- see this note
- for create/update MIDI Play Event
- see API doc PlayEvent
- study the Arpeggiator plugin and the articulation and ornamentation control plugin
- for fetching webpage
- see this snippet
- study the updated online service version of ABC Import plugin
- the Harmony analysis tool plugin
- for starting another program, command line and parameters
- read community notes on API and add yours
- many more eg Time signature etc, QML notes, and html alternative and other visuals find inside Boilerplates and Snippets and Useful Resource below.
Useful Resource
Source code
MuseScore 3.6.2 Backend mainly under /libmscore
API 3.5 (for Musescore 3.6) under /mscore/plugin/api
* An online code search enabled clone of MuseScore 3.6.2 src (Online code search on the official repo always returns results based on current master src ie MuseScore 4 up-to-date version)
* An essential collection is also shown on the doxygen website.
Latest MuseScore 4 code:
MuseScore 4 Backend is rewritten and separated into two layers, under /src/engraving/libmscore and various /*/internal
API (3.5, not yet updated for MuseScore4, as of Nov2022) under /src/plugins/api
* Official src
Enumerations and element types
Also try log type enum string snippet and Makeshift REPL plugin function tester plugin for enum and keyword autocompletion.
Namespace/enum list
Base Class/Component
All elements has a .name
property to provide understandable info of its type.
To match and compare reliably, use .type
property. It is Enum, it uses a integer number internally. These enums can be referenced from various properties of the Base Class/Component
eg Accidental.FLAT
eg how-to Element.NOTE
find NOTE
under ElementType in the Namespace/enum list,
use Element
because Base Class/Component says Element Contains Ms::ElementType enumeration values.
Plugin API doxygen documentation
The Plugin API Documentation is automatically generated (in Doxygen format) whenever MuseScore developers build the main program. It is normal for beginners to be startled by its complexity.Use the search on the top right, instead of menu navigation.
Notes on API written by fellow musescore.org users, feel free to pitch in
List of all API object types
To build UI
1. Use the QML
Also see QML boilerplates
Note: doc.qt.io search sometimes returns an unexpected outdated page, eg QtQuick 1 Button instead of current QtQuick 2 Button.
Qt Quick Controls, the anchors and Qt Quick Layouts may suffice. Using Qt Widgets from QML may be overkill not worth your time.
List of all QML components for Qt 5.9
Customizing Qt Quick Controls 2 Please note that style are unsupported though.
Anchors enum
Keys enum list eg Qt.Key_Space
Mouse button enum list eg Qt.LeftButton, more on mouse see this notes
QtQuick Type properties for disabled, qmlssed, checked, checkable, focused, highlighted, flat, mirrored, hovered etc.
Settings{ } for persistence (save to OS, eg registry in windows)
Get the theme status with SystemPalette { }
Musescore.org users' notes on QML and snippets
and/or
2. Use a WebEngine plus html, css and javascript
Windows only, see QML notes
Use the two boilerplates, which utilize a hybrid view built with html, css and standard javascript thru a 100% width and height WebEngine.
Standard set of javascript is used, for tech compatibility check on caniuse.com (find Chrome v56), eg css display:grid is unsupported. This js set should not be confused with the other restricted set in QML functions, more info in Caution section
The following javascript inside WebEngine works:
- Arrow function
- template-literals ie `string${var}`
- DOMParser().parseFromString("html")
The following css works:
- Flex
The following css will not work:
- Gap
- Grid
Visit WebEngine community notes
Technical info on WebEngineView, WebChannel, WebView:
WebEngineView fetches url, search data on html and runs javascript from QML side only, its version in MuseScore 3 (Qt 5.9) is based on Chromium version 56.0.2924.122.
To communicate bidirectionally between QML and webpage use it with WebChannel.
WebView 1.1 is an older component and use a different engine which does not offer simple WebChannel support, try WebSocket.
Bundled resource
A list of every qrc:/// built-in musescore.qrc (src ref)
Icons, symbols and fonts (not soundfont) see this snippet
MuseScore dev team designs and uses its own two sets of styles, their details are not exposed as API yet, find them in github repo (then plz share link here).
import QML Module Versions
Musescore 3.6.2 use Qt 5.9.9, for latest version of common modules use:
import MuseScore 3.0
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.2
import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.0
import FileIO 3.0
import QtWebEngine 1.5 // web modules are Windows only
import QtWebChannel 1.0 // web modules are Windows only
The powerful non API method
Developers of MuseScore do not have resource to maintain and expose every function and data as API, some functionalities of Musescore the main program are yet to be available as plugin API.
Try out cmd() to run program sequence that you've seen in musescore and think may exist as coroutine. Actions that can be assigned to keyboard shortcuts are possible cmd(). These commands are poorly documented, and often cause prog crash (save your qml before Run). Study main C++ repo to understand more.
- calculuswhiz's handpicked list
- complete list
- complete list in CSV format
- A searchable MuseScore 3.6.2 github repo
- This command parser plugin makes them more scriptable
Caution
Don't reinvent the wheel
- Search plugins on musescore.org, someone may have already made one in Musescore 2 or Musescore 1(Change search filter to find them), remember you can always try to use an old version of MuseScore.
- Search plugins on github
- Study their source code, sometimes all you need to do is a few tweak.
- Seek help from the author via a comment under the repo or ask in the plugins forum.
- Try Element Analyser plugin which aims to provide a reusable library
API inheritance versus Score Structure
Beginners into programming may get confused with API Class Inheritance Hierarchy and Musescore runtime internal score structure hierarchy, read up on inheritance object oriented programming, also try out the debugger
Javascript issues
A different non-QML javascript API was used in MuseScore 1.x. While one can still learn a lot reading those files, they use the old API and will not work with current one. One way to spot the old API is presence of new Cursor(curScore)
. The current QML system use curScore.newCursor()
The QML functions use a restricted version of javascript, the following will not work:
- Arrow function
- Spread syntax
- Array.fill
To write modular codes, QML has import .js
Inside QML WebEngine, a different, standard version of javascript runs on outdated Chromium v56 engine, more info in UI section
Class/Object inheritance, composition and .prototype
You cannot edit class/object as you would with .prototype in javascript, see component creation if it suits your need.
Object.assign() (and spread function) also does not work, as opposed to stated on Qt webpage. This probably happens when Qt company add dynamically typed javascript scripting to the strong typed C++ based env. Instead create your own shallow copy with a for loop and then some spaghetti code.
QML list and javascript array
QML property declaration:
A list can only store QML objects:
Item { property list aList: [ ] aList2: [ ] //shorthand of above }
A list is an object: typeof list == 'object'
An array is a variant:
Item { property var anArray: [ ] }
_
inside QML functions:
same syntax as in standard javascript
Item { function a(){ var anArray=[ ] } }
UI Styles
Qt Quick Controls style eg import QtQuick.Controls.Material unsupported, see reasons
MuseScore dev team designs and uses its own two sets of styles, get the theme status with QML SystemPalette
, see source post. Their color and metric details are not exposed as API yet, find them in github repo (then plz share link here).
Above concerns UI component styles, not engraving style
The Plugin Base Component Musescore { }
- Component.onCompleted
Run once, right after the plugin component is created, before console.log() is functional - You should not use Qt.quit() in your plugins, see this post on why, and possible different approaches. Qt.quit() crashes Musescore 4.0 plugins.
- Set pluginType: "dock" for normal behavior eg stay on top; "dialog" is quite outdated.
- Create plugin as an action instead of a persistent object with prop and methods, because when the user close and reopen the plugin window, it may cause unwanted behavior.
- This post explains the nature of onRun() and Qt.quit(). The code Qt.quit() may not work the way you expect.
- The plugin window onClosing Event is not accessable from QML. The [Plugin API base] is in a QQuickView in a QWidget window docked inside a QDockWidget , see code.
- No way to detect plugin's open or closed.
- After plugin window is closed, listeners will continue to run, eg experimental onScoreStateChanged Handler
- Workaround palette-like plugin
- use Qt Labs Settings to save data across sessions
- other tips also check out the snippets and notes page
Placement of objects, cursor track and tick
cursor.rewindToTick(x) will only work correctly if there is a segment at x. Otherwise it will put the cursor at the next available segment (in the current track) after x, see https://musescore.org/en/node/345409#comment-1206211
Troubleshooting with help from community
If you are having difficulty, try
- Identify whether the problem is related to QML, or javascript, or the MuseScore plugin API. If it is QML or javascript, you can seek help from sites like stackoverflow and forum.qt.io in addition to musescore.org
-
Use google and the musescore.org forum search before posting new questions.
-
Ask politely in the plugins forum, provide a Minimal, Reproducible Example if possible, the community is usually more than happy to help.
- Enclose qml codes between
<qml>
and</qml>
to get better layout and to avoid musescore.org auto escaping eg to show & instead of&
- Come back and help others by adding your valuable discovery to this handbook.
Translation
see Internationalization
one solution to folder structure
Share your plugin
Plugin could be posted as a project on musescore.org without any github knowledge. Chat with other dev at the plugin forum.
Fill out the API compatibility 3.x or else your plugin with remain hidden to most users.
Licensing
Following is not written by a lawyer, consult a real one if you are concerned with licensing.
You do not need Qt licensing, as it does not affect QML scripts solely on the basis that they are written in the QML language per se, more info consult Qt dual licensing.
You do not need to follow MuseScore's GPL licensing as long as your plugin does not use MuseScore code base. MuseScore 3 use GPL which is copyleft, derivative work using MuseScore code base, once conveyed, must follow. This matter is debatable.
Credits
API 3.5 thanks to
dmitrio95,
and many others
Reference footnote
import API FileIO module version
import module version at Qt
import module version at wikipedia
import WebChannel module version