Plugin syntax, looping, and language issues

• Apr 17, 2015 - 08:56

I have become much more familiar with the plugin creator/editor that is built into MuseScore2, but have yet to figure out, after a couple days of trying, how to loop through the notes in a score in the most basic manner. Yes, I know other plugins do it, but they do it differently than I require for mine. I have tried to edit them, only to be entangled in undefined errors, etc. I have even attempted to reduce an existing plugin to the most basic portions, all of which appeared to me to be a complete piece of code, only to have errors that prevented it from running.

I've searched online as well, only to receive the perception that the .qml format is not well known nor documented. It certainly seems rather different from JavaScript. I haven't even seemed to figure out whether it is case-sensitive or not, though it appears to be so and yet the existing plugins seem to function in spite of using what appears to be the incorrect case.

Is there any reference manual on qml? Or can anyone provide me with the most basic skeleton of a program that will loop through each note, following the first voice (voice[0]) but stopping to catch each note at the same cursor point for each of the other voices in all staves?

I need something like this:

while (cursor.segment && (fullScore || cursor.tick < endTick)) {
  for (var voice=0; voice<4; voice++) {
      for (var staff = startStaff; staff <= endStaff; staff++) {
            note[voice] = cursor.notes
     }
  }
  cursor.next()
}

Basically, I need the chords, which cannot be obtained by getting just one note at a time. I have found no way of accessing multiple notes at the same time.

I can't seem to get even such a basic loop as the above going. I'm on the verge of giving up. I don't have infinite time to spend guessing and checking at an unknown (and seemingly undocumented) syntax and grammar to find a solution. I will admit that my programming style is concrete, not abstract, and I don't understand references, pointers, and objects. If those are required, perhaps someone can save me from wasting more time by sharing the truth now and putting me out of my misery.


Comments

In reply to by Jojo-Schmitz

Yes, thank you. I've been working with it. I have been trying to hybridize that one with the Note Names plugin. The two, however, resist the hybridization attempt rather strongly. I have my own code for identifying the chords which I have not yet had opportunity to include, because I cannot get the basic framework up and running yet, even without it.

NOTE: The Color Notes plugin goes through the whole score one voice at a time. I need four+ voices at the same time, and haven't found a way to do it.

This can't be done with a Cursor object, because cursor.next() will always proceed to the next element in the selected track but we cannot know which track will contain the next element. I used Segment therefore in the following plugins:

The basic idea is

// init segment pointer
var segment = cursor.segment;

while(segment) {
   // iterate tracks
   for (var track = firstTrack; track < lastTrack; track++) {
      var element = segment.elementAt(track);
      // make sure we got a valid pointer
      if (element) {
         // do work
         // Note: you will get all different kind of elements here
         //       not just chords and rests, so type checking is needed
         //       for example check for chords:
         if (element.type == Element.CHORD) { /* chord */ }
      }
   }
   // proceed to next segment
   segment = segment.next;
}

Hope that helps.

Well, heuchi's comment got me a little bit farther, but I still seem to be in no man's land as far as the script working.

I'll just attach what I have, which does not function properly, and perhaps someone can discover the error. Your help would be greatly appreciated.

Attachment Size
chordnames_non-functioning.qml 60.05 KB

In reply to by Tongkam

QML is actually well-documented:
http://doc.qt.io/qt-5/qmltypes.html
There are many examples here, as well.

I've looked at your code, and If I were you, I would start over by trying to make a very small modification to the notenames plugin. That plugin already does what you're trying to do for single staves. Start with that. In that plugin, the function nameChords(notes, text) is called from code in onRun : The notes argument is an array (or "list" in QML), and in this case it comes from lines 179-180

179 var notes = cursor.element.notes;
180 nameChord(notes, text);

The cursor.element in this case is of type Element.CHORD which is checked here:


156 if (cursor.element && cursor.element.type == Element.CHORD) {

which is inside the loop that iterates through the whole score using the cursor:


155 while (cursor.segment && (fullScore || cursor.tick < endTick)) {

You will see in the nameChord(..) function that each individual note is assigned a text name, based on the note.tpc. That function loops through the notes array (see line 179-180 above) that was obtained from a single chord on a single staff. If the chord only has a single note, then that is all that will be in the array. Or there could be two notes, or ten. It is limited to one staff at a time.

I would suggest trying to write a function that analyzes the notes that are already being found by the notenames plugin. Here is a little bit of code to get you started (including some debug code so you can see the results) try plugging this into the existing notenames plugin:

113 } // end if courtesy- and microtonal accidentals
114 } // end for note

