Skip to content

譜表・記譜操作ガイド(MuseScore 4.6+)

二胡・篠笛などの 数字譜 や、五線を簡略化した記譜をプラグインで組み立てるときの実践ノウハウです。
実装を通じて確認した API と、うまくいった/いかなかった選択肢を対応ごとにまとめます。

関連: 開発ノウハウ独自フォントAPI リファレンス

対象: MuseScore Studio 4.6+ のレガシー QML プラグイン(import MuseScore 3.0)。
一部プロパティ(positionisFullMeasureRestshowInvisible など)は 4.6 以降で安定しています。

API 名はできるだけ API リファレンス の該当節へリンクしています。StaffTypeChange の各プロパティ(staffLines など)は専用クラスではなく、EngravingItemAPI_PROPERTY として公開されています。


目次

  1. 数字譜化の全体像
  2. 譜線(横線)を消す
  3. 音部記号・拍子・調号を消す
  4. 先頭段のインデントをオフにする
  5. N 小節ごとに改行を入れる
  6. 小節幅をできるだけ揃える
  7. 音符・休符を指定テキストに置き換える
  8. テキスト位置の実測補正(2 パス)
  9. 符幹・旗・連桁を消す
  10. 高音・低音による縦スペースを潰す
  11. 元要素を「不可視」にせず消す
  12. StaffTypeChange の編集マーカー
  13. 音域外警告色(制限事項)
  14. 参考:処理の推奨順序

1. 数字譜化の全体像

数字譜では「Staff/Part の既定五線」をいじるより、先頭に StaffTypeChangeElement.STAFFTYPE_CHANGE)を置き、その位置以降の見た目だけを上書きする方が安全です。UI の「譜表の種類の変更」と同じ経路で、線数・記号生成・符幹などをまとめて切り替えられます。

譜表まわりの設定は、次を 同じ StaffTypeChange にまとめると安定します。

やりたいこと主な手段
譜線を消すstaffLines = 0
音部/拍子/調号を出さないstaffGenClef / staffGenTimesig / staffGenKeysig = false
符幹を出さないstaffStemless = true
加線を出さないstaffShowLedgerlines = false
先頭段インデント OFFstyle.setValue("enableIndentationOnFirstSystem", false)
N 小節ごとに改行Element.LAYOUT_BREAKLINE
小節幅を揃えるminMeasureWidthスタイル) + Segment.leadingSpace
音符を数字などに置換FINGERING / STAFF_TEXT + 位置補正

生成には newElementCursor.add、変更の囲みには Score.startCmd / endCmd を使います。

qml
curScore.startCmd()
var stc = newElement(Element.STAFFTYPE_CHANGE)
cursor.add(stc)
stc.staffLines = 0
stc.staffGenClef = false
stc.staffGenTimesig = false
stc.staffGenKeysig = false
stc.staffStemless = true
stc.staffShowLedgerlines = false
curScore.endCmd()

StaffTypeChange は小節上に 四角い編集マーカーを出します(§12)。


2. 譜線(横線)を消す

2.1 結論:StaffTypeChange.staffLines = 0 が最適

方法結果備考
Staff.staffInvisible = trueほぼ効かないAPI 上 RW でも、プラグインからの直接書き込みでは見た目が変わらないことがある
StaffTypeChange.staffInvisible = true譜線は消える「不可視を表示」オンだと灰色で残る
五線色(Staff.color)を透明にする消える他要素の色と混同しやすい
StaffTypeChange.staffLines = 0消える線数 0。表示オプションに依存しにくい。数字譜向き

数字譜では「線を隠す」より 線を持たない譜表にする方が意図に合います。

qml
var stc = newElement(Element.STAFFTYPE_CHANGE)
cursor.add(stc)
stc.staffLines = 0

線数や線間隔の読み取りには Staff.lines(f) / Staff.lineDistance(f) が使えます(§8.1)。

2.2 注意

  • StaffTypeChange はカーソル位置以降に効く。スコア先頭で入れるのが基本。
  • 既存の StaffTypeChange がある場合は上書き・重複に注意する。

3. 音部記号・拍子・調号を消す

同じ StaffTypeChange で生成フラグを落とします。

qml
stc.staffGenClef = false
stc.staffGenTimesig = false
stc.staffGenKeysig = false
対象プロパティ
音部記号staffGenClef
拍子記号(4/4 の C 含む)staffGenTimesig
調号staffGenKeysig

既に配置済みの記号は自動では消えないことがあります。新規レイアウトや記号削除と組み合わせてください。


4. 先頭段のインデントをオフにする

