Closed infojunkie closed 3 years ago
Output MusicXML harmony elements - noting that their specification is pretty close to your approach
To be clear, I am not requesting to output a MusicXML text string: a JSON structure that contains the equivalent info is much more useful.
In the coming days, I will be attempting to replace my handmade chord handling with your module and will provide more specific feedback here.
Hello!
Looks like the perfect match indeed đ Thanks for the kind words. Your project is a cool one and I'll be glad to help ;)
The parsing mostly works out of the box. I've added all iReal Pro symbols to the unit test suite and most were already there under a different variation: https://github.com/no-chris/chord-symbol/pull/322/files
I'm just unsure about 2 of them:
C^
as identical to C^7
? If so I need to fix the ^
modifierC-b6
I'm really not sure about that one... if you have all the iReal Pro chords sheets somewhere could you check if it is widely used? I'm afraid that one is against all rules :p Now for the output imho it should belong to its own repo as a custom filter for chord-symbol renderer. That way it would be a generic feature available for other to use. Something like:
import { chordPaserFactory, chordRendererFactory } from 'chord-symbol';
import { musicXmlRenderer } from 'chord-symbol-music-xml';
const parseChord = chordParserFactory();
const renderChord = chordRendererFactory({
customFilters: [musicXmlRenderer],
printer: 'raw'
});
const chord = parseChord('C^7'); // some iReal Pro chord symbol
console.log(renderChord(chord)); // <- the Music XML Json object
What musicXmlRenderer
would do is build the Music XML Json representation from the internal chord-symbol one. It could completely replace it or just add a new property (chord.musicXml
for ex).
I haven't checked all details of the harmony object but I see multiple cases:
function
, for example). I'm happy to add it to the core lib.musicXmlRenderer
rendererWhat do you think of this approach?
Thanks for your helpful reply!
do you understand C^ as identical to C^7? If so I need to fix the ^ modifier
I just tested on iReal Pro, and yes they play the same.
C-b6 I'm really not sure about that one...
It exists among the available iReal Pro chord qualities, and it seems to be a known chord - so it sounds legit to me. It's just a C- with an added b6 if I understand correctly.
Regarding MusicXML:
Now for the output imho it should belong to its own repo as a custom filter for chord-symbol renderer.
I would argue that since MusicXML is a W3C standard, it would make sense to include this filter in the main repo.
Otherwise, yes, the API makes sense to me - adding a chord.musicXml
attribute sounds great.
I will have more to say about the specifics of the proposed MusicXML filter when I work on the integration.
Thanks again!
I've indeed seen C-b6
in the real book. Even though it seems more logical to use AbMaj7/C
, the reason for this flat sixth was the chord progression:
| C- C-^7 | C-7 C-6 | C-b6 A-7(b5)| ...
Ă
@infojunkie Good idea! Do you use Musescore or something after the conversion to play your musicxml files or are you crafting an accompaniment generator?
Do you use Musescore or something after the conversion to play your musicxml files or are you crafting an accompaniment generator?
@Marr11317 both, actually: I use MuseScore to validate and edit the generated MusicXML (e.g. to add the melodic head), then I plan to use the finalized MusicXML with a combination of OSMD, MMA, and a Web MIDI player to reach a playable version including accompaniment. That's the medium-term plan at least :sweat_smile:
do you understand C^ as identical to C^7? If so I need to fix the ^ modifier
I just tested on iReal Pro, and yes they play the same.
Right. So I'll fix it and I guess Î too.
the reason for this flat sixth was the chord progression
Got it. So we need support for it as well. But then I assume the 5
would be left out of the chord correct?
I will have more to say about the specifics of the proposed MusicXML filter when I work on the integration.
Great! Let us know about the progress. At some point could you post a sample of the JSON harmony object to get an idea of the missing information?
But then I assume the
5
would be left out of the chord correct?
Not sure about that. Let me ask someone more competent, but I think technically the 5th should be there even if the pianist may decide to omit it (like he does for other fifths). I would simply render C-b6
exactly like `AbMaj7/C', so including the G.
(In my book, that's the difference between a b6
and a #5
: the b6
should contain the 5th.)
I just pushed a branch where I use chord-symbol
instead of my handmade chord parsing. Here's the relevant function. Some comments based on this experience - please forgive my ignorance / misunderstandings:
Specification differences in chord quality:
dominant-ninth
, dominant-11th
, etc. These are expressed as dominant7
+ extensions in chord-symbol
. suspended-fourth
is represented by isSuspended
in chord-symbol
independently of chord quality suspended-second
is represented as a chord with alterations in chord-symbol
half-diminished
is converted to a minor b5 chord in chord-symbol
chord-symbol
are missing from MusicXMLMapping of extensions and alterations to harmony/degree
: All degree changes are expressed via the degree
element in MusicXML. This leads to some uncertainty in the mapping, especially when a degree appears in both extensions
and alterations
, e.g. "D13#5#9".
chord-symbol
API comments:
alterations
, not in adds
? The original "Ab" has no 11 extension. I would have expected alterations
to only affect degrees that exist in the chord's quality + extensionsalt
in alterations
. Would be great to spell out the actual degrees there.isSuspended
to distinguish between sus4 and sus2 I hope this is constructive enough to continue this conversation :pray: Thanks!
* How come "Ab(add b9,#11)" shows #11 in `alterations`, not in `adds` ? The original "Ab" has no 11 extension. I would have expected `alterations` to only affect degrees that exist in the chord's quality + extensions
If I recall correctly, that is standard jazz notation: #11 is always an extension. Do you mean that because it's "Ab(..." and not "Ab7(..." it should be considered an addition?
Do you mean that because it's "Ab(..." and not "Ab7(..." it should be considered an addition?
Right: Ab has only a major triad. Even Ab7 is triad + dominant 7, which still does not contain the 11 extension. Of course, I'm approaching this not from a musician's convention, but from a consistency point of view. So the "notation" part is less relevant than the "structural" part.
what is an alteration for you if they exist only to replace additions?
Does that mean that in G11(#11)
the 11 would be adding two extension: 9 and 11, and then the #11
would alter the existing 11th?
Does that mean that in G11(#11) the 11 would be adding two extension: 9 and 11, and then the #11 would alter the existing 11th?
Your specific example does not work at https://chord-symbol.netlify.app/, but G13(#11) works, and it does not show the 11 in the extensions. I would have expected it to show there, as per my argument that
I would have expected alterations to only affect degrees that exist in the chord's quality + extensions
To be precise, I don't expect alterations to show for additions, but for extensions and for the degrees in the core quality. It's not a big deal, btw, since practically my code needs to loop on all those arrays :-)
Many thanks for the investigation and the great feedback! đ
Not sure how to handle the qualities conversion. My first intuition would be to build something like: https://github.com/no-chris/chord-symbol/blob/802cbb326ee29a902b466d58fb19c6b0765694ef/src/parser/filters/normalizeDescriptor.js#L131
In order to do that you need a "straight", or "unaltered", version of the chord, which could totally be part of the chord-symbol object since I'm already building that information in the referenced filter above. Then the degrees would be built by looping over the alterations, as you are already doing.
I have the feeling this would be a more robust approach than deriving MusicXML chord qualities from a mix of chord-symbol qualities and extensions/alterations.
I can quickly add this information to an experimental branch, if that makes sense?
How come "Ab(add b9,#11)" shows #11 in alterations, not in adds ? The original "Ab" has no 11 extension. I would have expected alterations to only affect degrees that exist in the chord's quality + extensions
I think I see your point. I need to dig a bit in my supporting literature to find out if this has some kind of background or if it is just an inconsistency with Cb13
and Cb9
Altered chords show as alt in alterations. Would be great to spell out the actual degrees there.
Alt chords are a special case, since the alterations themselves are configurable. You can easily reconstruct that information based on the parser configuration object: https://github.com/no-chris/chord-symbol/blob/master/API.md#AltIntervals
Would be great to return an explanation when a chord fails to parse
đ
I suggest adding a parameter to isSuspended to distinguish between sus4 and sus2
I knew this topic would come up at some point but Mark Harrison makes it very clear that there is no such thing as a suspended2
chord. Since the usage is so widespread (it even made it to MusicXML đ), maybe we could register a sus2
intent to allow building the MusicXml quality, for example.
what is an alteration for you if they exist only to replace additions?
Does that mean that in
G11(#11)
the 11 would be adding two extension: 9 and 11, and then the#11
would alter the existing 11th?
In my understanding that would have been the case, and prior to adding the interval consistency filter this is probably what chord-symbol would have yield.
What's interesting is that #11
comes out as an add
if the chord is minor Cm(#11)
so there is definitely some logic behind this, that I don't remember. Same thing with Cb13
vs Cm(b13)
https://github.com/no-chris/chord-symbol/blob/802cbb326ee29a902b466d58fb19c6b0765694ef/src/parser/filters/normalizeDescriptor.js#L271
In that case the alterations relates to the scale and not the chord extensions.
In order to do that you need a "straight", or "unaltered", version of the chord, which could totally be part of the chord-symbol object since I'm already building that information in the referenced filter above. Then the degrees would be built by looping over the alterations, as you are already doing. I have the feeling this would be a more robust approach than deriving MusicXML chord qualities from a mix of chord-symbol qualities and extensions/alterations.
My code which is referenced above does not attempt to recreate the "missing" chord qualities from further examination of the alterations: I only map what chord-symbol
returns to the MusicXML equivalent. I was just highlighting the differences for you to decide whether you want to enlarge the set of qualities (e.g. to include half-diminished, dominant9, etc.) or if you think that your set is "more correct" than MusicXML's. I have no strong opinion either way, but it seems that MusicXML defines "quality" differently than you do.
Regardless, though, I think it's important to keep extensions
, alterations
, adds
and omits
consistent so that any downstream application such as mine can rely on them for further processing. Specifically, to clearly define the logic behind each array, to resolve the apparent inconsistencies discussed above.
maybe we could register a sus2 intent to allow building the MusicXml quality, for example.
More info about the sus2 "controversy" on Stack Exchange. Yes, an intent would be fine. Would you consider a half-diminished intent too? Assuming it's not a legit quality.
Alt chords are a special case, since the alterations themselves are configurable. You can easily reconstruct that information based on the parser configuration object
Yes, that's what my code does - I was commenting from the pov of a user of your API, how this is an additional complexity to keep in mind and that will probably make its way into every client code.
Most immediately, recognizing "^" and "-b6" chords will allow me finalize the chord-symbol
integration. Next step may be to move my chord-symbol
conversion function to a filter in your repo. Or we can keep the status quo and go about the rest of our lives :joy:
Thanks!
My code which is referenced above does not attempt to recreate the "missing" chord qualities from further examination of the alterations: I only map what chord-symbol returns to the MusicXML equivalent.
Is that enough for your use case?
I was just highlighting the differences for you to decide whether you want to enlarge the set of qualities (e.g. to include half-diminished, dominant9, etc.) or if you think that your set is "more correct" than MusicXML's. I have no strong opinion either way, but it seems that MusicXML defines "quality" differently than you do.
Just to be clear I do not define anything here đ As stated in the readme qualities definitions are based on Mark Harrison's body of work (https://www.harrisonmusic.com). MusicXml use a different approach, which might be as valid a his, but switching the approach would represent a significative amount of work that I'm not sure would make sense đ
Regardless, though, I think it's important to keep extensions, alterations, adds and omits consistent so that any downstream application such as mine can rely on them for further processing. Specifically, to clearly define the logic behind each array, to resolve the apparent inconsistencies discussed above.
I definitely agree there.
Would you consider a half-diminished intent too? Assuming it's not a legit quality.
Half-diminished is really mi7(b5)
. An intent would allow to render Ch
as CĂ
(for ex) and Cmi7(b5)
as Cmi7(b5)
but that defeats a bit the purpose of normalisation. I would consider this "user preferences" to be handled by custom filters, which are basically made for this kind of use cases. Here you could test the intervals array against 1
, b3
, b5
, b7
and set the quality as you prefer.
Most immediately, recognizing "^" and "-b6" chords will allow me finalize the chord-symbol integration.
That has made it to the todo list for v1.2.0
đ https://github.com/no-chris/chord-symbol/projects/4
No ETA, though, but feel free to contribute if you feel like it đ
Next step may be to move my chord-symbol conversion function to a filter in your repo.
I would love that! â¤ď¸
Is that enough for your use case?
I think so - for my current purposes, I care about rendering the right chord, even if its metadata are a bit off.
[..] but switching the approach would represent a significative amount of work that I'm not sure would make sense
Understood. Since you seem interested in the ontological aspects of music theory, I encourage you to lurk or participate in the W3C music notation community - that's where MusicXML and its successor / competitor MNX are being designed and discussed.
[..] I would consider this "user preferences" to be handled by custom filters
Makes sense. In that case, though, it would be good to also clearly define what the intents
array means and is expected to hold.
That has made it to the todo list for v1.2.0
:tada: I will first reach an alpha version of ireal-musicxml
before I work on merging chord-symbol
. Hope I can contribute!
Next step may be to move my chord-symbol conversion function to a filter in your repo.
I would love that!
Sounds great. Thanks for your cooperation!
from the API documentation:
[the intent object] keeps track of intents that are part of the symbol but cannot be conveyed by the interval list only
definitely could use some refinements
đ
The v1.2.0
branch has b6
parsing as well as correct parsing for ^
/Î
modifiers.
If you could test it locally before release that would be amazing đ
Thanks! đ
Just ran my branch https://github.com/infojunkie/ireal-musicxml/tree/chord-symbol against your v1.2.0
branch and it passes :raised_hands: - it is currently failing on Travis against your latest official release. Thanks!!
v1.2.0
is released đ
Merged my working chord-symbol
branch into main
. Thanks so much for your cooperation :pray:
Fyi, to convert the chord-symbol
output to something that MusicXML can deal with, I've had to write some non-trivial code. If you are still interested, we can cooperate on turning it into a filter.
Yes that is interesting. I'll look into it once I'm done with the error handling.
Hello!
Your module looks fantastic, and it's great that you are basing your work on solid literature. I am working on a leadsheet converter from iReal Pro to MusicXML, and I'm currently hand-parsing the iReal Pro chords, and hand-generating the MusicXML chords.
Since your module seems so, um, modular, it looks like a good candidate to replace both these functions in a coherent whole. I'm thinking specifically of the following:
harmony
elements - noting that their specification is pretty close to your approachThanks!