//New code here:
115 var textArray = text.text.split(",");
116 analyzeChord(textArray);
117 console.log("textArray length " + textArray.length);
118 }
119
120 function analyzeChord(textArray) {
121 for (var i =0; i
Then you can try using your own code inside the analyzeChord(..) function.

In reply to by jensm

Thank you for pointing me to the documentation for qml. I will check it out.

Regarding the note names being a good starting routine, I'm not sure I can agree. It IS what I started with, but it seemed unable to adapt. As heuchi posted here earlier, it seems the cursor object cannot be made to work with chords. In the notenames script we see a note about something with the tpc not working, and so it appears even the authors of that were unable to provide the full functionality they had hoped to achieve (chord names?). The function "nameChord" implies to me that this was something they may have hoped to do.

The problem is that only one note generally ever appears in the array. Even though they have taken the time to iterate through as many notes as might be in the "chord," it's usually just one note. I've puzzled with this for hours already, to no avail. As heuchi pointed out, and you noted yourself, you cannot address multiple staves at the same time with the cursor. So only one staff is processed, and the way the thing appears to work, unless the notes in the staff are entered as separate voices, you will only see the top note anyhow. This is why the array is limited to just one note at a time...which isn't good for the chord-naming business.

Since I've never programmed in qml before, not only am I having difficulty with the museScore issues, but also I'm having trouble with the coding itself. The means no end of frustration, as I don't always know if the problem is my bad code, or the difficult framework I'm working in. I guess and check till I'm too frustrated to continue. Personally, I think I have to agree with heuchi that with the cursor it's not possible. But that is how the note names script was setup. So I'm starting off on a bad foot to use code that is not going to work for my purpose. It would be almost better to program from scratch...which is where my lack of acquaintance with the qml scripting really hurts. I'd rather just go from scratch, as I honestly don't always know what I'm messing with under the hood of the scripts I'm trying to adapt.

The note names plugin does not find chords to analyze. It appears that given its use of the cursor element, it cannot be made to find chords. Therefore, I'm still stuck. If you think the note names will work, and that it would not be difficult to adapt it, perhaps you can show me how. I'm a newbie here, and I honestly don't know how to do it. I would suggest that if you can adapt the note names routine to actually procure chords (get the notes from the same beat in all staves simultaneously), then I'd be willing to continue plugging away at it from there to complete the script. As it stands now, I'm too discouraged with that route, for it appears not possible anyhow, and heuchi appears to affirm that. I don't have the experience he does, so I have to respect his advice.

In reply to by Tongkam

I think you got some things mixed up here.

I didn't mean to say, the Cursor cannot handle chords. It can.
In MuseScore even a single note is considered a chord.

Look at this little example:
NOT FOUND: 01

Measure 1: Here we have a chord in track 0 (which is voice 1 of the only staff).

Measures 2 and 3: Here we have two different voices (tracks) each having single notes, however MuseScore will create a Chord object for all of these.

About the notenames plugin. It was not meant to detect chord names, and it handles chords exactly as it's meant to. This is the same file after having run notenames:
NOT FOUND: 02

As you can see, all three notes of the first chord are named, and they are also comma-seperated, so notenames realised, they are all part of the same chord and are in that chord's notes array.
The other notes are named above the staff for track 0 (voice 1) and below the staff for track 1 (voice 2).

This might all be a little confusing for now, but that's probably why jensm suggested to start with a simpler task. Chords like the one in measure 1 can be processed using the Cursor object.

So you could start trying to fully understand how notenames actually works and then try to write a plugin that analyses chords in only one track, such as in measure 1 in my demonstration score.

Attachment Size
chords01.png 12.92 KB
chords02.png 16.73 KB

In reply to by heuchi

Thank you, heuchi. I appreciate that for a single staff, the notenames is supposed to work that way. But all of the scores I want to add the chord names to are double-staff scores, with both treble and bass. In the future, I can see the potential for having two treble cleft staves and one bass cleft staff for some songs.

I'm not sure that my note names plugin works like you've demonstrated. In mine, I've gotten a different result. I'll try to attach pictures...

Before running Note Names...
MuseScore0.png

After running Note Names....
MuseScore1.png

As you can see, the plugin doesn't seem to be picking out all of the notes properly for me. At the very least, it is not grouping any of them into chords, as your example so nicely illustrated. Where did you get your version of the plugin? As can be seen in the images, there are four parts (SATB), each given its own voice in MuseScore. But the plugin addresses each of these notes in a separate "chord." They are not really ever in one "chord." I'm not sure why it is useful to even call a single note a chord.

Attachment Size
MuseScore0.png 30.62 KB
MuseScore1.png 43.29 KB

In reply to by Tongkam

You don't have chords there - well, at least, not multi-note chords - you have single notes in mutliple voices. Totally different thing.

I think you are still confused about the basics of how MuseScore represents notes. Let me try to summarize. Check out https://docs.google.com/document/d/1BmjPqk9j4-zSFaiFsUjYSURDk98MHSgrHjf… and see if it helps.

Bottom line: all notes in MuseScore belong to chords. It might be a chord of one notes or a hundred, but it's a chord either way. That's because the chord data structure is where certain information lives that has to be common to all notes of the chord - duration, stem, etc.

In reply to by Marc Sabatella

Thank you, Marc. It looks like I am indeed attempting the impossible. I just read the following at the link you provided...

A segment contains an element for a given track only if something actually happens at the tick for the segment. So for instance, if one staff has a whole note while another has two half notes, there will be two segments total. The first segment, representing beat one (tick 0 within the measure) will contain the whole note for the first staff and the first half note for the second staff. The second segment, representing beat three (tick 960 within the measure), will contain the second half note for the second staff but will contain nothing for the first staff.

That seems to be a show stopper, as that whole note is still part of the chord at that moment in time. It appears I now know why no one has ever created a Chord Names plugin to date. I'm afraid I was too wet behind the ears to think I could. Is there any way the core code could be updated on something like this?

In reply to by Tongkam

I don't understand what you mean, but think you migfht still be confused. Of course the second segment in my example contains nothing for the first staff - because there *is* nothing for first staff at that tick. If you wish to write a plugin to figure out a chord name for tick 960, it will simply be up to you to remember that there there was a chord at tick 0 (or search backwards for it). It's no different from how you'd do it looking at the actual printed score. You'd see a note on the second staff on beat 3, and nothing on beat three in the first staff. You'd have to remember you already saw a note on beat 1, or else look backwards for it. Thius isn't some arbitrary limitation of the plugin framework or the MuseScore core representation, it's just plain common sense. Which is what me think you must still be fundamentally misunderstanding something. We can't make there be something on beat 3 in staff 1 if there *isn't* anything on beat in staff 1!

In reply to by Marc Sabatella

The trouble with saving the state of the note on beat 1 for use in beat 3 is that, while it may sometimes have been a whole note on beat one, sometimes it isn't. There would be no usefulness in doing it always one way or the other, because it varies. As I look at the properties for element note, I see the following:

subchannel
line
fret
string
tpc
tpc1
tpc2
pitch
ppitch
ghost
hidden
mirror
small
play
tuning
veloType
veloOffset
userMirror
userDotPosition
headGroup
headType
elements
accidental
accidentalType
dots
dotsCount
tieFor
tieBack

None of them appears to provide a notelength, notecount, or similar property for the note itself. I could, perhaps, count the dots. So the only way I would expect to find the actual length of the note is to address its length in ticks, and if it is only a note at its first tick, that doesn't work.

In reply to by Tongkam

Those are *Note* properties. As I mentioned previously, one of the reasons for the existence of the Chord abstraction is because all notes of a chord must share the same duration, so it is the Chord object that has duration. Well, not directly, but it inherits ChordRest, which inhertis DurationElement, which provides "duration", measured in ticks.

In reply to by Marc Sabatella

Well...I guess I'm confused then. Somehow I thought a chord was made up of multiple notes, but if each note can have its own duration, and thereby be invisible at the next tick, it seems I'm back to square one. If every note in a "chord" must be of the same length, then we must deal with multiple chords even on the same staff for the same tick...and that now seems to be flying over my head. If I can't follow the logic, I can never put it to code. Obviously, we must already have to deal with multiple chords when crossing staves, and I haven't even figured out how to do that yet, much less this new complication.

Again, if someone could just tell me how to use the MuseScore objects/parameters to acquire the full chord (in layman's terms, now) for even one tick in time, maybe I could play with it from there. I have yet to see that such a thing is possible. Apparently none of the other plugins does this. Most of the plugins handle one voice at a time, but here we are talking about handling all of the voices, all of the staves, at the same time and returning a list of the notes for that "tick."

In reply to by Tongkam

A chord *is* made of one or more notes. And no, each note can *not* have its own duration. As I just wrote above, it is the *chord* that has a duration. Every note of the chord by definition has the same duration. This is not some obscure quirk of MuseScore - it's basic music notation. All notes of a chord have the same duration. So MuseScore stores in the duration in the *Chord* object, not the individual note objects, just as I explained previously. And yes, there can definitely be multiple chords on the same tick for any given staff - up to four of them. That's what multiple voices are - exactly ewhat your example shows (you have two voices per staff in your example).

I would suggest aanother read, perhaps more slowly / carefully this time, of the document I posted earier. It really should explain this stuff pretty well.

And actually, quite a few plugins look at multiple voices and multiple staves. See in particular the one that check for parallel fifths etc. It shouldn't be hard to get a list of notes for a particular tick - just move segment by segment, keeping track of the chords you find and their durations.

In reply to by Tongkam

Tongkam, hang in there. First of all, if you are familiar with JavaScript, you should be able to figure out QML eventually. It really isn't that complicated, and in fact allows you to use JavaScript function calls (the String split() function I used above is a JavaScript function).

Secondly, do some basic research on object-oriented programming and pointers (they are related concepts) - since you said you did not understand them. The basic concepts aren't that difficult, and looking at the QML code will make a lot more sense if you realize what's going on with the objects and references to them.

For example, in heuchi's code above, the variable "cursor" is a reference to a Cursor object (the Cursor class defines the Cursor object type). If you look at the documentation for the Score class in the plugin creator (? = Manual), you will see that it has a method called newCursor(), which is where you get the cursor pointer. MuseScore's implementation of QML gives you a pointer to the current Score object (curScore), so you can write code like this:

var cursor = curScore.newCursor();
var segment = cursor.segment;
var element = cursor.element;

The element is a single element on a single track. The cursor moves along from segment to segment on a single track (each track equals a voice on a staff) - cursor.next() moves to the next segment in the score, cursor.rewind(n) moves to the beginning of the selection, end of selection, or beginning of score, depending on value of n, cursor.staffIdx indicates the current staff, and cursor.voice indicates the current voice. So when you iterate through the score using the Cursor object, you can move left to right (assuming you use cursor.next()) on a single track, rewind to the beginning and set the next track, staff, etc.

If you are interested in all of the notes at a given moment of time, you can get that with the Segment object (as heuchi showed in the code above), and can ignore the cursor completely. In this case, you get the first segment of the score from the Score object (see heuchi's code). You would probably initialize the variable firstTrack = 0, and lastTrack = curScore.ntracks - 1 (notice that the Score object has the property ntracks with type int). In other words, heuchi's code stops at each segment, and then iterates down through every track in that segment, looking for every element. The if (element) {...} conditional is there because if there is no element on a track, you will get a null pointer and the plugin will crash. Since you are interested in notes and not other types of elements, you use the if (element.type == Element.CHORD) to filter for Chord objects only. But you still need to see how many notes that Chord represents - it could be as few as 1, or any other number. The Note objects are held in the Chord.notes array (also see that the property "notes" is defined in the Chord class description in the Manual).

Also note that "track" and "voice" are related. MuseScore assigns 4 voices per staff, first staff in a system has tracks 0 - 3, second staff 4 -7, and so on.

In reply to by jensm

"Secondly, do some basic research on object-oriented programming and pointers (they are related concepts) - since you said you did not understand them."

I've tried to understand them. There are times when my mind has momentarily appeared to grasp the abstract, only to return to the concrete. I honestly feel I have a mental limitation on this point. I've never truly gotten OO, references, etc., and I've given up trying, especially from text-only. If someone could explain in person, with dialogue, I might try again. I program only as a hobbyist. It is not my trade. I mostly program in Perl, and, believe it or not, I get regexp just fine. But I have the same OO limitations in Perl. It's like a glass ceiling for me. I'm not a young college student, but even if I were, I'm not sure I was ever cut out for the abstract. So I did not make my comment about not being able to work with pointers, etc. idly. I have to accept my limitation and work around it as best I can. I've actually programmed some pretty complicated stuff (in JavaScript I programmed a Sunset Calculator)....but perhaps not in the usual manner. In Perl, I frequently am forced to program my own code instead of lightening the load by using someone else's module--simply because I cannot grasp how to use the pointers and references.

"Also note that "track" and "voice" are related. MuseScore assigns 4 voices per staff, first staff in a system has tracks 0 - 3, second staff 4 -7, and so on."

Thank you. That's the first explanation I've seen of what a "track" means in MuseScore. I had never understood it until now. It would be nice if that little bit were included in the documentation in the helps for the Plugin creator (where "track" is not even listed as an element).

In reply to by Tongkam

Tongkam,
I'm attaching a very small demo that merely runs through a score and looks at every note contained in a segment. This is really stripped down - it gets the segment number, the track number, and the duration of the note (i.e., the duration in ticks represented by the Chord element's duration property) and writes to the console. Try it out with a few small example scores and see if it makes sense to you.

Attachment Size
findAllNotes.qml 1.23 KB

In reply to by Tongkam

Yes - so if you have code like: var eTrack = element.track, and eTrack evaluates to 6, then you would know your element (whatever type it is) is assigned to the 3rd voice of the second staff in a system. If you only have one staff per system in a score, then the highest track number you could get from an Element is 3.

In reply to by jensm

Thank you very much. This is great! I have hope again! This gives me a workable starting point, I think, from which I should be able to develop something. I'm learning things just from observing the output in the console. Now I might have to do the dive into qml's documentation to learn better how to handle arrays...I feel like I'm back in business. This seems possible again. Before it seemed almost like trying to operate a computer without a monitor--I had no idea where in the score I was, nor how to get what I needed from it. Thank you, thank you!

In reply to by Tongkam

"Now I might have to do the dive into qml's documentation to learn better how to handle arrays"

re: arrays - in QML, an array is called a list (you won't find "array" in the documentation). Also, according to the documentation (for v. 5.4) the size of a list is immutable. However, I have found that not to be true in the MuseScore implementation. You can do something like this:

property var noteList : []
...
function someFunction() {
noteList[0] = "A";
noteList[1] = "B";
noteList[2] = "C";
}
and you will end up with noteList ["A","B","C"]

In reply to by jensm

Yes, thank you. I've discovered most of the file is javascript, so I'm trying to use the JS standards. I'm struggling with the two-dimensional array that I need, however. I have the logic all worked out, but cannot seem to manage the syntax for the array. Sigh. Still plugging....once this array is worked out, the entire plugin is about ready.

var chordnotes = new Array(2);
      	  	chordnotes[0] = new Array(64);
      	  	chordnotes[1] = new Array(2);
                 chordnotes.push(element.duration);
                 chordnotes.push(Nname);

...That's where I'm at for creating/populating the array. But for some reason I'm getting type errors.

What I'm looking to do here is create an array something like this:

480 B
240 G
240 A
480 D

...where the two columns have tick lengths and note names respectively. The array needs to be sorted by the tick lengths, shortest first, and some other operations will be done, but that's the hardest part. I'll also need to know how to completely empty and/or reset the array.

In reply to by Tongkam

Let's walk through your code line by line:

(line 1) var chordnotes = new Array(2);

After that line you have something like: chordnotes = [ ? , ? ]
('?' means, you didn't yet set a value. Thus an array/list of size 2)

(line 2) chordnotes[0] = new Array(64);  
(line 3) chordnotes[1] = new Array(2);

After these two lines you have: chordnotes = [ [?,?,?, ... ,?] , [?,?]]
This is a list (of size 2) containing two (sub-)lists, the first one of size 64 and the second of size 2. (Note: it's not a two-dimensional array, because the second list is not of the same size as the first.)

(line 4) chordnotes.push(element.duration);

After this you have: chordnotes = [ [?,?,?, ... ,?] , [?,?] , element.duration]
This chordnotes now has size 3 and that's probably not what you wanted to do.

To create an array as shown in your sketch, you need to add note durations to chordnotes[0] and notenames to chordnotes[1].
Note: You don't have to specify a size when creating a new array in QML, so it's fine to just write:

chordnotes = [];
chordnotes[0] = []; // for length
chordnotes[1] = []; // for notename

And to add a note:

chordnotes[0].push(element.duration);
chordnotes[1].push(Nname);

Now, you can get the duration of the first note in the list by chordnotes[0][0] and the name by chordnotes[1][0]. Or, to get the duration of the nth note in the list use chordnotes[0][n] and for the name chordnotes[1][n]. Here we have a two-dimensional array.

I don't know if there is an easy way to remove an element at the beginning of such a list/array. But you can remove the last one with chordnotes[0].pop() and chordnotes[1].pop().

In reply to by Tongkam

Hmm - not sure why you'd be getting type errors; is element defined somewhere in your code?

Also, I think your code should be:

var chordnotes = new Array();
chordnotes[0] = new Array();
chordnotes[1] = new Array();
chordnotes[0].push(element.duration);
chordnotes[1].push(Nname);

otherwise chordnotes will look something like [,,,,,,,,,,,,. . . , element.duration, Nname, element.duration, Nname, . . .] (i.e., 66 undefined array members followed by alternating duration and name elements).

Assuming the push() calls are inside a loop.

[edit] I see that heuchi beat me to it, and his is even better (no need for the new Array() syntax).

In reply to by jensm

Ok. Back to cursor problems.

I've got chords working (though they'll definitely need some adjustments still). But I cannot print the chord title to the score. I don't have a cursor element, and apparently the segment element has no attachment to the text. So, am I stuck all over again between a rock and a hard place? Or is this solvable? The script you started me with was fabulous, and works just fine without a cursor. But now it appears that the cursed cursor is a precursor to success. So much for a cursory result.

In reply to by Tongkam

I came across the very same problem (add a text to the top(!) staff at a given segment position), and I didn't find anything easier than to create a new cursor, advance it to the same position in the score as the segment I have (same tick value) and then use the cursor to add the text. It's maybe not very elegant, and certainly not fast, but it seems to work... ;-)

So I created a function that can be called like this: addText("Text",segment.tick);

If there's no note or rest in any track at the given point in the score, the function will not find a valid cursor position and don't add the text, i.e. fail silently.

      // add a staff text element to the top staff at given tick
      // with given text
      function addText(text,tick) {
            var cur = curScore.newCursor();
            var myText = newElement(Element.STAFF_TEXT);
            myText.text = text;
          
            // find a track with a segment at given tick
            var track;
            for (track = 0; track < curScore.ntracks; track++) {
                  cur.track = track;
                  cur.rewind(0);
                  // advance to tick
                  while (cur.segment && cur.tick < tick) {
                        cur.next();
                  }
                  // found tick?
                  if (cur.segment && cur.tick == tick) {
                        // reset to top staff and write text
                        cur.track = 0;
                        cur.add(myText);
                        break;
                  }
            }
      }

In reply to by heuchi

Tongkam, I'm finding out that QML is quite versatile and flexible. Here's an idea for you: instead of trying to manipulate a 2d array, why not take advantage of the ability in QML to create objects on the fly. For example, you can easily create items with properties like this:

var Nname = "A"; //string
var duration = 10; //int
var noteInfo = { "name" : Nname, "duration" : duration };

Each key/value pair inside the { } is a property name followed by its value. You can then access the properties using dot notation:
noteInfo.name, noteInfo.duration

Your code would amount to something like this:

//create the array
property var hashArray : []

//add values to the array (inside a loop, for example, with index i)
hashArray[i] = {"name" : Nname, "duration" : duration};

//sort the array
hashArray.sort(function(a,b){return a.duration - b.duration});

//access array members
var myDuration = hashArray[i].duration;
var myNname = hashArray[i].name;

Edit: note - you can remove the first element of the array using hashArray.shift(), and empty / reset the array using hashArray = []

In reply to by heuchi

I seriously would have used that new sortable hash system if I hadn't already come super close to figuring out a solution. In the end, I avoided having to sort the two-column array, so I didn't end up needing that extra complexity. It required only an iteration through the array to pull out the relevant values and find the smallest one. That's all I really needed.

I was missing the capability of perl while I was doing that...had to revert to a non-perlish way of programming that I hadn't done in a long time.

Has anyone tried the plugin yet? I'd be interested in your opinion/experience with it.

In reply to by Tongkam

I just did, not bad at all, a few observations though:
- some chords are named twice and differently like A and D, A and Bm7, Bb and C, B and Gbm, A end E.
- "M" should rather be "Maj", shouldn't it?
- the plugin always works on the entire score, not on a selection if there is one.
- apparently no attempt is make to detect inversions (term?), like D/F# or F/A

In reply to by Jojo-Schmitz

It's stuff like that that I may need help with at this point, I think. I'm not a music expert. I play accordion, and my accordion only has major, minor, 7th, and diminished. I'm not a guitarist, so I don't have much knowledge of the other chords. I just found a list of chords online, and went by that.

What I did was create a list of C chords, then transposed those to every other possible key, as best I could.

Here's the list of chords I used:


our @chorddata_sortlarge = (
'Caug11 C Augmented 11th C, E, G, B♭, D, F♯ ',
'CM9 C Major 9th C, E, G, B, D ',
'C7/6 C Seven Six C, E, G, B♭, A ',
'Cm6 C Minor 6th C, E♭, G, A ',
'C6 C Major 6th C, E, G, A ',
'CM7 C Major 7th C, E, G, B ',
'CM9 C Major 9th C, E, B, D ',
'Cadd9 C Add9 C, E, G, D ',
'C7 C Dominant 7th C, E, G, B♭ ',
'Cm7 C Minor 7th C, E♭, G, B♭ ',
'Cm9 C Minor 9th C, E♭, B♭, D ',
'Cdim7 C Diminished 7th C, E♭, G♭, A ',
'C7sus4 C 7th Suspension 4 C, F, G, B♭ ',
'C C Major C, E, G ',
'Cm C Minor C, E♭, G ',
'Cm6 C Minor 6th C, E♭, A ',
'C6 C Major 6th C, E, A ',
'C+ C Augmented C, E, G♯ ',
'CM7 C Major 7th C, E, B ',
'C7 C Dominant 7th C, E, B♭ ',
'Cm7 C Minor 7th C, E♭, B♭ ',
'Cdim C Diminished C, E♭, G♭ ',
'Cdim7 C Diminished 7th C, E♭, A ',
'Csus C Suspended C, F, G ',
'Csus C Suspended 2 C, D, G ',
'C C Major C, E ',
'C C Major C, G '
);

You'll notice that the more complex chords are listed first. There's a reason for that. If it's not one of them, then it looks for a simpler chord.

NOTE: If you have chords that you would suggest be added to this list, just give me their C-key components, as is done for those others in the list, and I can add them in quite easily at my end. I may be breaking some rules with the music, but I've also attempted to accommodate the equivalences of, for example, C# and Db. If a chord is a basic one which includes the note represented by either C# or Db, it should be labeled as that chord.

In reply to by Jojo-Schmitz

So, I guess the next question is, how practical vs. accurate should the plugin be? In practice, I would never want to see something like C13#11 on my score as a chord. It might represent precise music theory, but it would be something only a college music grad would easily read. (Consider I'm in a third-world country where everyone plays folk songs on guitar with only their older brother, uncle, or second cousin to help them learn.) If we put "Maj" instead of "M", it also lengthens the notation. The longer the notation, the more stretch the score will be forced to have to keep the chords from overlapping each other. For my purposes, concise is better.

What do you think most people would want to use the chords for? If we're talking about the average person on a guitar or instrument, I don't thing the more complex chords are necessary, or even desirable. If we're talking about piano teachers and music majors, anything less than the best and most precise may offend.

My personal reason for doing this is that I would like to compile a book of several hundred or more songs, and include guitar chords for each. For my purposes, the plugin already suits me. But I'm willing to tinker more with it and add what people think might be the best.

In reply to by Tongkam

I'd challenge a couple of your assumptions here. First, C13#11 is not "something only a college music grad would easily read". It's more of a genre thing - chords like this are an absolutely integral part of the jazz language, but probably less common in other styles. On the other hand, even in jazz, there is a danger of overspecifying chords.

Basically, there is no universal answer, no single best way of representing what you see as a chord symbol.

BTW, the downside - and it's a serious one - of using "M" for major chords rather than, well, just about anything else is that it is not always on first glance if one is seeing "M" or "m". That is why most major publishers have abandoned these abbreviations. The standard these days in the jazz world is ma & mi; publishers in other genres tend to use other standards. If you want to avoid misunderstandings, I can speak from extensive personal experience is recommending you *not* make the mistake of asking players to figure out the difference betwene "m" and "M". Especially if you don't see them side by side, it's just often hard to be sure. And if your use case is folk songs on guitar, surely the chords aren't actually changing so often so that extra space is a problem? That tends to be the case only in very dense music with lots of complex chords.

In reply to by Marc Sabatella

Perhaps the plugin needs to be more user-configurable, to fit personal preferences and styles based on usage requirements. What would you suggest? If you were the one making the plugin, what would you see as its best standard of practice, as it were?

I'm completely open to suggestions. I gave my preferences as a means of promoting understanding. I just entertained a gentleman in my home a few weeks ago who is studying music theory. He taught me a few chords, but I must say his knowledge of music theory trumps mine by a long shot.

I'm more of a hobbyist programmer than either a music aficionado or professional programmer. But I like to make things useful to people, so when I program, I often enjoy adding features. I'm not sure how to do it yet with a plugin like this...which is why I'm open to suggestions.

In reply to by Tongkam

If I had a good answer, I'd have already written a plugin like this :-). The problem of algorithmic harmonic analysis is a very big and many-faceted one. That is the real reason, I think, why no such plugin exists already. The reality is, it takes an enormous amount of sophistication to contextualize what you are seeing and understand what the harmonic rhythm is (eg, when the chord is actually changing), what notes to consider non-chord tones and what notes to consider essential to the harmony etc.

So I'd say, do whatever works for you right now and enjoy using it, and the world is a big enough place that probably there are others who will find whatever choices you make useful as well. But it's also a big enough place that it's unlikely it would serve everyone's needs no matter how hard you tried. Better to solve a narrowly-defined problem well, I think, than to solve a too-broadly-defined problem poorly.

In reply to by Marc Sabatella

Well, I'll give it a little thought, and may tweak the chords some before submitting an official version of the plugin. Which category do you think it fits best?

Chord symbols
Composing tools
Other

??

I don't see these as being exactly chord symbols, but they might fit that general category.

Thank you for your helpful comments here that got me past the initial curve--and my apologies for the early pessimism I went through in feeling as if this were not actually doable. I'm very happy to have something that will work this well for my purposes.

In reply to by Jojo-Schmitz

That list is confusing. There are multiple chords with divergent nomenclature. For example, which is the following?

C Eb G#

Is it Cm+ or is it Cm#5? Both names are in the list, but their voicings are identical. My preference would always be the shortest expression, in this case Cm+. But the fact that duplicates are here in the list illustrates a basic problem. There's more than one name per chord.

Another issue presents with chords that lack one of a fuller set. For example, either of the following might be considered to be Cm6:

C, E♭, G, A
C, E♭, A

Is it necessary to adjust the chord names so that there are no ambiguities like this? Would it be substandard or unsightly to do so? For example, consider:

Cm6 vs Cm6-5

I'm inclined, again, to just keep it simple: Cm6 for both in this case. Anyone have thoughts or preferences on these things?

Consider also:

CMaj6+9 (C Major 6th add 9) C, D, E, G, A
CMaj7Lyd C, D, E, G, A [and I don't know what "Lyd" is supposed to me]

How can a Maj7 and a Maj6+9 be the same?

In reply to by Tongkam

C Eb G# is not really a normal chord. If it were Ab, it would be - an Ab major chord in first inversion. But it is important to realzie thast there is no always a single clear unique name for every random combination of notes. Any two professional musicians might disagree on what to call certain combinations of notes, and in their thinking about it, they wouldn't just be looking at the notes themselves but the surrounding context.

But I can say Cmi6 is definitely wrong - that would be C Eb G A.

"Lyd" is short fot "lydian", and really should include a #4 (F# for CLyd). Not sure where the definition you posted comes from; it doens't really make sense.

In reply to by Marc Sabatella

The definitions for those chords came from the chords.xml that Jojo-Schmitz posted above. Take a look at that, perhaps, and tell me if it's worth incorporating into the Chord Names plugin. I've already started incorporating it, though. Again, I'm no expert, so I have little ability to see mistakes in a list such as that. I either assume it's authoritative, and use it, or someone tells me otherwise.

In reply to by Jojo-Schmitz

Well, I got all of those chords entered in, found a few anomalies (which for now I've not entered them all in), and now have over 4000 lines of code just for the chord identification function. It crashes MuseScore. I'm not sure why is should actually crash the program. It seems like decent code to me, just one line at a time, and the only memory requirement would be loading the code itself. The code would not require much memory when running. If the plugin were simply processed line at a time, it should function beautifully.

In any case...it doesn't. I'm going to tinker with it some more, and meanwhile, here are the chord anomalies that I managed to find:

NOTE: [Trying again with that in a new post as for some reason it won't display here....]

In reply to by Tongkam

C7sus♯5♯11:	C F A♭ B♭ 
C7sus♯5♯11:	C F G♯ B♭ F♯

Cdim7:	C E♭ G♭ Bbb
Cdim7:	C E♭ G♭ A

Cdim7add♯7:	C E♭ G♭ Bbb
Cdim7add♯7:	C E♭ G♭ A

C2 = Cadd2 = Cadd9

CPhryg:	C D♭ E♭ F G B♭
CPhryg:	C E F♭ G B♭ D♭

C7♭9	C: E G B♭ D♭
C7♭9♯9:	C E G B♭ D♭

CMaj13:	C E G B D F♯ A	
CMaj13♯11:	C E G B D F♯ A

(Note: It seems the double flat character cannot display here, and cuts the post short...so I've exchanged those with "bb".)

In reply to by Tongkam

I don't quite get what you're tying to say here?
The 1st C7sus#5#11 looks wrong to me, needs one note more and the G# rather than the Ab
A Cdim7 and a Cdim7add#7 are surely not the same chords, same for C7b9 and C7b9#9, the 2nd of these pairs should have one note more than the 1st?
And CMaj13 vs. CMaj13#11 should differ in whether they have an F or an F#?

In reply to by Jojo-Schmitz

Yes, I'm just presenting what I found in the files you posted. I'm not expert enough to know which one of each pair is correct. I'll try to update per your instructions here, but when you say "one note more," I'm simply too ignorant to know which note is missing. I was only able to notice the similarities or dissimilarities in some chords that seemed anomalous. I don't know what their correct forms are. Thank you for your assistance.

In reply to by Tongkam

Ah, I see. Well, I'm not an expert here either and my files are by no means meant to be authoritative...

More details (to be taken with a large grain of salt):

The 1st C7sus#5#11 looks wrong to me, needs one note more (the #11 -> F#) and the #5 -> G# rather than the Ab, so just look like the 2nd.

A Cdim7 and a Cdim7add#7 are surely not the same chords, same for C7b9 and C7b9#9, the 2nd of these pairs should have one note more (the add #7 -> A#?) than the 1st

With thanks to all of the help here, and I honestly don't know whom to attribute and/or appreciate in the names attached to this code (supply me with your actual names and I'd be happy to add them), here is the script as it stands now. I _think_ everything is working. There are three possible settings for marking the chords, adjustable from within the script via two main variables: 1) Mark every possible chord, regardless; 2) Mark each repeated chord at least once per measure; and 3) Mark only chord changes as they occur in the score (default at present).

I'm sure as you experts look at the code, you may have ways of improving it, and/or even find bugs. NO GUARANTEE is made regarding the accuracy of the output, and/or that every chord will be matched. If a chord is not recognized, it is skipped (no name given).

Thank you all again, and any word from the experts as to how this should be submitted to the proper place(s) when verified to be working would be appreciated.

Attachment Size
ChordNames.qml 145.46 KB

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