Closed ice6 closed 4 years ago
i believe that OSMD itself used a DOMParser to read the musicXML, and I am prepared to do the same. And I would like to convert our transpose_xml routine to use it if we can get it to work properly.
Can you create a small sample .htm which uses DOMParser to read a MusicXML file and the allows access to it in the Document.
And can you add the opposite function to take the parsed MusicXML file and turn it mack into a XML string which I could then save to disk, etc.
When I tried this last time - about 6 months ago, I ran into a problem. I beleive it was that items with attributes, (e.g. default-x="294.17"), like this:
<note default-x="294.17" default-y="-30.00">
<chord/>
<pitch>
<step>B</step>
<alter>-1</alter>
<octave>2</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>eighth</type>
<stem>up</stem>
</note>
<note>
were either difficult to get data from, or did not convert back to an XML string properly.
So see if you can create a small .html to test this.
OK, I will write one
This looks promising.
Let me see what it would take to make it work for us.
[edit] I am able to do lots of good things with this, but have added some comments here that I could really use help with,
In this line:
const transposedRest = this.transposePitch(stepElem.innerHTML, 0, +octaveElem.innerHTML);
Does the unary plus operator, (+), in "+octaveElem.innerHTML" do anything.
Perhaps it forces the innerHTML to be converted to a number, the same as "Number(octaveElem.innerHTML)"?
If that is the case, I think I'll continue to use Number(octaveElem.innerHTML) because it easier to read in the code.
If you get a chance, see if you can fix the logic for adding a new
Item FIxed
[EDIT: I am able to use 'sub_element.remove();' to remove elements I no longer want.]
alter in pitch should be added if it was not there already. I know how to do that.
But if the new alter is 0, alterElem should be removed.
const transposedNote = {octave: 3, step: 'C', alter: 1, accidental: 'flat'}
octaveElem.innerHTML = transposedNote.octave;
stepElem.innerHTML = transposedNote.step;
alterElem && (alterElem.innerHTML = transposedNote.alter);
So if alterElem was found, but the transposedNote had "alter: 0", how would I remove the old alterElem?
Item FIxed
[EDIT - this thing to use here was: 'getAttribute("number")' ]
// <beam number="1">end</beam>
beam_number = beam_element.getAttribute("number");
Your example did not show how to read xml attributes such as "default-x", as in:
<note default-x="294.17" default-y="-30.00">
<chord/>
<pitch>
<step>B</step>
Item FIxed
Nested items
Your sample, had a NOTE and processed everything in the NOTE.
But when I pass a more complete score, like the one below, it finds the
Can you figure out how to get the "while (target = stack.pop()) {" loop to loop through and process everything.
If the "while" loop passes everything to the switch statement, then I can grab just the things I want._
"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="3.1">
<work>
<work-title>2 notes</work-title>
</work>
<identification>
<encoding>
<software>MuseScore 3.4.2</software>
<encoding-date>2020-05-25</encoding-date>
<supports element="accidental" type="yes"/>
<supports element="beam" type="yes"/>
<supports element="print" attribute="new-page" type="yes" value="yes"/>
<supports element="print" attribute="new-system" type="yes" value="yes"/>
<supports element="stem" type="yes"/>
</encoding>
</identification>
<defaults>
<scaling>
<millimeters>7.05556</millimeters>
<tenths>40</tenths>
</scaling>
<page-layout>
<page-height>1584</page-height>
<page-width>1224</page-width>
<page-margins type="even">
<left-margin>56.6929</left-margin>
<right-margin>56.6929</right-margin>
<top-margin>56.6929</top-margin>
<bottom-margin>113.386</bottom-margin>
</page-margins>
<page-margins type="odd">
<left-margin>56.6929</left-margin>
<right-margin>56.6929</right-margin>
<top-margin>56.6929</top-margin>
<bottom-margin>113.386</bottom-margin>
</page-margins>
</page-layout>
<word-font font-family="FreeSerif" font-size="10"/>
<lyric-font font-family="FreeSerif" font-size="11"/>
</defaults>
<credit page="1">
<credit-words default-x="612" default-y="1527.31" justify="center" valign="top" font-size="24">2 notes</credit-words>
</credit>
<part-list>
<score-part id="P1">
<part-name>Piano</part-name>
<part-abbreviation>Pno.</part-abbreviation>
<score-instrument id="P1-I1">
<instrument-name>Piano</instrument-name>
</score-instrument>
<midi-device id="P1-I1" port="1"></midi-device>
<midi-instrument id="P1-I1">
<midi-channel>1</midi-channel>
<midi-program>1</midi-program>
<volume>78.7402</volume>
<pan>0</pan>
</midi-instrument>
</score-part>
</part-list>
<part id="P1">
<measure number="1" width="361.76">
<print>
<system-layout>
<system-margins>
<left-margin>0.00</left-margin>
<right-margin>748.85</right-margin>
</system-margins>
<top-system-distance>170.00</top-system-distance>
</system-layout>
</print>
<attributes>
<divisions>1</divisions>
<key>
<fifths>0</fifths>
</key>
<time>
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<note default-x="79.27" default-y="-25.00">
<pitch>
<step>A</step>
<octave>4</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note default-x="215.22" default-y="-15.00">
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
<stem>down</stem>
</note>
<note>
<rest>
<display-step>D</display-step>
<display-octave>5</display-octave>
</rest>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<barline location="right">
<bar-style>light-heavy</bar-style>
</barline>
</measure>
</part>
</score-partwise>
Item FIxed
AHA! I found my parsing problem.
[EDIT But for things like notes in measures, I am using. element.children to get an array of child elements, and then looping through them:
let measure_children = measure_object.children;
console.log("CHILDREN: %s", measure_children.length);
// let's mark chords
// a note is in a chord if the second note element, and subsequent are marker chord
for (let ii = 0; ii < measure_children.length; ii++)
{
let measure_child = measure_children[ii];
console.log("measure CHILD %s: %s", ii, measure_child.tagName);
switch (measure_child.tagName)
The "continue" at the end of the "switch 'NOTE'" means "continue and don't parse any child elements. Because they are already processed"
So for 'MEASURE', I just need to remove the continue - which will then cause the child elements, like 'NOTE' and 'ATTRIBUTES' to be parsed by the switch.
I'll try that and add a comment here it that works for me.
Item FIxed - using insertAdjacentElement
Insert a new element in front of an existing element.
If the original xml looks like this:
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
And I translate from C to Eb, I want the new xml to look like this. with alter in front of octave.
<pitch>
<step>E</step>
<alter>-1</alter>
<octave>5</octave>
</pitch>
You used code like this, which appends 'alter' at the end of 'pitch'. I want to insert it after step. Can you help with the insert code?
octaveElem.innerHTML = transposedNote.octave;
stepElem.innerHTML = transposedNote.step;
alterElem && (alterElem.innerHTML = transposedNote.alter);
if (!accidentalElem) {
accidentalElem = document.createElementNS('', 'accidental');
pitchElem.appendChild(accidentalElem);
}
<pitch>
<step>E</step>
<alter>-1</alter>
<octave>5</octave>
</pitch>
Item FIxed
I'll give these two functions a try...
Insert After
It looks like I can insert the new element after a specific element using "insertAdjacentElement("afterend", s)"
let h = document.getElementById("myH2");
h.insertAdjacentElement("afterend", s);
Remove Element
It looks like I can remove an element with remove()
let myobj = document.getElementById("demo");
myobj.remove();
:+1: I am working on my company's project nowadays. It is great to see the progress you have made.
The lastest version uses DomParser() to read the XML file, and does not try to read the ASCII XML file.
After reviewing @leo6140 's wonderful work, I'd like to share my though.
We saw the possibility that
DOMParser
&Document
works quite well for transposing.We can get the transposed musixml text from the Document.
We use comparision tool like
araxis merge
to test the function currently, after migrating to DOMParser & Document & TypeScript, we need another way to test this routine.We can upload some files transposed by other mature software like MuseScore or Finale, and compare with them automatically. We need a way to identify what is the equalness(function equivalence).
:)