Skip to content

Commit

Permalink
Generalize clef handling
Browse files Browse the repository at this point in the history
  • Loading branch information
th-we committed Jan 13, 2017
1 parent d1d3192 commit 3601004
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 34 deletions.
82 changes: 48 additions & 34 deletions mei2ly.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@
<xsl:key name="isBeamEnd" match="mei:beam" use=".//*[self::mei:note or self::mei:rest or self::mei:chord or self::mei:space][last()]/generate-id()"/>
<xsl:key name="isBeamEnd" match="@beam[contains(., 't')]" use="generate-id(..)"/>
<xsl:key name="isBeamEnd" match="mei:beamSpan[not(@beam.with)]" use="key('idref', @endid)/generate-id()"/>
<xsl:variable name="namesOfElementsWithDuration" select="('bTrem', 'chord', 'fTrem', 'halfmRpt', 'mRest', 'mSpace', 'note', 'rest', 'space', 'beam', 'beatRpt', 'mRpt', 'mRpt2', 'multiRest', 'multiRpt', 'tuplet')"/>
<xsl:key name="staffDefByFirstAffectedElement" match="mei:staffDef">
<xsl:variable name="hasPrecedingLayerContent" as="xs:boolean"
select="ancestor::mei:layer and preceding-sibling::mei:*[local-name()=$namesOfElementsWithDuration]"/>
<xsl:variable name="firstAffectedLayerContentElement"
select=".[$hasPrecedingLayerContent]/following-sibling::mei:*[name()=$namesOfElementsWithDuration][1]"/>
<xsl:choose>
<xsl:when test="$firstAffectedLayerContentElement">
<!-- This staffDef takes effect in the middle of a layer -->
<xsl:value-of select="$firstAffectedLayerContentElement/generate-id()"/>
</xsl:when>
<xsl:when test="ancestor::mei:staff and not($hasPrecedingLayerContent)">
<!-- This <staffDef> affects the <staff> element it lives in. -->
<xsl:value-of select="ancestor::mei:staff[1]/generate-id()"/>
</xsl:when>
<xsl:otherwise>
<!-- This <staffDef> takes effect in the next <staff> -->
<xsl:value-of select="following::mei:staff[@n=current()/@n][1]/generate-id()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:key>
<xsl:template match="/">
<xsl:text>\version "2.18.2"&#10;</xsl:text>
<xsl:text>#(ly:set-option 'point-and-click #f)&#10;</xsl:text>
Expand Down Expand Up @@ -169,16 +190,7 @@
<xsl:call-template name="setBarNumber" />
</xsl:if>
<!-- add clef change -->
<xsl:if test="generate-id(preceding::mei:staffDef[@n = $staffNumber][@clef.shape][1]/following::mei:measure[1]) = $currentMeasure">
<xsl:call-template name="setClef">
<xsl:with-param name="clefColor" select="preceding::mei:staffDef[@n = $staffNumber][@clef.shape][1]/@clef.color" />
<xsl:with-param name="clefDis" select="preceding::mei:staffDef[@n = $staffNumber][@clef.shape][1]/@clef.dis" />
<xsl:with-param name="clefDisPlace" select="preceding::mei:staffDef[@n = $staffNumber][@clef.shape][1]/@clef.dis.place" />
<xsl:with-param name="clefLine" select="preceding::mei:staffDef[@n = $staffNumber][@clef.shape][1]/@clef.line" />
<xsl:with-param name="clefShape" select="preceding::mei:staffDef[@n = $staffNumber][@clef.shape][1]/@clef.shape" />
</xsl:call-template>
<xsl:text>&#10;&#32;&#32;</xsl:text>
</xsl:if>
<xsl:apply-templates select="(key('staffDefByFirstAffectedElement', generate-id())/(@clef.shape, mei:clef))[last()]"/>
<!-- add key signature change -->
<xsl:if test="generate-id(ancestor::mei:measure/preceding-sibling::*[contains(local-name(),'Def')][@*[starts-with(name(),'key')]][1]/following-sibling::mei:measure[1]) = $currentMeasure">
<xsl:call-template name="setKey">
Expand Down Expand Up @@ -280,10 +292,10 @@
</xsl:template>
<!-- MEI score element -->
<xsl:template match="mei:score">
<xsl:apply-templates select="descendant::mei:scoreDef[1]" />
<xsl:apply-templates select="descendant::mei:scoreDef[1]" mode="score-setup"/>
</xsl:template>
<!-- MEI score definition -->
<xsl:template match="mei:scoreDef">
<xsl:template match="mei:scoreDef" mode="score-setup">
<!-- lilypond score block -->
<xsl:text>\score { &lt;&lt;&#10;</xsl:text>
<xsl:if test="ancestor::mei:mdiv[1]//@source">
Expand All @@ -294,7 +306,7 @@
</xsl:for-each>
<xsl:text>)&#10;</xsl:text>
</xsl:if>
<xsl:apply-templates select="mei:staffGrp|mei:staffDef" />
<xsl:apply-templates select="mei:staffGrp|mei:staffDef" mode="score-setup"/>
<xsl:text>&gt;&gt;&#10;</xsl:text>
<!-- lilypond layout block -->
<xsl:text>\layout {&#10;</xsl:text>
Expand Down Expand Up @@ -366,7 +378,7 @@
</xsl:if>
</xsl:template>
<!-- MEI staff group -->
<xsl:template match="mei:staffGrp">
<xsl:template match="mei:staffGrp" mode="score-setup">
<xsl:text>\new StaffGroup </xsl:text>
<xsl:if test="@label or @label.abbr or child::mei:label">
<xsl:text>\with { </xsl:text>
Expand All @@ -375,11 +387,11 @@
</xsl:if>
<xsl:text>&lt;&lt;&#10;</xsl:text>
<xsl:call-template name="setStaffGrpStyle" />
<xsl:apply-templates select="mei:staffGrp|mei:staffDef" />
<xsl:apply-templates select="mei:staffGrp|mei:staffDef" mode="score-setup"/>
<xsl:text>&gt;&gt;&#10;</xsl:text>
</xsl:template>
<!-- MEI staff definitons -->
<xsl:template match="mei:staffDef">
<xsl:template match="mei:staffDef" mode="score-setup">
<xsl:variable name="mdivNumber" select="ancestor::mei:mdiv/@n" />
<xsl:variable name="staffNumber" select="@n" />
<xsl:text> \new </xsl:text>
Expand Down Expand Up @@ -457,16 +469,6 @@
</xsl:choose>
<!-- set MEILER default styles -->
<xsl:text>\set tieWaitForNote = ##t&#10; </xsl:text>
<xsl:if test="ancestor-or-self::*/@*[starts-with(name(),'clef.')]">
<xsl:call-template name="setClef">
<xsl:with-param name="clefColor" select="@clef.color" />
<xsl:with-param name="clefDis" select="@clef.dis" />
<xsl:with-param name="clefDisPlace" select="@clef.dis.place" />
<xsl:with-param name="clefLine" select="@clef.line" />
<xsl:with-param name="clefShape" select="@clef.shape" />
</xsl:call-template>
</xsl:if>
<xsl:apply-templates select="mei:clef" />
<xsl:call-template name="setKey">
<xsl:with-param name="keyTonic" select="ancestor-or-self::*/@key.pname" />
<xsl:with-param name="keyAccid" select="ancestor-or-self::*/@key.accid" />
Expand Down Expand Up @@ -559,7 +561,7 @@
<xsl:text>}&#32;</xsl:text>
</xsl:template>
<!-- MEI measure -->
<xsl:template name="measure" match="mei:measure">
<xsl:template match="mei:measure">
<xsl:value-of select="' '" />
<xsl:if test="(ancestor::mei:measure[@n and not(@metcon='false')]/@n != preceding::mei:measure[@n and not(@metcon='false')][1]/@n + 1)">
<xsl:call-template name="setBarNumber" />
Expand Down Expand Up @@ -595,13 +597,25 @@
<xml:text>\\ </xml:text>
</xsl:if>
</xsl:template>
<!-- MEI staffDef (inside musical flow) -->
<xsl:template match="mei:staffDef[ancestor::mei:layer]">
<xsl:apply-templates select="(mei:clef, @clef.shape)[1]"/>
</xsl:template>
<!-- MEI clefs -->
<xsl:template name="setClef" match="mei:clef">
<xsl:param name="clefColor" select="@color" />
<xsl:param name="clefDis" select="@dis" />
<xsl:param name="clefDisPlace" select="@dis.place" />
<xsl:param name="clefLine" select="@line" />
<xsl:param name="clefShape" select="@shape" />
<xsl:template match="mei:clef|@clef.shape">
<xsl:param name="clefColor" select="@color|../@clef.color" />
<xsl:param name="clefDis" select="@dis|../@clef.dis" />
<xsl:param name="clefDisPlace" select="@dis.place|../@clef.dis.place" />
<xsl:param name="clefLine" select="@line|../@clef.line" />
<xsl:param name="clefShape" select="@shape|../@clef.shape" />
<xsl:variable name="mei2lyClefMap">
<clef mei="G" ly="G"/>
<clef mei="F" ly="F"/>
<clef mei="C" ly="C"/>
<clef mei="perc" ly="percussion"/>
<clef mei="TAB" ly="tab"/>
<clef mei="GG" ly="GG"/><!-- Not working in v2.18 and earlier? -->
</xsl:variable>
<xsl:variable name="clefTrans">
<xsl:choose>
<xsl:when test="$clefDisPlace='above'">
Expand Down Expand Up @@ -641,7 +655,7 @@
<xsl:if test="@cautionary">
<xsl:value-of select="concat('\set Staff.forceClef = ##',substring(@cautionary,1,1),' ')"/>
</xsl:if>
<xsl:value-of select="concat('\set Staff.clefGlyph = #','&quot;clefs.',$clefShape,'&quot; ')" />
<xsl:value-of select="concat('\set Staff.clefGlyph = #','&quot;clefs.', $mei2lyClefMap/*[@mei=$clefShape]/@ly,'&quot; ')" />
<xsl:value-of select="concat('\set Staff.clefPosition = #',$clefPos,' ')" />
<xsl:value-of select="concat('\set Staff.clefTransposition = #',$clefTrans,' ')" />
<xsl:value-of select="concat('\set Staff.middleCPosition = #',$clefPos + $cOffset - $clefTrans,' ')" />
Expand Down
94 changes: 94 additions & 0 deletions tests/clefs.mei
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://www.music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://www.music-encoding.org/schema/3.0.0/mei-all.rng" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="3.0.0" xmlns:meiler="NS:MEILER_TEST">
<meiHead>
<fileDesc>
<titleStmt>
<title>clef change tests</title>
</titleStmt>
<pubStmt/>
</fileDesc>
<extMeta>
<meiler:test system="bash" input="ly">
# Test strategy: We assigned ascending color values to elements in the order of appearance.
# We expect the order to be the same in the output.
testcolors=$(egrep -o 'rgb-color[^)]+' "$ly" | egrep --color=never -o '[0-9.].+')
# Clefs are flagged with a trailing 255 blue value (1 in lilypond)
cleftestcolors=$(echo "$testcolors" | grep --color=never '1$')
if echo "$cleftestcolors" | sort | uniq --count | egrep -v '^\s*1' > /dev/null
then
echo "At least one clef was output twice"
exit 1
fi
if [ $( echo "$cleftestcolors" | wc -l ) -ne 8 ]
then
echo "Number of output clefs does not match number of defined clefs"
exit 1
fi
if [ "$testcolors" != "$( echo "$testcolors" | sort )" ]
then
echo "At least one clef was output in the wrong place"
exit 1
fi
</meiler:test>
</extMeta>
</meiHead>
<music>
<body>
<mdiv>
<score>
<scoreDef meter.count="4" meter.unit="4">
<staffGrp>
<staffDef lines="5" n="1">
<clef shape="C" line="3" color="rgb(1,0,255)"/>
</staffDef>
<staffDef clef.line="4" clef.shape="F" lines="5" n="2" clef.color="rgb(100,0,255)"/>
</staffGrp>
</scoreDef>
<section>
<measure n="1">
<staff n="1">
<layer n="1">
<note dur="2" oct="5" pname="c" color="rgb(2,0,0)"/>
<clef shape="F" line="4" color="rgb(3,0,255)"/>
<rest dur="2" color="rgb(4,0,0)"/>
</layer>
</staff>
<staff n="2">
<layer n="1">
<note dur="2" oct="3" pname="f" color="rgb(101,0,0)"/>
<staffDef clef.shape="C" clef.line="3" n="2" clef.color="rgb(102,0,255)"/>
<rest dur="2" color="rgb(103,0,0)"/>
</layer>
</staff>
</measure>
<measure n="2">
<staffDef n="1" clef.shape="G" clef.line="2" clef.color="rgb(5,0,255)"/>
<staff n="1">
<layer>
<rest dur="2" color="rgb(6,0,0)"/>
<clef shape="perc" line="3" color="rgb(7,0,255)"/>
<rest dur="2" color="rgb(8,0,0)"/>
</layer>
</staff>
<staff n="2">
<staffDef n="2" clef.shape="F" clef.line="4" clef.color="rgb(104,0,255)"/>
<layer>
<beam>
<note dur="8" pname="c" oct="4" color="rgb(105,0,0)"/>
<note dur="8" pname="c" oct="4" color="rgb(106,0,0)"/>
<clef shape="G" line="2" color="rgb(107,0,255)"/>
<note dur="8" pname="c" oct="4" color="rgb(108,0,0)"/>
<note dur="8" pname="c" oct="4" color="rgb(109,0,0)"/>
</beam>
<rest dur="2" color="rgb(110,0,0)"/>
</layer>
</staff>
</measure>
</section>
</score>
</mdiv>
</body>
</music>
</mei>

0 comments on commit 3601004

Please sign in to comment.