vertically aligning stave text or adding figured bass or Chord symbols?

• Aug 21, 2016 - 11:50

Hi all,

I'm writing a plugin for musescore v2 that summarizes the vertical sounds (chords) throughout the score, and prints the result on the score.

The idea is to write some string representation of the sounding chord (could be proper chord symbol, or figured bass like notation - let's assume some arbitrary string) whenever there is some change in some voice on some stave (new note sounding, or previously sounding note silenced by a rest) that essentially changes the previously sounding chord.

Obviously, I would like the output to be horizontally aligned to reflect exactly where the change occurs in time. At the same time, I would like to print my plugin output below the last stave of the score, or alternatively, above the first stave, and in such a way that all chord symbols appear at a fixed vertical position.

How can I do this?

Currently, I am using stave text. This is my code:

function writeChordStringRepresentationToScore(cursor, chordStringRepresentation){
//get a note with a tick where the chord changes.
var targetNote = chordStringRepresentation.targetNote;
//init the cursor
cursor.track = targetNote.track;
cursor.rewind(0);
do {
//if our cursor is positioned to point to our targetNote,
if (cursor.element && cursor.element === targetNote.parent) {
//create staff text
var staffText = newElement(Element.STAFF_TEXT);
//attempt to position the text below the last staff by adding 10 space for each staff
staffText.pos.y = (curScore.nstaves - cursor.staffIdx)* 10;
//actually set the text and add it to the score.
staffText.text = chordStringRepresentation.text;
cursor.add(staffText);
break;
}
} while (cursor.next());
}

Basically, the chordStringRepresentation argument contains both the textstring (.text) I want to print, as well as some note (.targetNote) that is at the tick where the chord changes. I use the targetNote to position the cursor (in order to achieve the right horizontal alignment) and then I add stave text, with an extra vertical offset of 10 for each stave between the stave where the targetNote sits and the last stave

The problems with this approach are that
1) Assumming 10 offset for each stave is a too rough approximation, totally disregarding the actual height used by a stave. I don't know how to find out how much height the staff actually uses. I cannot simply write stave text on only the last stave either, since the last stave might not have a note or rest at the actual tick where the chord changes, which I believe I need to achieve the horizontal alignment I need.

2) Even if the per stave vertical offset would be accurate, the vertical placement of the text depends on the vertical position of the targetNote. That seems to be just how stafftext works, and I don't know if and how I can change that.

I was thinking there should be a better way to achieve what I want, perhaps even use actual features like "chord symbols" or "figured bass" to print my output too, but I just can't figure out how to control these features from within my plugin code.

Can anybody please point me to some code that shows how I can either position my stave text, or how I can add chord symbols or figured bass text?


Comments

I kind of doubt the actual height of a staff is anywhere you can get at directly - it is something calculated on the fly during layout as opposed to a fixed quantity. But the basic calculation is pretty simple - its the number of staff spaces (lines - 1) times the line distance for the staff. The latter figure is normlly 1sp by definiton but can be alterted in staff properties.

How much of this can be access via the plugin interface I cannot say, but I can say that this is the info you'd need: number of staff lines, line distance for the staff.

Staff text should not depend in any way on any note - "0" is the top line of the staff, whetehr there is a note there or not. Staff text can, in princible, be attached to time positions that do not contain notes for that particular staff. They are *segment* annotations, not *note* annotations.

In reply to by Marc Sabatella

Marc, thanks again!

This piece of info was crucial for me:

"
Staff text should not depend in any way on any note - "0" is the top line of the staff, whetehr there is a note there or not. Staff text can, in princible, be attached to time positions that do not contain notes for that particular staff. They are *segment* annotations, not *note* annotations.
"

I guess my misunderstanding stems from the fact that in the UI, when you add staff text, you have to select an element on the stave to which the text will be attached. But internally this is apperently more flexible. Good!

My code is now:

function writeChordStringRepresentationToScore(cursor, chordStringRepresentation){
var targetNote = chordStringRepresentation.targetNote;
var chord = targetNote.parent;
cursor.track = targetNote.track;
cursor.rewind(0);
do {
if (cursor.element && cursor.element === chord) {
var staffText = newElement(Element.STAFF_TEXT);
staffText.text = chordStringRepresentation.text;
staffText.pos.y = 15;
cursor.track = curScore.ntracks;
cursor.add(staffText);
break;
}
} while (cursor.next());
}

What would be really cool is if we could directly position the cursor at the right tick or segment, i.e. without having to set the appropriate track and loop until I found the target element.

Is that possible? Documentation says cursor tick is read-only.

In reply to by Roland Bouman

You are correct that the UI requires to select a note or rest to attach the text to. You, can, however, then delete the notes in that measure leaving the text (if you use the selection filter to make sure the text isn't selected too, or edit/re-enter the notes in a way that causes there to no longer be a note or rest there. The segment will be left in place just for the sake of the text even though there are no notes or rests there.

Unfortunately I have no experience with the current plugin API, so I can only give general advice based on what I know about the internals. I would kind of imagine that "cursor" is just a fancy term for "current segment and staff/voice (aka track)". Realistivcally, the code intenrally msotly iterates over these in a loop as well, although there are convenience functions provided to do this for you to help you find the closest segment to a given tick. There aren't anything fancier than you could write yourself, though. I guess one thing that can be done internally but might not be straightforward in a plugin is to first loop through measures to find one with the right tick range, and then loop through the segments within that measure to find the right one. But realistically, we loop through all segments pretty often too.

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