Help us understand the problem. What is going on with this article?

MuseScore でプラグインを書く [Hello World編]

なにこれ

唐突に MuseScore のプラグインを作りたくなったので、並行してメモを取っておくぐらいの気持ちで書いたエントリです。課題ヤバい。

開発環境

どうやって実装するんじゃろ

Ctrl + Shift + P (⇧⌘P) でプラグイン作成画面に入りファイルを新規作成すると、勝手にコードが生成されます。

import QtQuick 2.0
import MuseScore 1.0

MuseScore {
    menuPath: "Plugins.pluginName"
    description: "Description goes here"
    version: "1.0"
    onRun: {
        console.log("hello world")
        Qt.quit()
        }
    }

MuseScore のプラグインは QML で書かれます。
MuseScore { ... }MuseScore 型のオブジェクトを宣言して、onRun: がエントリポイントというところでしょうか。よくわからん。

このコードはコンソールに hello world と出力するみたいですが、これをウィンドウに出すようにしてみましょう。

HelloWorld
import QtQuick 2.4
import QtQuick.Controls 1.3
import MuseScore 1.0

MuseScore {
    menuPath: "Plugins.HelloWorld"
    description: "returns 'Hello, world!'"
    version: "1.0.0"
    pluginType: "dialog"

    width: 400
    height: 200

    Label {
        id: textLabel
        wrapMode: Text.WordWrap
        text: "Hello, world!"
        color: "white"
        font.pointSize: 20
        anchors.centerIn: parent
        }

    MouseArea {
        anchors.fill: parent
        onClicked: Qt.quit()
        }
    }

ダイアログを呼び出す場合は pluginType: "dialog" と記述するといいみたいです。このとき onRun: { ... } は書かなくていいっぽい。
parent で親要素を呼び出せる辺り便利ですね。

つくってみる

このまま UI 方面ばかり連ねていると Qt Quick の記事になりかねないので、そろそろ MuseScore API をいじってみましょう。

選択した音符に譜表テキストで Hello, world! を付着させるコードを書いてみます。

HelloWorldOnNotes
import QtQuick 2.4
import MuseScore 1.0

MuseScore {
    menuPath: "Plugins.HelloWorldOnNotes"
    description: "Places 'Hello, world!' on selected notes"
    version: "1.0.0"
    onRun: {
        const cursor = curScore.newCursor()
        const text = newElement(Element.STAFF_TEXT)
        text.text = "Hello, world!"
        cursor.rewind(1)
        cursor.add(text)
        Qt.quit()
        }
    }

cursor は選択中の範囲といったところでしょうか。よくわからん。
newElement(Element.STAFF_TEXT) で譜表テキストが作成でき、.text で名前を指定することができます。

cursor.rewind(value) で値を指定すると、選択範囲の中で位置を指定することができます。

位置
0 楽譜の最初
1 選択範囲の最初
2 選択範囲の最後

そして、その指定した位置にテキストを追加します。

実行してみる

音符を Shift を押しながら選択すると、その音全体が選択された状態になります。

画像には写っていませんが、実際には周りに青い枠が表示されています。この状態で実行すると、

できた。

もうちょっと何とかしよう

勿論、このコードだと複数の音符に対応しているはずがなく、それを実現させるべくコードを改良します。

HelloWorldOnNotes
import QtQuick 2.4
import MuseScore 1.0

MuseScore {
    menuPath: "Plugins.HelloWorldOnNotes"
    description: "Places 'Hello, world!' on notes"
    version: "1.0.1"

    onRun: {
        const cursor = curScore.newCursor()
        cursor.rewind(2)
        const endTick = cursor.tick
        cursor.rewind(1)

        while (cursor.segment && cursor.tick < endTick) {
            if (cursor.element && cursor.element.type == Element.CHORD) {
                const text = newElement(Element.STAFF_TEXT)
                text.text = "Hello, world!"
                cursor.add(text)
                }
            cursor.next()
            }
        Qt.quit()
        }
    }

おっと、tick なるものが出てきましたね。これは音符の位置を示す値のようなもので、楽譜の最初の音符が 0、その後音価に従って増えていきます。

ピアノロールエディタをいじってる方なら、少し馴染みのある数字かもしれません。

このコードでは、選択範囲の最後に位置指定してから tick を取得しているので、endTick には範囲のうち一番最後の音符のものが入ります。
また、cursor.next() で指定位置を次の音符に移動できます。

しかーし

他声部に対応してない。

HelloWorldOnNotes
import QtQuick 2.4
import MuseScore 1.0

MuseScore {
    menuPath: "Plugins.HelloWorldOnNotes"
    description: "Places 'Hello, world!' on notes"
    version: "1.0.2"

    onRun: {
        const cursor = curScore.newCursor()
        cursor.rewind(2)
        const endTick = cursor.tick

        for (var voice = 0; voice < 4; voice++) {
            cursor.rewind(1)
            cursor.voice = voice

            while (cursor.segment && cursor.tick < endTick) {
                if (cursor.element && cursor.element.type == Element.CHORD) {
                    const text = newElement(Element.STAFF_TEXT)
                    text.text = "Hello, world!"
                    cursor.add(text)
                    }
                cursor.next()
                }
            }
        Qt.quit()
        }
    }

for 回せば良いわ。

まだ続くんかワレェ!

複数段に対応してなかった。

HelloWorldOnNotes
import QtQuick 2.4
import MuseScore 1.0

MuseScore {
    menuPath: "Plugins.HelloWorldOnNotes"
    description: "Places 'Hello, world!' on notes"
    version: "1.0.3"

    onRun: {
        const cursor = curScore.newCursor()
        cursor.rewind(1)
        const startStaff = cursor.staffIdx
        cursor.rewind(2)
        const endStaff = cursor.staffIdx
        const endTick = cursor.tick

        for (var staff = startStaff; staff <= endStaff; staff++) {
            for (var voice = 0; voice < 4; voice++) {
                cursor.rewind(1)
                cursor.voice = voice
                cursor.staffIdx = staff

                while (cursor.segment && cursor.tick < endTick) {
                    if (cursor.element && cursor.element.type == Element.CHORD) {
                        const text = newElement(Element.STAFF_TEXT)
                        text.text = "Hello, world!"
                        cursor.add(text)
                        }
                    cursor.next()
                    }
                }
            }
        Qt.quit()
        }
    }

あとがき

どうでもいいけどこの Ratliff style 抵抗ある(MuseScore 開発陣特有の記法っぽい)。

Opus
15歳学生。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした