外観
譜表・記譜操作ガイド(MuseScore 4.6+)
二胡・篠笛などの 数字譜 や、五線を簡略化した記譜をプラグインで組み立てるときの実践ノウハウです。
実装を通じて確認した API と、うまくいった/いかなかった選択肢を対応ごとにまとめます。
関連: 開発ノウハウ / 独自フォント / API リファレンス
対象: MuseScore Studio 4.6+ のレガシー QML プラグイン(
import MuseScore 3.0)。
一部プロパティ(position、isFullMeasureRest、showInvisibleなど)は 4.6 以降で安定しています。API 名はできるだけ API リファレンス の該当節へリンクしています。
StaffTypeChangeの各プロパティ(staffLinesなど)は専用クラスではなく、EngravingItemのAPI_PROPERTYとして公開されています。
目次
- 数字譜化の全体像
- 譜線(横線)を消す
- 音部記号・拍子・調号を消す
- 先頭段のインデントをオフにする
- N 小節ごとに改行を入れる
- 小節幅をできるだけ揃える
- 音符・休符を指定テキストに置き換える
- テキスト位置の実測補正(2 パス)
- 符幹・旗・連桁を消す
- 高音・低音による縦スペースを潰す
- 元要素を「不可視」にせず消す
- StaffTypeChange の編集マーカー
- 音域外警告色(制限事項)
- 参考:処理の推奨順序
1. 数字譜化の全体像
数字譜では「Staff/Part の既定五線」をいじるより、先頭に StaffTypeChange(Element.STAFFTYPE_CHANGE)を置き、その位置以降の見た目だけを上書きする方が安全です。UI の「譜表の種類の変更」と同じ経路で、線数・記号生成・符幹などをまとめて切り替えられます。
譜表まわりの設定は、次を 同じ StaffTypeChange にまとめると安定します。
| やりたいこと | 主な手段 |
|---|---|
| 譜線を消す | staffLines = 0 |
| 音部/拍子/調号を出さない | staffGenClef / staffGenTimesig / staffGenKeysig = false |
| 符幹を出さない | staffStemless = true |
| 加線を出さない | staffShowLedgerlines = false |
| 先頭段インデント OFF | style.setValue("enableIndentationOnFirstSystem", false) |
| N 小節ごとに改行 | Element.LAYOUT_BREAK(LINE) |
| 小節幅を揃える | minMeasureWidth(スタイル) + Segment.leadingSpace |
| 音符を数字などに置換 | FINGERING / STAFF_TEXT + 位置補正 |
生成には newElement と Cursor.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.firstMeasure と Measure.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 段)
- 全小節の
userStretchを揃え、前回のleadingSpace補正をリセットする - スタイル
minMeasureWidth(MStyle.setValue)を「段の幅 ÷ 段内小節数」付近まで上げ、狭い小節を底上げする - 残差を各小節の末尾
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.FINGERING | Note.add(fingering) | Note の正式な子。STAFF_TEXT を Note に add しても表示されないことが多い |
| 休符 | Element.STAFF_TEXT | Cursor.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 align と position は別物
MuseScore 4.7 付近でテキストの「揃え」と「位置」が分離されています。
| プロパティ | 意味 | プロパティパネルの対応イメージ |
|---|---|---|
align | テキストボックス 内 の行揃え | 文字の左/中央/右 |
position(Pid::POSITION) | テキストボックスと 音符/休符 の横関係 | 「テキストボックスを音符/休符に横方向に中央揃え」 |
AlignH: LEFT=0 / RIGHT=1 / HCENTER=2AlignV: 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 + segDeltaSegment.tick は整数、Measure.tick は Fraction を返す点に注意します(measure.tick.ticks で単位を揃える)。臨時記号付き音符は右にずれるため、平均より 中央値が安定します。
8.3 autoplace
autoplace = true(既定)だと衝突回避で上下に押し出されます。精密配置では false にします。
9. 符幹・旗・連桁を消す
Note.visible = false や符頭の透明化だけでは 符幹は残ります。符幹・旗・連桁は Chord 側の別要素(stem / hook / stemSlash、ChordRest.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 = falseScore.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[音符・休符のテキスト置換と位置補正]- 譜表タイプ変更(線・記号・符幹・加線)
- 先頭段インデント OFF
- 改行
- 小節幅揃え(改行後の段構成で実測する)
- テキスト置換(
fixedLine・透明化・2 パス位置補正)
各ステップは startCmd / endCmd で囲み、レイアウト依存の読み取りは endCmd のあとに行います。
関連 API(抜粋)
| API | 参照 | 用途 |
|---|---|---|
Element.STAFFTYPE_CHANGE | StaffTypeChange | 譜表タイプ変更(見た目の局所上書き) |
staffLines / staffGenClef / staffGenTimesig / staffGenKeysig | StaffTypeChange | 線・記号生成 |
staffStemless / staffShowLedgerlines | StaffTypeChange | 符幹・加線 |
MStyle.setValue / value | 8.8 MStyle | スタイル(インデント、minMeasureWidth など) |
Element.LAYOUT_BREAK | Element 列挙 | 改行・改ページ |
Measure.userStretch | 7.2 Measure | 小節のストレッチ係数 |
Segment.leadingSpace | 7.1 Segment | セグメント前の余白 |
Note.fixed / fixedLine | 6.4 Note | 表示線の固定 |
Chord.noStem / stem / hook | 6.3 Chord | 符幹まわり |
ChordRest.beam / isFullMeasureRest | 6.2 ChordRest | 連桁・全休符判定 |
Element.FINGERING / STAFF_TEXT | Element 列挙 | 置換テキスト |
text / color / align / position / autoplace / offsetX / offsetY | 5.2 EngravingItem | テキスト・配置 |
pagePos / bbox / posY | 5.2 EngravingItem | レイアウト後の実測 |
Staff.lines / lineDistance / staffInvisible | 8.2 Staff | 五線情報 |
Score.startCmd / endCmd / showInvisible / showUnprintable | 2. Score | 編集コマンド・表示トグル |
Selection.clear | 4. Selection | 選択解除 |
詳細な型・版数は API リファレンス を参照してください。