Plugin API Bug or Feature? Note.accidental and Note.accidentalType not updated in new cursor instance after setting to regular accidental.
Hi all. I have provided a condensed snippet of my situation:
Assuming that the first note in the score on voice = 1, staffIdx = 1, tick = 0 exists, and is any note that is not F#...
// some necessary preliminary code for other parts of the plugin.
cursor.rewind(1);
cursor.track = 0;
cursor.rewind(0);
// Setting the first note to F#5
var x = {the first note in the score};
x.line = 0;
x.accidentalType = Accidental.SHARP;
console.log(x.accidental, x.accidentalType); // as expected: Ms::PluginAPI::Element(0x1dbb9fe0) SHARP
// some more necessary code
cursor.rewind(1);
cursor.track = 0;
cursor.rewind(0);
// this is my issue
var y = cursor.element.notes[0];
console.log(y.line); // correct: 0
console.log(y.tpc); // correct: 20
console.log(y.accidental); // expected: [Element object], got: null
console.log(y.accidentalType); // expected: SHARP, got: NONE
The unexpected values of y.accidental
and y.accidentalType
do not occur when I set the x.accidentalType
to a non-standard microtonal accidental such as SHARP_ARROW_DOWN
or MIRRORED_FLAT
, and I assume it is because when I set the accidental to a recognized standard accidental, it updates the tpc of the note, removes any attached accidental and marks the score dirty such that it updates and attaches the new regular accidental only after the plugin runs.
However, I require access to that accidental in order for my plugin to work. Is there any way I can force the score to redraw in the middle of my plugin's execution? Or is there something I'm missing or doing wrong? Or is this a bug that I should report in the Support and Bug Reports forum?
Any help greatly appreciated :)
Thanks in advance!
Comments
Depending on your pluginType the framework calls startCmd/endCmd for you to apply the undostack correctly.
You could try calling
endCmd()
after changing the setting, ThenstartCmd()
again before changing different stuff.In reply to Depending on your pluginType… by jeetee
My plugin type is currently undefined, and there is no GUI for the plugin. Also, in that case, if the user would want to undo the entire operation caused by the plugin, they would have to undo one time for each
startCmd()
endCmd()
pair?In reply to In that case, if the user… by matt28
that would be my guess
In reply to that would be my guess by jeetee
yep it is! Thanks.
In reply to Depending on your pluginType… by jeetee
Hi, I have the same problem:
note.accidental
staysundefined
after changingnote.tcp
and/ornote.accidentalType
.endCmd()
/startCmd()
do not help (and would semantically incorrect). My plugin type isdock
.Also, I noticed that the inspector tool doesn't display a button for
accidental
. Why? Any ideas?In reply to Hi, I have the same problem:… by nurfz
First,
note.accidental
should benull
if there is no accidental for this note, notundefined
. If the value you see is exactlyundefined
then it may happen that yournote
variable points to something else than a note.Second, changing
tpc
values directly does not really do the right thing. In order to get a note in a consistent state one should change at least all oftpc1
,tpc2
andpitch
. This stems from the way it is implemented internally in MuseScore, and plugin API currently does not provide a more convenient way to do this. It may be easier to remove the old note and add a new one instead if it is appropriate.Changing
accidentalType
though does work for me, and the accidental is available at the note'saccidental
property afterendCmd()
/startCmd()
. The latter calls are needed to do a score re-layout which would add the necessary accidental to a note. If you really need to access the accidental object before the re-layout you may try to create an accidental object manually and add it to the note withnote.add()
call.In reply to First, note.accidental… by dmitrio95
Thanks! Oh, I had a bug which explains the
undefined
!Ups, I only assigned
tcp
so far which seems to work unless I don't change MuseScore setting "Concert Pitch". Thank you for the hint.Does changing
accidentalType
affectstcpX
/pitch
? Or is it "safe" to change it just for a different accidental appearance?Looks like I really have to use
note.add(myAccidental); note.accidental = myAccidental
to make it always visible (important for my use case). Can you tell me how I can createmyAccidental
(of typeElement
). Can it just be{visible: true}
?Thank you!
In reply to Thanks! Oh, I had a bug… by nurfz
Yes, changing note's
accidentalType
changes pitch andtpc
if needed.As for your other questions, the answer depends on what exactly do you need. If you only need to add some accidental that will always be displayed, even if such accidental is implied by key signature, then setting note's
accidentalType
seems to work fine.If you also need to access that accidental in the same command and do something with it then the simplest way to do it I was able to get working is the following:
Basically, here I create an accidental with
newElement()
call, and the rest is something weird. It seems that the accidental gets removed if it does not match the note'saccidentalType
, but in order to always display the accidental you should only set the note'saccidentalType
after adding the accidental to the note. In the same time the final accidental seems to be notacc
so changing its color does nothing, but if I do not add thatacc
to a note first then the entire code fails if the note has not had an accidental before. So this is a somewhat hacky but hopefully working way to achieve what you have described (if I understood you correctly).In reply to Yes, changing note's… by dmitrio95
Thank you for the explanation and examples! I'll keep that in mind. But it's indeed not easy and I have to invest some more hours to get this working. For your information, my plugin is for converting the first note system in this image to one of the other systems (different "dialects" of a tabulature system). The SHARP2 symbols are only used as symbols in the tabulature and the side effects between tcp, pitch, accidental are pretty annoying in this case ^^
In reply to Thank you for the… by nurfz
If you only need a symbol without any meaningful side effects then you should probably use exactly symbol elements instead of accidentals. In user interface you can drag a symbol to a note from "Symbols" section in Master Palette, in plugins you can do the same by adding a symbol to a note:
The downside of this solution is that you would have to manually set an offset to make the accidental be displayed at the correct position, but the effect would be exactly as desired: just a visual marking without any side effects.
The list of available symbols can be found here or directly in Master Palette (symbol tooltips seem to contain the relevant symbol names). There are several flavors of double sharp and many other symbols there.
In reply to If you only need a symbol… by dmitrio95
Wow, thank you so much! I should have ask earlier! Your solution is so much nicer than abusing
accidental
and just perfect for my use case.Do you happen to know, if I'm allowed to set my own properties on, e.g. a note object like
note.myCrossSymbol = sym
(in addition tonote.add(sym)
)? It would be helpful to avoid a for-loop overnote.elements
to find the added symbol later on...In reply to Wow, thank you so much! I… by nurfz
No, unfortunately it won't work this way. The objects accessible in plugins are actually wrappers for internal MuseScore objects, and those wrappers are created on demand when relevant properties and methods are invoked from plugins. Therefore several wrappers may point to the same internal object (this can be checked with
is()
method), and while you can add a custom property to some wrapper object, other wrapper objects will not see such property. So this will not work for saving an information between plugin invocations or between different operations in the same plugin instance.In reply to No, unfortunately it won't… by dmitrio95
Alright. Thank you for the explanation!
In reply to First, note.accidental… by dmitrio95
I think, I could solve my last question:
But when
endCmd()
performs the re-layout, the the accidental on the second note in the measure gets visible again. Is there really norelayout()
command that does not commit to the undo history?