How to insert a chord?
Hi
How do I insert a chord using javascript in a plugin for Musescore 2+?
I would expect the following code to output a CEG triad but instead I get two side-by-side B notes with no stems with what looks like a quarter tone accidental.
var cursor = curScore.newCursor(); cursor.rewind(0); curScore.startCmd(); cursor.setDuration(1, 4); var c = newElement(Element.CHORD); c.duration = 480; c.visible = true; var n1 = newElement(Element.NOTE); n1.pitch=60; c.add(n1); var n2 = newElement(Element.NOTE); n2.pitch=64; c.add(n2); var n3 = newElement(Element.NOTE); n3.pitch=67; c.add(n3); cursor.add(c); curScore.doLayout(); curScore.endCmd(); Qt.quit()
What's the right way to insert a chord at the cursor's current position?
Thanks in advance.
Attachment | Size |
---|---|
not a triad.png | 1.99 KB |
Comments
Check how the plugin 'random.qml' is doing this.
That note(s) you got are actually Bbb (same pitch as an A) and the accidental is a double b
In reply to Check how the plugin by Jojo-Schmitz
Neither random.qml nor random2.qml insert chords. They only insert single notes. Actually, a quick check shows none of the example plugins insert chords. Any other suggestions? :)
In reply to Neither random.qml nor by bsdz
But it inserts notes with stems...
In reply to But it inserts notes with by Jojo-Schmitz
It's different. Those examples use cursor's addNote method which appears to be a helper function for inserting single notes but not chords.
Cursor.addNote indeed cannot add chords.
You're original idea is correct, but you need to also set the tonal pitch class of the new note by using the tpc1 and tpc2 properties of Note.
See Berteh's chordsToNotes plugin for an example.
I made a few tests:
1)
Cursor.setDuration(x, y);
seems to do nothing: a plug-in with just this command leaves the chord/rest at the cursor unchanged.2) By setting the
tpc1
and thetpc2
of each note added, it is possible to obtain a chord:No duration is set, assuming the chord will keep the duration of the element it replaces (i.e. the whole measure rest).
3) HOWEVER: this creates a no-duration chord (the debugger tells its duration is "0/1", whatever this may mean, the actual ticks are 0 and its duration type is empty) and the measure the chord is in is corrupted. This is rendered as a crochet-headed, unstemmed chord:
NOT FOUND: 1
4) if
c.duration = 480;
is used, the debugger reports the correct chord duration (1/4) and ticks (480), but the duration type is still empty and the measure is corrupted, as it contains only one crochet but its total duration is still 4/4. The visual rendering is the same as above. There does not seem to be any way to set the duration type.So, unless I dramatically overlooked something very obvious, I would assume either something is wrong or some necessary step is missing in the plug-in framework.
In reply to I made a few tests: 1) by Miwarre
I must admit I didn't test Berteh's plugin...
This way of adding chords doesn't seem to work.
Cursor.addNote() seems to have problems as well.
I tried to find a work-around to add chords by using cursor.addNote() for the first note and adding the remaining notes to the new chord, but I couldn't retrieve a valid pointer to the Chord created by addNote():
After a call to cursor.addNote(), cursor.element == null and cursor.segment also seems outdated (while not null).
This also leads to unexpected results when calling Cursor.next() after Cursor.addNote(). I ran the following on an empty score:
This is what I got:
NOT FOUND: 01
Cursor.next() jumps to the element following the one, that was replaced by the note created by addNote().
Things are getting more and more complex: now
Chord.duration
property no longer accepts anint
as value: it requires aFractionWrapper
, but I am not sure there is a way to create one with the desired numerator and denominator.(According to gihub, the change happened on April 7th, but I am pretty sure it was working with
int
at the time of the OP)Hi,
Is there anything new on this topic? What is the correct method to insert chords?
Thanks!
In reply to Hi, Is there anything new on by rousselmanu
From within a plugin? Or are you just trying to insert a chord in note entry mode of MuseScore?
If the latter see https://musescore.org/en/handbook/note-input
Hmm, I guess you meant the former, sorry
In reply to From within a plugin? Or are by Jojo-Schmitz
Thanks. Yes I meant within a plugin. Actually I just found a method to insert a non-corrupted chord, but this is not straightforward, the plugin framework is really not easy to work with and the documentation is poor ...
Here is the code if someone is interested:
{syntaxhighlighter class="brush: js"}
// create and return a new Note element with given (midi) pitch, tpc1, tpc2 and headtype
function createNote(pitch, tpc1, tpc2, head){
var note = newElement(Element.NOTE);
note.pitch = pitch;
var pitch2tpc=[14,21,16,23,18,13,20,15,22,17,24,19]; //get tpc from pitch...
if (tpc1){
note.tpc1 = tpc1;
note.tpc2 = tpc2;
}else{
note.tpc1 = pitch2tpc[pitch%12];
note.tpc2 = pitch2tpc[pitch%12];
}
if (head) note.headType = head;
else note.headType = NoteHead.HEAD_AUTO;
//console.log(" created note with tpc: ",tpc1," ",tpc2," pitch: ",pitch);
return note;
}
function setCursorToTime(cursor, time){
cursor.rewind(0);
while (cursor.segment) {
var current_time = cursor.tick;
if(current_time>=time){
return true;
}
cursor.next();
}
cursor.rewind(0);
return false;
}
//adds chord at current position. chord_notes is an array with pitch of notes.
function addChord(cursor, chord_notes, duration){
if(chord_notes.length==0) return -1;
var cur_time=cursor.tick;
cursor.setDuration(1, duration);
cursor.addNote(chord_notes[0]); //add 1st note
setCursorToTime(cursor, cur_time); //rewind to this note
var chord = cursor.element; //get the chord created when 1st note was inserted
for(var i=1; i
In reply to Thanks. Yes I meant within a by rousselmanu
I made a demo plugin to insert chords (well it's more like a library), you can download it here: //github.com/rousselmanu/msc_plugins , the file is "addChord.qml "
The example code to generate chords is:
{syntaxhighlighter class="brush: js"}
addChord(cursor, [n2p('D',4)], 2); //add a D4 note
addChord(cursor, [n2p('D',4), n2p('A',4), n2p('D',5), n2p('F',5)], 4); //add a Dm chord with 2 roots
addChord(cursor, [n2p('A#',3), n2p('D',4), n2p('G',4)], 4);
addChord(cursor, [n2p('A',3), n2p('G',4), n2p('C#',5)], 4);
addChord(cursor, [n2p('D',4), n2p('D',5), n2p('F',4), n2p('A',4)], 2);
addChord(cursor, [62], 1); //other method to add note: give the pitch
addChord(cursor, [60, 65, 69, 72, 69], 8); //duplicate note is automatically removed
addChord(cursor, [60], 8);
var chord = [60, 64, 67];
addChord(cursor, shift_notes(chord,5), 8); //shift the chord by 5 semi-tones
addChord(cursor, chord, 2);
{/syntaxhighlighter}
And the result is attached:
In reply to I made a demo plugin to by rousselmanu
Hi,
I've been struggling with the same thing and came up with a very similar solution. You can also add rests in a similar manner. Once you have added the note at the cursor, you can replace it with a rest.
This works without corrupting the file.
Rewind to the created note then do :
var rest = newElement(Element.REST);
rest.durationType = cursor.element.durationType;
cursor.add(rest);
I am currently testing a plugin that uses this, and it seems to work without a problem. (sorry I don't know how to add a code block. I will find out for future posts).
In reply to Hi, I've been struggling with by stevel05
I also found that using this method does not work reliably if the target measure already contains notes or rests (other than a full measure rest). So the notes have to be deleted and the measure set to a full-measure-rest. Have you found this, or have you overcome it another way?
In reply to I also found that using this by stevel05
Thanks for the tip for adding rests! I didn't try it yet. Only chords and notes for now.
I have seen no problem or bug if the measure already contains something: it simply overwrite it. You may try my plugin demo addChord.qml to see if you still have the bug?
In reply to Thanks for the tip for adding by rousselmanu
By the way, to get syntax highlight for your code in posts you can surround it with (syntaxhighlighter class="brush: js") and (/syntaxhighlighter) tags. Just replace '(' by '{' and ')' by '}' in the tags
In reply to By the way, to get syntax by rousselmanu
Thanks for the feedback, a little digging and I found the reason. The code to add a rest needs to be:
{syntaxhighlighter class="brush: js"}
var rest = newElement(Element.REST);
rest.durationType = cursor.element.durationType;
rest.duration = cursor.element.duration;
cursor.add(rest);
{/syntaxhighlighter}
It now works like a charm without deleting the existing notes, and the workflow will be much easier.