Is it possible to move the lines on a staff with a plugin?

• Sep 6, 2022 - 16:46

Is it possible to move the lines on a staff to different positions up and down?

For example to get something that looks like this:

lilypond-line-positions

Which can be done in Lilypond with commands like

\override Staff.StaffSymbol.line-positions = #'(1 3 5 -1 -3)

As shown in the Lilypond Documentation.

Is it possible to modify the staff line positions in that way with a MuseScore Plugin?

I've looked at documentation for Staff, Part, and Instrument. Those contain fields about staff color, tab notation, and drum notation, but I couldn't find anything about the line positions.

My goal is to make a modified staff notation for Guitar with open strings on lines, to look something like this:

Happy Birthday modified Sheet Music notation: Guitar Open Lines

Is it possible?


Comments

Looking at this previous forum post by robertmengual: Create new custom music notation, this might be just barely possible, but I'm not sure.

Based on the replies by jeetee and illionas, my best hope so far seems to be "not displaying the staff lines" and "adding 'TextLine's manually and moving them to the correct vertical location", and one of the limitations is that it is "not possible ... to make the middle staff line disappear".

Luckily in the Guitar Open Lines notation I'm trying to make, the middle staff line is still there. The middle line in a standard guitar treble-clef-down-an-octave staff is a B, luckily one of the open strings on a Guitar in standard tuning is that B.

However I still have questions:

(1) How do I make all the lines except for the middle line and the line below that disappear? On a treble clef I would like to keep both the G and B lines as they are if possible.

(2) Do the 'TextLine's need to be added manually... like by hand to visually match the correct vertical location, or can a plugin tell it where to go based on steps, such as steps above/below that middle staff line?

(3) Would custom ledger-line positions also need to be 'TextLine's, and would those need to be added manually as well?

(4) For possible automation of this in a plugin, would it need to be aware of system breaks, and need to re-traverse the score every time the system breaks change? How should that work, or is it possible to avoid that?

In reply to by AlexKnauth

I'll start by re-iterating what I said over in the other topic as well: Plugins can't do a lot more that what you can do manually inside of MuseScore.

So the short answer is: No, you can't really achieve this without a big amount of manual effort.

(1) You can reduce the number of staff lines for a staff in the Staff/Part-properties, but you can't say which lines are used. MuseScore will always keep the top ones.

(2) Plugins can't add Lines in a decent manner.

(3) Custom ledger-lines aren't a thing in MuseScore; so yes, you'd need to fake this somehow as well

(4) It probably wouldn't have to be aware of system breaks; but see above for all of the other things a Plugin can't achieve.

In reply to by jeetee

I tried adding the lines manually and got some promising initial results:

One line

However, adding a system break broke the manual formatting I put on it:

Two lines

Is there something I need to do to make it keep its position (relative to the staff) after a system break?

In reply to by AlexKnauth

You might be able to program this in a plugout, working with the .mscx file. Everything is accessible to a plugout so the vertical position of notes could be changed. Can you overlay a standard stave on top of a 6 string TAB stave to get the 6 lines? This would stop system breaks from messing up the layout and all the fret numbers could be made invisible.

In reply to by AlexKnauth

You could preserve these note intervals but space the lines at equal distances, (as TAB does), and just never use the 4th fret position on the G string.

As you know, the strings on a guitar are spaced at equal distances so your stave may look even better, (or this may be deemed worse since the vertical spacing would no longer match the interval visually!)

In reply to by yonah_ag

Ideally I would want it to be responsive to changes in staff size, in units of "sp" and not pixels. 'TextLine's seem to allow me to do that (within a single system without system breaks), a transparent graphic of horizontal lines... I don't know how I would make that work the same way

In reply to by yonah_ag

I'm not sure what you mean?

It's what you get with these 2 lines of code in LilyPond:

\override Staff.StaffSymbol.line-positions = #'(-11 -8 -5 -2 0 3)
\override Staff.StaffSymbol.ledger-positions = #'(-9 -6 -3 2 5 7 9)

And it looks like the image I put in the original post above.

If you want me to describe it a bit more precisely without relying on the LilyPond code:
- the staff has 6 lines from bottom to top: E2, A2, D3, G3, B3, E4
- ledger lines can appear in between staff lines, and they alternate from the line below if there is one.

I have more scores that I've put through the conversion of MuseScore -> MusicXml -> LilyPond -> adding those 2 lines of code -> PDF, and I have a makefile setup to do some of it automatically if you'd like to see it applied to more examples.

The code I'm trying to write crashes MuseScore if I try to add the TEXTLINE elements to the score with a cursor. Specifically if I uncomment the // cursor.add(sl) in the code below, it crashes. I'm obviously doing something wrong... what do I need to do to add the TextLines properly here?

import QtQuick 2.0
import MuseScore 3.0

