Can a plugin access on-time/off-time?
Reported version
3.2
Type
Plugins
Frequency
Once
Severity
S5 - Suggestion
Reproducibility
Always
Status
closed
Regression
No
Workaround
No
Project
Can I write a plugin to impart a desired phrasing upon a run of notes?
For more detail on this request see these forum posts in order:
This is the original post:
https://musescore.org/en/node/291414
This post continues the discussion in the are of implementation:
https://musescore.org/en/node/291519
-Dale
Fix version
3.3.0
Comments
Okay, then maybe you have to do "make -f Makefile.osx clean" after all.
Doing that now. I managed to force it to the right Qt by renaming the old 5.12 subdir, but the built app couldn't find the Qt import files from the plugins. I unrenamed the directory, uninstalled 5.12, same thing. Rebuilding now after make clean.
OK now; make clean was necessary.
Success on the Xcode front; what other neat MS-specific features do I get besides the "Debugger" note context window and the Debug menu? The instructions should note that there are three nonfatal red "issues" about the autogen script ("no classes found", but tool did not return nonzero, so build succeeds). Worked for me without env var adjustments. The "About" box should note that this is a debug build.
Those errors are from MOC (Qt's Meta-Object-Compiler) and basically warnings. Haven't been able to get them removed so far, those files it complains about claim to be/contain Q_OBJECTs, but really don't, MOC is just to stupid to detect that all that code is
#ifdef
d out.Debug builds do mention this in the about box "Unstable Prerelease for Version:", at least they do for me.
Edit: actually no, prereleases do that, the way to tell debug builds from others is to check whether the Debug menu is present.
In reply to Those errors are from MOC … by Jojo-Schmitz
Repeat, it oughtta say in the "about", including in the copy-string...
Why? Those (practically) never are publicly visible, no development build is actually a devug build.
Anyway, there you have a potential candidate for your first PR ;-)
Where is the c++ header file that defines Note? XCode isn't helping me. What is the field of Note that gets me back to its containing chord?
libmscore/{note.h,chordrest.h}?
We truly need Note.Chord to be accessible via QML, (and segment from chord) or you can't get context (including grace notes) from a clicked-on note. I know that if I understood the well code enough I could do that myself, but Dale could do it faster ... I can search the whole score for the containing chord for now ...
As far as I remember Dale exposed
Element.parent
property as a part of another pull request, https://github.com/musescore/MuseScore/pull/5209. That should be exactly what you are looking for.In reply to As far as I remember Dale… by dmitrio95
deleted
In reply to if (element.type == Element… by [DELETED] 1831606
(deleted)
I did a make clean and now both make release and make xcode fail with this (I cannot build at all).
Unknown CMake command "QT5_ADD_RESOURCES".
-- Configuring incomplete, errors occurred!
See also "/Users/bsg/MuseScore/build.release/CMakeFiles/CMakeOutput.log".
xcodebuild: error: 'mscore.xcodeproj' does not exist.
xcodebuild: error: 'mscore.xcodeproj' does not exist.
make: *** [release] Error 66
[(chord-add-remove)]$
Is Qt still in your PATH?
In reply to Is Qt still in your PATH? by mattmcclinch
Duh. Superannuated console window. Thanks.
In reply to Duh. Superannuated console… by [DELETED] 1831606
How do I merge that other branch (chord-add-remove) with what I have? I fear switching to it will ignore the other changes.
There are multiple ways to do this, but I would do the following:
git fetch DLLarson chord-add-remove
git cherry-pick DLLarson/chord-add-remove
In reply to There are multiple ways to… by mattmcclinch
(sorry, wrong directory).
(comment no longer applicable)
$ git cherry-pick DLLarson/chord-add-remove
error: could not apply c3151b8... Restore Chord.remove() and Chord.add() methods. + collect_artifacts
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add ' or 'git rm '
hint: and commit the result with 'git commit'
Looks like there are conflicts between the two PRs. You can try to resolve them on your end if you want, or you can wait.
Hi everybody...
The PR's have been inspected and there is one change affecting the scripting. The property
selections
is now calledelements
to match the internal name. I've pushed the changes to my test branch:https://github.com/DLLarson/MuseScore/tree/qml-pr5224-pr5243-playevent-…
I've attached updated test scripts to this post. It's feeling close to finished!
-Dale
How do I get the whole @#$@#$#$ tree back into a consistent state? I'm trying to restore yesterday's branch, but getting
$ git checkout DLLarson/qml-pr5224-pr5243-playevent-selection
mscore/plugin/api/elements.h: needs merge
error: you need to resolve your current index first
>How do I merge that other branch (chord-add-remove) with what I have? I fear switching to it will ignore the other changes.<
Would you like me to stack it on top of the others?
-Dale
Dale: Please create a consistent branch with all the changes, including element.parent, which I truly need, thanks. Right now I don't have a buildable tree and I forgot the git magic to restore it to workingness (I knew years ago). I wish there were a channel for discussing this without posting on the forum.
How do I get the whole @#$@#$#$ tree back into a consistent state?
git cherry-pick --abort
In reply to Dale: Please create a… by [DELETED] 1831606
(deleted)
I just added the chord.add/remove PR to the uber feature branch and pushed it up (even though the branch name doesn't reflect it.)
-Dale
Is there any problem with deleting the whole MuseScore tree, re-cloning, and re-fetch/checkout Dale's branch?
Seems like overkill, but knock yourself out. Did you at least try
git cherry-pick --abort
?In reply to Is there any problem with… by mattmcclinch
Yes, cherry-pick --abort resolved the problem, and I built the older branch.
This will get the fresh code pretty fast:
git clone --depth 1 -b qml-pr5224-pr5243-playevent-selection https://github.com/DLLarson/MuseScore.git
-Dale
Über-kuhl. I've "checked it out", as git users and others differently say, and it's building. .selections is now very reasonably to be called .elements ....
In reply to Über-kuhl. I've "checked it… by [DELETED] 1831606
Here's another request. Shouldn't chords have .parent's, too (segment, so you can find all other chords which sound with it?) (Yes, they should...). no?
Up and running and in resonance with the elements...super-cool...
>Here's another request. Shouldn't chords have .parent's, too (segment, so you can find all other chords which sound with it?) (Yes, they should...). no?<
The parent property is exposed for all elements. It isn't restricted to chords. In theory you should be able to walk the object tree.
-Dale
In reply to >Here's another request… by DLLarson
Couldn't be better. Thanks. Busy plugin-coding....
Upgraded rednote plugin attached ("elements" instead of "selections", "enote" typo fixed).
After my new plugin changes 3 values in playEvents it has located, it logs
Debug: no active command, UndoStack
Debug: no active command, UndoStack
Debug: no active command, UndoStack
when exiting. And sure enough, the changes, which are correctly made, are not undoable. Do you have any idea why this may be happening? The plugin is of the dialog-type, and the changes are made by a button handler.
>Do you have any idea why this may be happening?
Since your plugin is dialog or dock based (i.e., has a user interface) you must manage the undo bracketing yourself.
https://dmitrio95.github.io/plugins/html/class_ms_1_1_plugin_a_p_i_1_1_…
So you need enclose code that changes stuff with Score.startCmd() and Score.endCmd() calls.
-Dale
In reply to >Do you have any idea why… by DLLarson
Duh[2]. That was easy. Thanks, works great.
Here's what I have (test score and plugin).
Hi,
Sorry to say I'm having issues. I'm running it from the plugin menu and have a debugger attached so I see script output. Here's what I get:
qml: hello adjust appoggiatura
qml: 1 selections
qml: element.type=19
qml: grace notes [object Object]
qml: main note playevs [object Object] 1
qml: on time 333 len 667 off time 1000
qml: grace chord 0: Ms::PluginAPI::Chord(0x15c013c0)
qml: grace note 0 Ms::PluginAPI::Note(0x15c00e80)
qml: on time 0 len 333 off time 333
qml: found summing appog-main pair!
file:///D:/Users/Dale/Documents/MuseScore3Development/Plugins/adjustappoggiatura.qml:100: TypeError: Cannot read property 'playEvents' of null
It gets through the code to the point it sets a note but for some reason the variable used to set note's playEventList is null at the moment it's needed.
However, a couple times it DID work for me but I can't get it to work anywhere near reliably.
This feels a lot like race condition between onRun and initialization of these variables:
property var the_note : null
property var the_grace_note : null
If they are lazy initialized and that happens after onRun--which may be completed before the dialog is up and running--then this could happen. I'm not sure how this declarative QML language works for this. Remember that the Javascript is just a bolt-on interpreter that is called in response to events.
https://doc.qt.io/qt-5/qtquick-performance.html#lazy-initialization
For me this is the only explanation for what I see. If another reason can't be seen for this, is there a way that the onRun code could be run in the dialog button run 'context'?
-Dale
Maybe we have to call that strange function you have that forces play events. I bet that's it. try that.
The initializations of those variables are not needed. I put them there for syntax. They are set by the onRun and used by the Apply handler.
onRun is called when the plugin is loaded, in every case. If it doesn't find a selection it likes, it exits, and QML never puts up the dialog. If it finds one, it saves the note pointers in those 2 vars (know a better way?) for the Apply handler when the Apply button is pressed. Only then is system data changed.
In reply to The initializations of those… by [DELETED] 1831606
Just one thought...
In terms of handling the data in a common context, checkout the attached tin-whistle-tab plugin I've been helping out on. If you look at the "onRun" I check the conditions for a successful use of the plugin and either put up an error dialog (in my case) or do the plugin's function.
In your case you would check for a selected note and grace note and NOT (unless you want to show a visible error) show your dialog if the conditions aren't right.
If all is ok then open your dialog and let the processing continue there.
Of course I realize that there are as many approaches as there are programmers (I call it the Hundred Programmer Problem--If you give a task to 100 programmers, you will get 100 different solutions!) but the key is to keep asynchronous stuff out of the main plugin work.
-Dale
In reply to Maybe we have to call that… by [DELETED] 1831606
>Maybe we have to call that strange function you have that forces play events. I bet that's it. try that.
It could be. Weirdly, I forgot about the function!
It should always be used when messing with PlayEvent's.
-Dale
In reply to >Maybe we have to call that… by DLLarson
I have a much better and more capable version with a much, much better demo. Here. Lemme look at the code you sent.
In reply to I have a much better and… by [DELETED] 1831606
It works for me (in Qt 5.9) whether I select a "good" note or not; if I don't select a good note, the dialog is never seen.
In reply to It works for me (in Qt 5.9)… by [DELETED] 1831606
Dale, any luck figuring what's going on? I removed the initialization of the global var, but it never fails for me. Are you using my score or some other test case?
I've only been using your files.
I just downloaded your latest and I have the same issue. I also played the score before trying to test your theory that the createPlayLists() should have been called. Here's the console output:
qml: hello adjust appoggiatura
qml: 1 selections
qml: element.type=19
qml: grace chords [object Object]
qml: N grace chords 1
qml: grace chord# 0 Ms::PluginAPI::Chord(0x178e0120)
qml: grace note 0 [0] Ms::PluginAPI::Note(0x178e0300)
qml: on time 0 len 333 off time 333
qml: summa 333
qml: main note playevs 1
qml: on time 333 len 667 off time 1000
qml: found summing appogiatura note!
file:///D:/Users/Dale/Documents/MuseScore3Development/Plugins/adjustappoggiatura_0.qml:110: TypeError: Cannot read property 'playEvents' of null
If a put a
console.log("console.log("the_note=" + the_note);
on line 109 I get this in the log:qml: 1 selections
qml: element.type=19
qml: grace chords [object Object]
qml: N grace chords 1
qml: grace chord# 0 Ms::PluginAPI::Chord(0x1a5f04d0)
qml: grace note 0 [0] Ms::PluginAPI::Note(0x1a5ef990)
qml: on time 0 len 333 off time 333
qml: summa 333
qml: main note playevs 1
qml: on time 333 len 667 off time 1000
qml: found summing appogiatura note!
qml: the_note=null
file:///D:/Users/Dale/Documents/MuseScore3Development/Plugins/adjustappoggiatura_0.qml:110: TypeError: Cannot read property 'playEvents' of null
You can see the
the_note
isnull
. I entered a number like 450 and press apply. That was the result. Beats me how that happens since above you can see it got through the code that sets the variable.Can you think of another place to stash that value? I'm going to try to stick a closure into the dialog ....
It will not let me assign the readOnly on-clicked.
Try changing
property var the_note: null
to
property var the_note
(i.e.,remove the intiialization)
I know. We can re-get the selected note. Let's try that.
OK, here's a version that does not use global variables, but recomputes the relevant note from the selection at apply time (in faith that it exists).
This time it worked. I got this console output:
qml: element.type=19
qml: grace chords [object Object]
qml: N grace chords 1
qml: grace chord# 0 Ms::PluginAPI::Chord(0x22d53ae0)
qml: grace note 0 [0] Ms::PluginAPI::Note(0x22d53c30)
qml: on time 0 len 333 off time 333
qml: summa 333
qml: main note playevs 1
qml: on time 333 len 667 off time 1000
qml: found summing appogiatura note!
qml: Begin apply pass, new transit= 333
qml: Apply pass grace_chords [object Object]
qml: Did it! 333
However, no undo frame was created. Hmmmmm.
-Dale
In reply to This time it worked. I got… by DLLarson
It looks like you didn't actually ask it to change anything (both old and new are 333).
Belay that last report.
If I used the default value it didn't set the undo. Other values it's working fine.
So I understand, to get it working you delayed your actual list scan, computation, and value setting to when the Apply button was pressed?
-Dale
In reply to Belay that last report. If I… by DLLarson
No, I do it twice. The value in the box is not the "default value", but the current value of the selected note. I do it once when invoked, and quit immediately if none is found, and again when Apply is pressed.
In reply to No, I do it twice. The… by [DELETED] 1831606
Look at the code. find_usable_note is called twice, once in onRun and once in ApplyChanges.
In reply to Look at the code. find… by [DELETED] 1831606
The seeming inability to have a global variable, passing anything at all from onRun to UI handlers, is very, very bad.
(superseded by next).
See this https://musescore.org/en/node/292664 (minimal test case and detail for categorical dialog-plugin initialization problem)
I've pushed up another update of the uber branch:
https://github.com/DLLarson/MuseScore/tree/qml-pr5224-pr5243-playevent-…
There are no changes to the scripting interface. The changes are all related to ensuring the script doesn't damage internal data.
I've attached a new test script for some of those changes.
Other than that I'm hopeful that this latest set of PR's will be accepted into master.
-Dale
In reply to No, I do it twice. The… by [DELETED] 1831606
>No, I do it twice.
The important part is that the final computation all happened in the same time lineage.
-Dale
In reply to >No, I do it twice. The… by DLLarson
Do you understand what's going on with my test dialog and initialization? What do I tell git to receive your latest changes?
>Do you understand what's going on with my test dialog and initialization?
Nope. I can see in the code that there a distinct differences between the way menu initiated plugins are loaded and executed:
https://github.com/musescore/MuseScore/blob/c37676f8a2f91f51b37d9b698d8…
versus the way the plugin creator does it.
https://github.com/musescore/MuseScore/blob/c37676f8a2f91f51b37d9b698d8…
But that's about it. This will have to be looked at by an overall plugin loader qml expert. It does look like a bug so a defect issue should be entered for it.
>What do I tell git to receive your latest changes?
Since you cloned a shallow history with
git clone
it's simplest to delete the folder and re-clone the source:git clone --depth 1 -b qml-pr5224-pr5243-playevent-selection https://github.com/DLLarson/MuseScore.git
-Dale
In reply to >Do you understand what's… by DLLarson
$ git clone --depth 1 -b DLLarson/qml-pr5224-pr5243-playevent-selection
You must specify a repository to clone.
usage: git clone [options] [--] [
(with or without DLLarson/ ).
In reply to $ git clone --depth 1 -b… by [DELETED] 1831606
You missed the rest of the command line. The repo URL is at the end of it.
-Dale
In reply to You missed the rest of the… by DLLarson
Yup, figured it out. It's fetching now, as it were.
I found a foolish workaround to the plugin initialization problem, a "press me!" button. In this version, if you're not satisfied with grey "334", you can press "See Current", and violà, as the mis-say, it re-finds the note, computes the summa and puts it in the slot, at dialog-button time. Pretty silly, other people say. Try it. I'm using your branch, all builds and works with my code (haven't tried your code). I used this plugin in actual work to customize dozens of appoggiature in this actual score, which came out pretty well (I bound a key to it): https://musescore.com/bsg/erbarme_dich .
In reply to I found a foolish workaround… by [DELETED] 1831606
I enjoyed the piece!
MuseScore can do some impressive things. -- when in capable hands of course.
-Dale
In reply to I enjoyed the piece!… by DLLarson
Thanks, but Bach gets all the credit here. But see how important it is to tinker with the appoggiatura playEvents?
When I use your message dialog technique to report errors, if the error is shown and accepted, plugin accelerators no longer work unless I switch to a different application and back to MuseScore. There is something broken in re-selecting the MuseScore window with respect to those accelerators after such a message-box closes. I don't know if it's mac specific. My "onAccepted" calls Qt.quit() like yours. If my "dialog-plugin" dialog closes normally, there is no problem. Do you get this effect?
>here is something broken in re-selecting the MuseScore window with respect to those accelerators after such a message-box closes.<
It appears that the Mac's input 'focus' didn't return to your application. This can be quirky between OS'es. I've attached an updated version that makes the dialog "application.modal" so that control should go back to the application. Give it a try.
I noticed something annoying about short-cut key assignment. When I reload plugin's from the plugin manager my assigned keyboard shortcuts vanish.
-Dale
In reply to When I use your message… by [DELETED] 1831606
Unable to find a workaround, I removed the error-complaint feature. Error indication is now "doesn't do anything", but the accelerators work properly. It is crazy that I cannot pass info to the dialog (it could put up an error message if I could), or run any code before it is exposed.
In reply to >here is something broken in… by DLLarson
I added that declaration to my own message-dialog, and observe no difference in behavior. I tried several combinations of quit() or lack thereof after the open() call and in the button handler. I think it has to do with the fact that the plugin is a dialog-type plugin, which, given that it has to accept input, is mandatory. Yeah, when you reload plugins, bye-bye bindings. MS QML is witchcraft.
In reply to I added that declaration to… by [DELETED] 1831606
I created a minimal test case (selection problem) that does not fail (attached). Must be pilot error -- later.
Dmitrios has identified the no-init bug as known since 2013, has references, a fix in the works, and an easy workaround (use Component.onCompleted instead of onRun until the fix) and that house is now all in order. This surely will fix the the_note problem, too, See the other thread.
In reply to Dmitrios has identified the… by [DELETED] 1831606
So it turns out that instead of running out of sync in two different time contexts--like a race condition--the plugin code is running in two different code contexts.
It's great news that the cause is known and easily fixable!
-Dale
I've found the accelerator problem (but not the core code bug causing it): https://musescore.org/en/node/292732 . With that in mind, and this morning's writearound, attached is a fully operative version of the Appoggiatura plugin.
Here's an even cooler plugin using the new capabilities , the one I've been waiting for for years. From the source,
/* This plugin replaces the Piano Roll Editor as the most convenient means of
adjusting the on-times and off-times (not "len"s) of notes on a one-by-one
basis. This allows you to phrase without the yellow bar jungle (which is
always there for hard cases). This even works on appoggiature, but does
not work on notes with real "ornaments" (not well-defined how to edit).
Extensions to impose duple- and triple- phrasing patterns are under
consideration.
Just click on any note, and invoke this (maybe via a shortcut), and
edit away the on and off times. Return and ESC are accepted as
Apply and Cancel.
*/
Here's a dialogue-driven Baroque trill generator based upon your unique ornamenter, and demo (just play it through).
By the way, destructuring assignment [a, b] = [1, 2] is an ECMAScript 6 feature which is thus not in Qt 5.9. Dale, could you private-mail me an email address so we can take this conversation out of the forum? Thanks.
In reply to Here's a dialogue-driven… by [DELETED] 1831606
Despite my not understanding any of the words in the Dialog... That's really cool!
Just punch in a couple numbers, hit a few buttons, and you get a really nice trill of various forms.
-Dale
In reply to Despite my not understanding… by DLLarson
In the hands of musicians, professional or amateur, who know what they're doing, these capabilities and tools will accelerate the process of score-preparation for quality performance (by whatever sound resources) immeasurably, and allow the Piano Roll Editor to be thrown off the roof....
>and allow the Piano Roll Editor to be thrown off the roof....
It's kind of nice to see the spatial effects on the score as a visualization tool.
-Dale
I agree it's beautiful and entertaining, but only showing one staff at a time, it is less valuable as a visualization tool. As a performance-editing tool, it is far better than it was in version 2, where the usual outcome was crashing the program, and is a huge boon, but has nothing to offer over these new tools.
Fixed in branch master, commit 216188f7ed
_Fix #291708: Expose Score.selection object to access to GUI selected elements.
This commit exposes the Score.selection.elements list
enabling QML scripts to manipulate on user selected score elements.
The expectation is that additional selection information will be
provided on this object in the future._
Fixed in branch master, commit 366ccb0628
_Merge pull request #5243 from DLLarson/expose-score-selection
Fix #291708 Plugin: Expose Score.selection object to access to GUI selected elements._
That was still not the main PR about note events, I return the status back for now.
Fixed in branch master, commit b05c823912
_Fix #291708: Expose PlayEvent's via QML Plugin Note interface.
Adds capablity to examine and modify PlayEvent's and a Note's
playEvents list. Adds access to Chord.playEventType. Also
supports UNDO for these operations._
Fixed in branch master, commit c25a17e919
_Merge pull request #5224 from DLLarson/qml-expose-noteevents
Fix #291708 Plugin: Expose NoteEvent's via QML Note interface._
This, like the Piano Roll Editor, is "beautiful and entertaining", but a terrific development. Looking forward to checking out the nightly! Thanks, Dmitrios!
Probably no one's reading this except myself, Dale, and Matt, but this is what a 5-minute Bach motet movement sounds like when every single note is deliberately phrased, by use of the new tools facilitated by these improvements, to match the text, line shape, slurs/phrasing marked by the composer, and other architectural considerations (i.e., "choral director dharma"): https://musescore.com/bsg/scores/1697186 . This opens a new chapter in MuseScore realism.
All commits have been merged. Check out tonight's (7/30/2019) if you wish to try a copy.
Fini!
-Dale
Not quite. I just learned that "nightly" isn't really 'nightly', it happens as soon as a merge succeeds! Now for the bad news! The mac build times out, and the previous build (0734 this morning, Europe time) doesn't have the OnRun fix, which I now need. Hopefully Dmitrios or Anatoly will fix the build problem. I so do not want to have to back out the onRun fix code.
In reply to Not quite. I just learned… by [DELETED] 1831606
>The mac build times out, and the previous build (0734 this morning, Europe time) doesn't have the OnRun fix,
What onRun fix?
-Dale
In reply to >The mac build times out,… by DLLarson
Habemus appam.
It is all well now! MuseScoreNightly-2019-07-30-1306-master-ec7d9a8.dmg
I was referring to the fix that executes onRun in the correct instance. It all seems to work now!
In reply to >The mac build times out,… by DLLarson
Hold on. I do see some onRun stuff from dmitrio in the commits!
Gonna try it out.
-Dale
In reply to Hold on. I do see some onRun… by DLLarson
Here ya go, y'all (announcement/plugin posting) https://musescore.org/en/node/292789 Thanks Dale, Matt, Dmitrio, Jojo, and Jeetee.
Automatically closed -- issue fixed for 2 weeks with no activity.