スタイル設定(MStyleです。五線ごとではなく スコア全体に効きます。

qml
curScore.startCmd()
curScore.style.setValue("enableIndentationOnFirstSystem", false)
curScore.endCmd()

読み戻し例:

qml
var v = curScore.style.value("enableIndentationOnFirstSystem")

5. N 小節ごとに改行を入れる

Element.LAYOUT_BREAK を小節に追加します。layoutBreakType は環境により列挙の名前が違うため、フォールバックを用意します。小節の走査には Score.firstMeasureMeasure.nextMeasure、既存要素の確認には Measure.elements を使います。

qml
function layoutBreakLineValue() {
    try {
        if (typeof LayoutBreak !== "undefined" && LayoutBreak.LINE !== undefined)
            return LayoutBreak.LINE
    } catch (e1) {}
    try {
        if (typeof LayoutBreakType !== "undefined" && LayoutBreakType.LINE !== undefined)
            return LayoutBreakType.LINE
    } catch (e2) {}
    return 0 // LINE
}

function breakEveryN(n) {
    n = n || 4
    var lineType = layoutBreakLineValue()
    curScore.startCmd()
    var m = curScore.firstMeasure
    var count = 0
    while (m) {
        count++
        // 既存の LAYOUT_BREAK を除去してから入れ直す
        var els = m.elements
        if (els) {
            for (var i = els.length - 1; i >= 0; i--) {
                if (els[i] && els[i].type === Element.LAYOUT_BREAK)
                    removeElement(els[i])
            }
        }
        if ((count % n) === 0 && m.nextMeasure) {
            var lb = newElement(Element.LAYOUT_BREAK)
            lb.layoutBreakType = lineType
            m.add(lb)
        }
        m = m.nextMeasure
    }
    curScore.endCmd()
}

改行マーカー(ピンクの記号)は印刷されない編集用表示です。Score.showUnprintable を落とすと改行位置も消えるため、表示設定をプラグインから書き換えない方が安全です。


6. 小節幅をできるだけ揃える

6.1 なぜ揃いにくいか

MuseScore は各小節の必要幅を計算し、余白を 音符密度に比例して配分します。
全休符だけの小節は必要幅が小さく、同じ Measure.userStretch でも狭く見えます。

measure.userStretch = 1.0 だけでは 実幅は一致しません

6.2 実用的な寄せ方(3 段)

  1. 全小節の userStretch を揃え、前回の leadingSpace 補正をリセットする
  2. スタイル minMeasureWidthMStyle.setValue)を「段の幅 ÷ 段内小節数」付近まで上げ、狭い小節を底上げする
  3. 残差を各小節の末尾 Segment.leadingSpace で数回フィードバック補正する

段の判定には EngravingItem.pagePos、幅の実測には EngravingItem.bbox を使います。

qml
// 段の切れ目: pagePos.y が変わる/x が戻る
function collectSystems() {
    var systems = []
    var current = null
    var prev = null
    var m = curScore.firstMeasure
    while (m) {
        var pos = m.pagePos
        if (!prev || Math.abs(pos.y - prev.y) > 0.01 || pos.x < prev.x - 0.01) {
            current = []
            systems.push(current)
        }
        current.push(m)
        prev = pos
        m = m.nextMeasure
    }
    return systems
}

// 目標幅の例(段スパン ÷ 小節数)
var systems = collectSystems()
var perSystem = systems[0].length
var first = systems[0][0]
var last = systems[0][perSystem - 1]
var target = (last.pagePos.x + last.bbox.width - first.pagePos.x) / perSystem

curScore.startCmd()
curScore.style.setValue("minMeasureWidth", target * 0.98)
curScore.endCmd()

// 残差補正(末尾セグメント前の余白)
curScore.startCmd()
for (var k = 0; k < systems[0].length; k++) {
    var mm = systems[0][k]
    var goal = target
    var seg = mm.lastSegment
    if (!seg)
        continue
    var delta = goal - mm.bbox.width
    seg.leadingSpace = Math.max(0, Number(seg.leadingSpace) + delta)
}
curScore.endCmd()

6.3 限界

  • 音符が多くて目標幅を超える小節は 縮められない
  • 最終段は幅いっぱいに引き伸ばされないため、統計から外すと評価しやすい
  • minMeasureWidth の既定はおおむね 8sp。元に戻すときはその値へ

7. 音符・休符を指定テキストに置き換える

7.1 要素の選び方

対象使う要素追加方法理由
音符Element.FINGERINGNote.add(fingering)Note の正式な子。STAFF_TEXT を Note に add しても表示されないことが多い
休符Element.STAFF_TEXTCursor.add(restText)Rest の子にはできない。時間位置へ注釈として置く

テキスト内容(EngravingItem.text)は次のいずれかで指定できます。

形式
直接文字"1"
Unicode"\u266F"
SMuFL 参照"<sym>noteheadBlack</sym>"(記譜フォント依存)

配置系(align / position / autoplace / color)は内部 Pid 経由の要素プロパティです。

qml
function configureReplacementText(text, label, fontFace) {
    text.text = label
    if (fontFace)
        text.fontFace = fontFace
    text.fontSize = 14
    text.autoplace = false
    // align: 文字自身 / position: テキストボックスと音符・休符の関係(4.6+)
    text.align = 2 | 8          // HCENTER | VCENTER
    text.position = 2           // HCENTER(「音符/休符に横方向中央揃え」)
    text.color = Qt.rgba(0, 0, 0, 1)
}

7.2 alignposition は別物

MuseScore 4.7 付近でテキストの「揃え」と「位置」が分離されています。

プロパティ意味プロパティパネルの対応イメージ
alignテキストボックス の行揃え文字の左/中央/右
positionPid::POSITIONテキストボックスと 音符/休符 の横関係「テキストボックスを音符/休符に横方向に中央揃え」

AlignH: LEFT=0 / RIGHT=1 / HCENTER=2
AlignV: TOP=0 / BOTTOM=4 / VCENTER=8(ビット OR)


8. テキスト位置の実測補正(2 パス)

EngravingItem.pagePos / bbox はレイアウト確定後に初めて正しい値になります。
startCmd → 要素追加 → endCmd のあと、再度 startCmd して offsetX / offsetY を直します。

8.1 縦:五線中央へ

線数・線間隔は Staff.lines(f) / Staff.lineDistance(f)、要素の親相対位置は EngravingItem.posY で取得します。

qml
function staffCenterOffset(staff, tickFraction) {
    var lines = staff.lines(tickFraction)
    var dist = staff.lineDistance(tickFraction)
    if (!(lines > 1))
        return 0
    return (lines - 1) * dist / 2
}

// pagePos は五線を考慮、posY は親相対 → 差が五線原点
var staffTopY = anchor.pagePos.y - anchor.posY
var targetY = staffTopY + staffCenterOffset(staff, measure.tick)
var currentCenterY = item.pagePos.y + item.bbox.y + item.bbox.height / 2
item.offsetY = item.offsetY + (targetY - currentCenterY)

8.2 横:休符を音符の見た目に合わせる

  • 通常の休符: 親 Segment のページ X を基準にする
  • 全休符ChordRest.isFullMeasureRest): セグメントが小節線際に寄り、休符記号だけ中央へ描かれる → 小節左端基準にする

音符テキストの「基準からの距離」を中央値で取り、休符へ適用します。

qml
function segmentPageX(chordRest) {
    var seg = chordRest.parent
    return (seg && seg.pagePos) ? seg.pagePos.x : null
}

// Segment.tick は int、Measure.tick は Fraction
function isAtMeasureStart(chordRest, measure) {
    var seg = chordRest.parent
    return seg && measure && seg.tick === measure.tick.ticks
}

// 全休符: measure.pagePos.x + measureDelta
// 通常休符: segmentPageX + segDelta

Segment.tick は整数、Measure.tickFraction を返す点に注意します(measure.tick.ticks で単位を揃える)。臨時記号付き音符は右にずれるため、平均より 中央値が安定します。

8.3 autoplace

autoplace = true(既定)だと衝突回避で上下に押し出されます。精密配置では false にします。


9. 符幹・旗・連桁を消す

Note.visible = false や符頭の透明化だけでは 符幹は残ります。符幹・旗・連桁は Chord 側の別要素(stem / hook / stemSlashChordRest.beam)です。

qml
function hideChordStems(chord) {
    try { chord.noStem = true } catch (e) {}
    var parts = [chord.stem, chord.hook, chord.stemSlash, chord.beam]
    for (var i = 0; i < parts.length; i++) {
        if (parts[i])
            makeTransparent(parts[i]) // または visible=false
    }
}
手段効果
chord.noStem = true符幹・旗・連桁をレイアウトから省く(余白も残りにくい)
stem / hook / beam を個別に消す念のための二重防御
StaffTypeChange.staffStemless = true譜表全体を符幹なしにする(§1 の一括設定向き)

10. 高音・低音による縦スペースを潰す

10.1 問題

visible = false や透明色にしても、符頭の レイアウト上の位置は音高のままです。
加線やスキャイラインに縦スペースが残ります。

10.2 対処:fixed / fixedLine

Note.fixed / Note.fixedLine は表示線だけを固定し、音高・再生は変えません(打楽器の 1 線譜などで使う仕組み)。

qml
note.fixed = true
note.fixedLine = 0   // 0 = 最上線相当。全音符を同じ線に集約

あわせて:

qml
stc.staffShowLedgerlines = false

臨時記号(Note.accidental)・付点(Note.dots)は符頭とは別要素なので、個別に透明化/不可視化します。

qml
if (note.accidental)
    makeTransparent(note.accidental)