MuseScore {
  menuPath: "Plugins.guitarOpenLines"
  description: "Guitar staff notation with Open string on Lines"
  version: "1.0"

  function scoreGuitarOpenLines(sc) {
    console.log("hello Score")
    for (var i_pa = 0; i_pa < sc.parts.length; i_pa++) {
      var pa = sc.parts[i_pa]
      if (pa.shortName == "Guit." && pa.hasPitchedStaff) {
        partGuitarOpenLines(sc, pa)
      }
    }
  }

  function partGuitarOpenLines(sc, pa) {
    console.log("hello Part")
    var startStaff = pa.startTrack / 4
    var endStaff = pa.endTrack / 4
    sc.startCmd()
    sc.selection.clear()
    sc.selection.selectRange(0, sc.lastSegment.tick + 1, startStaff, endStaff + 1);
    sc.endCmd()
    var cursor = curScore.newCursor();
    cursor.voice = 0
    cursor.rewind(Cursor.SELECTION_START)
    cursor.staffIdx = startStaff
    createStaffLines(sc, cursor)
  }

  function createStaffLines(sc, cursor) {
    // relevant style keys: staffLineWidth, ledgerLineWidth, ledgerLineLength
    console.log("hello createStaffLines")
    var offsetYs = [0.5, 2, 3, 0.5, 2, 3.5]
    var placements = [0, 0, 0, 1, 1, 1]
    for (var i = 0; i < 6; i++) {
      var sl = newElement(Element.TEXTLINE)
      sl.offsetX = -8
      sl.offsetY = offsetYs[i]
      sl.lineWidth = sc.style.value("staffLineWidth")
      sl.placement = placements[i]
      // cursor.add(sl)
    }
  }

  onRun: {
    console.log("hello world")
    scoreGuitarOpenLines(curScore)
    Qt.quit()
  }
}

The goal for now is to add 6 TextLine elements, 3 of them at positions 0.5sp, 2sp, and 3sp relative to the top of the staff, and 3 more at positions 0.5sp, 2sp, and 3.5sp relative to the bottom of the staff.

I'm also hoping that if I add them with a plugin, the TextLine Segments created after system breaks will also keep those positions just as they were before the system break.

Since MuseScore crashes when I run this with the // cursor.add(sl) line uncommented, I don't know how to recover any useful error message.

In reply to by AlexKnauth

After some playing around, I've found that if I change the call to sc.selection.selectRange to use just sc.lastSegment.tick instead of sc.lastSegment.tick + 1, it only selects everything in the part except for the last chord, but it doesn't crash.

It doesn't add the TextLine elements that I expected it to add either though, so I still don't understand it yet.

(Edit: wait I think that might have been with the line still commented out... when I try it now it still crashes, sorry)

In reply to by jeetee

What do you mean by that? Is there a way for a plugin to add them in an indecent manner?

One thing I did notice was that I couldn't find a way in the Plugin API to control the end-point of the line, only the beginning of it... is that part of what you meant?

In reply to by jeetee

Ah, after some searching through these forum posts by illionas and jonarnold: Create horizontal Line (TextLine) and Add text line to range.

I found one of the comments by parkingb reports a crash exactly as I've been experiencing! el.add(bracket); // STOP : crashes Musescore

And the proposed solution for that particular problem was to use cmd("add-noteline");. However, I'm a bit worried about whether that would be equivalent to going in the "Add menu -> Lines submenu -> Note Anchored Line" vs going in the "Palattes -> Lines pallate -> Line". When I tried doing the former manually I got diagonal lines that were hard to adjust, but when I do the latter manually I get horizontal lines that are comparatively easy to adjust.

In reply to by AlexKnauth

A Note Anchored Line is not the same as a Staff Line from the palettes no.
To my knowledge there are no shortcuts defined for the other line types (though add-8va is available as well, that one has the nasty "side effect" of actually changing the notation...)

So what I meant is; since MuseScore wasn't updated since the findings from that linked topic here those findings haven't changed yet and the same limitations still apply.

Using the Score Comparison Tool between the score before and after adding the TextLines manually, I was able to get the Diff showing the kinds of elements I would need insert:

(see file attachment below, using a markdown codeblock didn't work because the markdown parser still interpreted the XML tags within the codeblock as html I think, that's probably bad)

So that's where I may turn to next with a "plug out" kind of thing if I can't insert these TextLines with a plugin.

Attachment Size
diff.txt 4.24 KB

In reply to by AlexKnauth

Again the trouble comes when I insert a system break, and it splits the Spanner/TextLine into Segments. The new Segments don't get the same offset and off2 formatting that I'm putting on the original.

Is there a way to specify "default" properties for the TextLine that will be applied when new Segments are created after system breaks?

In reply to by AlexKnauth

I couldn't find a way to specify "default" properties, but I can just ram in a Segment for every measure so that even if every measure has a system break on it, it will be enough:

generated-openlines-system-break

The next 2 things I'll be looking at are either:
- Tweaking the offsetX positions so that they go to before the Clef/TimeSig stuff on the first line but don't go too far beyond the Clef on the subsequent lines
- Adding custom ledger lines, even if they have to be faked with more TextLines

Alternative approach using multiple staves in the instrument, "fix to line" on the notes and a little bit of clef displacement with a final touch of fixed staff spacers:
334941-Guitar_MSN-example.png

There are different variations of this thinkable that can cover both staff lines and correct ledger lines.
Black line is a standard 5 line staff; gray is expanding it with identical spacing for reference. Blue lines are the staff & ledger lines as given by your LilyPond values. Green is the option I choose in the example, yellow is a different alternative.
334941-Guitar-MS.png

Now I think another (but similar) alternative approach might be possible as well; by adding multiple instruments instead of staves within a single instrument you'd get the option of using instrument transposition on them instead of having to resort to "fix to line" to get correct note positioning; which should allow you to keep regular accidental behavior instead of having to manually fix up symbols for them.
The obvious downside of that approach is that when exporting to other formats you've changed the musical meaning and effectively split your instrument into 5 different instruments.

Note that I've not yet added the fretboards and their chord symbols to the score, but since those don't deviate from the defaults at all, just refer to the handbook page (or ask here) if you run stuck on them.

I'm not sure how much of this can be automated (I don't think a plugin can do the fixed spacer thing), but at least the setting of note positions to their respective lines and cut and pasting (or copy and paste) from a reference input seems achievable.

Attachment Size
334941-Guitar_MSN.mscz 14.65 KB

Do you still have an unanswered question? Please log in first to post your question.