Add Metronome Part fails with changing time signatures. Found a fix, but why does it work?
I found that with a score containing changes in beats-per-measure, Add Metronome Part does not work correctly.
I fixed it and am happy with the result, but I have no idea why this solution works. Probably my too naive understanding of plugin development. Can anybody enlighten me? Thanks!
For reference, the code as downloaded through https://musescore.org/en/project/add-metronome-part
is
import QtQuick 2.0 import MuseScore 3.0 MuseScore { menuPath: "Plugins.Add Metronome Part" description: "Add metronome part" version: "0.1" requiresScore: true onRun: { console.log("...") curScore.appendPart("wood-blocks") var idx = curScore.nstaves-1 curScore.parts[idx].isMetro = true var c = curScore.newCursor() c.rewind(0) c.staffIdx = idx c.voice = 0 if( c.measure.timesigActual.str != c.measure.timesigNominal.str ) c.nextMeasure() do{ c.setDuration( 1, c.measure.timesigActual.denominator ) for( var i=1; i <= c.measure.timesigActual.numerator; i++ ) c.addNote( i==1 ? 76 : 77, false ) }while( c.prev() && c.nextMeasure() ) Qt.quit() } }
I did a few experiments, all from the Plugin Maker. The results are shown in the image below, together with a test score.
First experiment was running the plugin as is.
The result is seen in the first Woodblock staff: no ticks.
The Plugin Maker gives a TypeError on the line
curScore.parts[idx].isMetro = true
.Apparently, this line is not allowed in my version 3.6.2. I commented it out with no apparent ill side effects.
Commenting out the line gives some result, but not correct yet. See the second Woodblocks staff, measure 5. It looks like measure 4 spills over in 5, and the rest of 5 is skipped. The code looked correct to me, however.
Some experimenting led me to introduce a new variable at the beginning of the Do loop:
var numerator = c.measure.timesigActual.numerator
and use its value instead of the full expression as controlling variable in the For loop. The result is in the third Woodblock staff, and is as desired. The final code is:
import QtQuick 2.0 import MuseScore 3.0 MuseScore { menuPath: "Plugins.Add Metronome Part" description: "Add metronome part" version: "0.1" requiresScore: true onRun: { console.log("...") curScore.appendPart("wood-blocks") var idx = curScore.nstaves-1 //curScore.parts[idx].isMetro = true var c = curScore.newCursor() c.rewind(0) c.staffIdx = idx c.voice = 0 if( c.measure.timesigActual.str != c.measure.timesigNominal.str ) c.nextMeasure() do{ var numerator = c.measure.timesigActual.numerator c.setDuration( 1, c.measure.timesigActual.denominator ) //for( var i=1; i <= c.measure.timesigActual.numerator; i++ ) for( var i=1; i <= numerator; i++ ) c.addNote( i==1 ? 76 : 77, false ) }while( c.prev() && c.nextMeasure() ) Qt.quit() } }
Why does this substitution work? It seems to me that it should not make any difference. Thanks for any help.
Attachment | Size |
---|---|
example.png | 118.76 KB |
Comments
Hi jeroen2442,
Your question comes down to
why this does not work
while this works
I think it's because the cursor reference is mutated by .addNote() method (see jeetee's comment)
for loop at measure marked 4 runs 4 times instead of expected 3 times, the 4th time the conditional being (cursorAtMeasure5).measure.timesigActual.numerator
Sidetrack question: curScore.appendPart is undocumented but seems to work, contrary to this, should correct wiki?
In reply to Hi jeroen2442, Your post… by msfp
Thanks for pointing this out to me! I had implicitly assumed that the termination condition for a loop is determined and set at a fixed value at the time the loop is initiated.
I now know that is not how it works in JavaScript. The call is by reference, not by value. In this case the condition changes during the loop, which has unintended side effects. My fix solved this, without me realizing what it is that it being fixed.
Learned a new thing, thanks!
In reply to Thanks for pointing this out… by user2442
Glad to be of help
If your modified plugin's working, would you mind posting as new project/contact original dev to update and announce here