var dots = note.dots
for (var i = 0; dots && i < dots.length; i++)
    makeTransparent(dots[i])

11. 元要素を「不可視」にせず消す

11.1 visible = false の欠点

  • 「不可視を表示」オンだと灰色で見える
  • ユーザーに表示オプション操作を強いることになる

11.2 推奨:表示状態のまま透明色

EngravingItem.visible は残したまま、EngravingItem.color を透明にします。

qml
function makeTransparent(item) {
    if (!item)
        return
    try { item.visible = true } catch (e1) {}
    try { item.color = Qt.rgba(0, 0, 0, 0) } catch (e2) {}
}
  • 「不可視を表示」のオン/オフに左右されない
  • 画面・印刷とも通常は描画されない
  • 音高・音価・再生は残る
  • 要素自体はスコアに残るため、選択対象にはなり得る

置換テキストには明示的に不透明色を付け、親の透明色の影響を防ぎます。

qml
text.color = Qt.rgba(0, 0, 0, 1)

11.3 やってはいけないこと(改行を消したくない場合)

qml
// 改行マーカー(LAYOUT_BREAK)まで消える
curScore.showUnprintable = false

// ユーザーの「不可視を表示」をプラグインが勝手に変える
curScore.showInvisible = false

Score.showUnprintable / showInvisible といった表示トグルはプラグインから書き換えない方が、改行位置や他の編集マーカーを保てます。


12. StaffTypeChange の編集マーカー

数字譜化のために先頭へ Element.STAFFTYPE_CHANGE を入れると、1 小節目に 四角に中点の記号が出ます。

項目内容
正体StaffTypeChange の編集用アイコン
ステータスバー例「譜表の種類の変更」
印刷通常は印刷されない
透明色効くこともあるが、書式マーカーとして残ることがある

選択直後は青くハイライトされるため、処理後に Selection.clear で選択解除すると落ち着きます。

qml
try { curScore.selection.clear() } catch (e) {}

13. 音域外警告色(制限事項)

楽器の演奏可能音域外の音符は、MuseScore が描画時に 赤/黄緑などで色を上書きします。

試したこと結果
Note.color を透明警告色が優先され、赤い符頭が残る
Chord.mag = 0符頭倍率には実質効かず、消えない
visible = false + showInvisible = false消えるが、表示設定操作・改行マーカーへの副作用がある

プラグイン公開 API だけでは、警告色をユーザー設定なしに確実に消す手段は無い、と考えてよいです。
数字譜用途では警告色の残存を受け入れるか、手動で環境設定の「演奏可能音域外の音符に色を付ける」をオフにする選択になります。


14. 参考:処理の推奨順序

改行位置や目標小節幅は後工程に影響するため、だいたい次の順が扱いやすいです。

mermaid
flowchart TD
    A[StaffTypeChange(線・記号・符幹・加線)] --> B[先頭段インデント OFF]
    B --> C[N 小節ごとに改行]
    C --> D[小節幅揃え]
    D --> E[音符・休符のテキスト置換と位置補正]
  1. 譜表タイプ変更(線・記号・符幹・加線)
  2. 先頭段インデント OFF
  3. 改行
  4. 小節幅揃え(改行後の段構成で実測する)
  5. テキスト置換(fixedLine・透明化・2 パス位置補正)

各ステップは startCmd / endCmd で囲み、レイアウト依存の読み取りは endCmd のあとに行います。


関連 API(抜粋)

API参照用途
Element.STAFFTYPE_CHANGEStaffTypeChange譜表タイプ変更(見た目の局所上書き)
staffLines / staffGenClef / staffGenTimesig / staffGenKeysigStaffTypeChange線・記号生成
staffStemless / staffShowLedgerlinesStaffTypeChange符幹・加線
MStyle.setValue / value8.8 MStyleスタイル(インデント、minMeasureWidth など)
Element.LAYOUT_BREAKElement 列挙改行・改ページ
Measure.userStretch7.2 Measure小節のストレッチ係数
Segment.leadingSpace7.1 Segmentセグメント前の余白
Note.fixed / fixedLine6.4 Note表示線の固定
Chord.noStem / stem / hook6.3 Chord符幹まわり
ChordRest.beam / isFullMeasureRest6.2 ChordRest連桁・全休符判定
Element.FINGERING / STAFF_TEXTElement 列挙置換テキスト
text / color / align / position / autoplace / offsetX / offsetY5.2 EngravingItemテキスト・配置
pagePos / bbox / posY5.2 EngravingItemレイアウト後の実測
Staff.lines / lineDistance / staffInvisible8.2 Staff五線情報
Score.startCmd / endCmd / showInvisible / showUnprintable2. Score編集コマンド・表示トグル
Selection.clear4. Selection選択解除

詳細な型・版数は API リファレンス を参照してください。