<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     version="2.0" exclude-result-prefixes="#all">
	<xsl:param name="input-uri" as="xs:string"/>
  <!--
  v. 0.3 July 11, 2007
    output <divisions/> and <staves/>only when necessary (once at start of part)
    eliminate empty tags: <notations/>
    move redundant code into template (mods output shared between notes and rests)
    cautionary accidentals- default to acc over eAcc value
    
  v. 0.2 July 2, 2007
   initial version (skipping 0.1 for consistency with xml2nl and NightXML version numbers) 
   based on ns2xml C code
   XSL 2.0, supports MusicXML 2.0


  usage, with Saxon 8+: 
  `java -jar saxon8.jar -it main nl2xml.xsl input-uri=notelist.nl > music.xml`
  
  TODO:
    refine handling of tuplets (add tag with "stop" attribute)
    combine attributes??
    lyric dashes / multisyllable
    remove redundant clefs (exist in notelist), only show clef changes
    refine handling of chords
    refine handling of voices/staves
    better handling of single-measure scores
    improve performance
 -->        

	<xsl:output method="xml" version="1.0" encoding="ISO-8859-1" 
  standalone="no" indent="yes" omit-xml-declaration="no"
  doctype-public="-//Recordare//DTD MusicXML 2.0 Timewise//EN" 
  doctype-system="http://www.musicxml.org/dtds/timewise.dtd"/>

    <!-- assume Notelist file is in MacRoman -->
		<xsl:variable name="notelistFile" select="unparsed-text($input-uri, 'iso-8859-1')"/>
		<xsl:variable name="newline">\n</xsl:variable>
		<xsl:variable name="singleQuote"><xsl:text>&#39;</xsl:text></xsl:variable>
		<xsl:variable name="greaterThan"><xsl:text>&gt;</xsl:text></xsl:variable>
		<xsl:variable name="lessThan"><xsl:text>&lt;</xsl:text></xsl:variable>
    <xsl:variable name="newlineOut"><xsl:text>&#xa;</xsl:text></xsl:variable>
    <xsl:variable name="shpFlt"/>
    <xsl:variable name="measureNum">1</xsl:variable>

    <!-- maps for notelist values to musicxml values-->

    <xsl:variable name="durations">
      <duration>32</duration>
      <duration>256</duration>
      <duration>128</duration>
      <duration>64</duration>
      <duration>32</duration>
      <duration>16</duration>
      <duration>8</duration>
      <duration>4</duration>
      <duration>2</duration>
      <duration>1</duration>
    </xsl:variable>

    <xsl:variable name="durationTypes">
      <durationType>quarter</durationType>
      <durationType>full</durationType>
      <durationType>whole</durationType>
      <durationType>half</durationType>
      <durationType>quarter</durationType>
      <durationType>eighth</durationType>
      <durationType>16th</durationType>
      <durationType>32nd</durationType>
      <durationType>64th</durationType>
      <durationType>128th</durationType>
    </xsl:variable>

    <xsl:variable name="noteModTags">
      <noteModTag><fingering>1</fingering></noteModTag>
      <noteModTag><fingering>2</fingering></noteModTag>
      <noteModTag><fingering>3</fingering></noteModTag>
      <noteModTag><fingering>4</fingering></noteModTag>
      <noteModTag><fingering>5</fingering></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag><fermata/></noteModTag>
      <noteModTag><trill-mark/></noteModTag>
      <noteModTag><accent/></noteModTag>
      <noteModTag><strong-accent/></noteModTag>
      <noteModTag><staccato/></noteModTag>
      <noteModTag><tenuto/></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag><mordent/></noteModTag>
      <noteModTag><inverted-mordent/></noteModTag>
      <noteModTag><turn/></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag><harmonic/></noteModTag>
      <noteModTag><up-bow/></noteModTag>
      <noteModTag><down-bow/></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag></noteModTag>
      <noteModTag><strong-accent/></noteModTag>
      <noteModTag><inverted-mordent/></noteModTag>
    </xsl:variable>    
    
    <xsl:variable name="noteModParentTags">    
      <noteModParentTag>technical</noteModParentTag>
      <noteModParentTag>technical</noteModParentTag>
      <noteModParentTag>technical</noteModParentTag>
			<noteModParentTag>technical</noteModParentTag>
			<noteModParentTag>technical</noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag>ornaments</noteModParentTag>
			<noteModParentTag>articulations</noteModParentTag>
			<noteModParentTag>articulations</noteModParentTag>
			<noteModParentTag>articulations</noteModParentTag>
			<noteModParentTag>articulations</noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag>ornaments</noteModParentTag>
			<noteModParentTag>ornaments</noteModParentTag>
			<noteModParentTag>ornaments</noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag>technical</noteModParentTag>
			<noteModParentTag>technical</noteModParentTag>
			<noteModParentTag>technical</noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag></noteModParentTag>
			<noteModParentTag>articulations</noteModParentTag>
			<noteModParentTag>ornaments</noteModParentTag>
    </xsl:variable>
    
    <xsl:variable name="noteheadTags">    
      <noteheadTag>none</noteheadTag>
      <noteheadTag></noteheadTag>
      <noteheadTag>x</noteheadTag>
      <noteheadTag>diamond</noteheadTag>
      <noteheadTag>square</noteheadTag>
      <noteheadTag>square</noteheadTag>
      <noteheadTag>diamond</noteheadTag>
      <noteheadTag>diamond</noteheadTag>
      <noteheadTag></noteheadTag>
      <noteheadTag>slash</noteheadTag>
      <noteheadTag>none</noteheadTag>
    </xsl:variable>

    <!--
     whether or not a Notelist notehead type is filled or not. some should not
     display at all, others should be yes and still others should be explicity "no" 
    -->
    <xsl:variable name="noteheadTagsFills">    
      <noteheadTagsFill></noteheadTagsFill>
      <noteheadTagsFill>no</noteheadTagsFill>
      <noteheadTagsFill>no</noteheadTagsFill>
      <noteheadTagsFill>yes</noteheadTagsFill>
      <noteheadTagsFill>no</noteheadTagsFill>
      <noteheadTagsFill>yes</noteheadTagsFill>
      <noteheadTagsFill></noteheadTagsFill>
      <noteheadTagsFill></noteheadTagsFill>
      <noteheadTagsFill></noteheadTagsFill>
    </xsl:variable>

    <!-- map accidentals -->
    <xsl:variable name="accidentalVals">
      <accidentalVal>flat-flat</accidentalVal>
      <accidentalVal>flat</accidentalVal>
      <accidentalVal>natural</accidentalVal>
      <accidentalVal>sharp</accidentalVal>
      <accidentalVal>double-sharp</accidentalVal>
    </xsl:variable>

    <!-- map dynamics -->
    <xsl:variable name="dynamicsMaps">
      <dynamicsMap>pppp</dynamicsMap>
      <dynamicsMap>ppp</dynamicsMap>
      <dynamicsMap>pp</dynamicsMap>
      <dynamicsMap>p</dynamicsMap>
      <dynamicsMap>mp</dynamicsMap>
      <dynamicsMap>mf</dynamicsMap>
      <dynamicsMap>f</dynamicsMap>
      <dynamicsMap>ff</dynamicsMap>
      <dynamicsMap>fff</dynamicsMap>
      <dynamicsMap>ffff</dynamicsMap>
      <dynamicsMap>piu piano</dynamicsMap>
      <dynamicsMap>meno piano</dynamicsMap>
      <dynamicsMap>meno forte</dynamicsMap>
      <dynamicsMap>piu forte</dynamicsMap>
      <dynamicsMap>sf</dynamicsMap>
      <dynamicsMap>fz</dynamicsMap>
      <dynamicsMap>sfz</dynamicsMap>
      <dynamicsMap>rf</dynamicsMap>
      <dynamicsMap>rfz</dynamicsMap>
      <dynamicsMap>fp</dynamicsMap>
      <dynamicsMap>sfp</dynamicsMap>
      <dynamicsMap>diminuendo</dynamicsMap>
      <dynamicsMap>crescendo</dynamicsMap>
    </xsl:variable>
    
    <!-- midi note mappings -->
    <xsl:variable name="midiNotes">
      <midiNote>
        <letterSharp>C</letterSharp>
        <sharp>false</sharp>
        <letterFlat>C</letterFlat>
        <flat>false</flat>
      </midiNote>
      <midiNote>
        <letterSharp>C</letterSharp>
        <sharp>true</sharp>
        <letterFlat>D</letterFlat>
        <flat>true</flat>
      </midiNote>
      <midiNote>
        <letterSharp>D</letterSharp>
        <sharp>false</sharp>
        <letterFlat>D</letterFlat>
        <flat>false</flat>
      </midiNote>
      <midiNote>
        <letterSharp>D</letterSharp>
        <sharp>true</sharp>
        <letterFlat>E</letterFlat>
        <flat>true</flat>
      </midiNote>
      <midiNote>
        <letterSharp>E</letterSharp>
        <sharp>false</sharp>
        <letterFlat>E</letterFlat>
        <flat>false</flat>
      </midiNote>
      <midiNote>
        <letterSharp>F</letterSharp>
        <sharp>false</sharp>
        <letterFlat>F</letterFlat>
        <flat>false</flat>
      </midiNote>
      <midiNote>
        <letterSharp>F</letterSharp>
        <sharp>true</sharp>
        <letterFlat>G</letterFlat>
        <flat>true</flat>
      </midiNote>
      <midiNote>
        <letterSharp>G</letterSharp>
        <sharp>false</sharp>
        <letterFlat>G</letterFlat>
        <flat>false</flat>
      </midiNote>
      <midiNote>
        <letterSharp>G</letterSharp>
        <sharp>true</sharp>
        <letterFlat>A</letterFlat>
        <flat>true</flat>
      </midiNote>
      <midiNote>
        <letterSharp>A</letterSharp>
        <sharp>false</sharp>
        <letterFlat>A</letterFlat>
        <flat>false</flat>
      </midiNote>
      <midiNote>
        <letterSharp>A</letterSharp>
        <sharp>true</sharp>
        <letterFlat>B</letterFlat>
        <flat>true</flat>
      </midiNote>
      <midiNote>
        <letterSharp>B</letterSharp>
        <sharp>false</sharp>
        <letterFlat>B</letterFlat>
        <flat>false</flat>
      </midiNote>    
    </xsl:variable>
    
    <!-- clef mappings -->
    <xsl:variable name="clefs"> 
      <!-- treble clef with 8va sign above -->
      <clef>
        <sign>G</sign>
        <line>2</line>
        <octaveChange>1</octaveChange>
      </clef>
      <!-- French violin clef (treble clef on bottom line)-->
      <clef>
        <sign>G</sign>
        <line>1</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!-- treble clef -->
      <clef>
        <sign>G</sign>
        <line>2</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!-- soprano clef (C clef on bottom line) -->
      <clef>
        <sign>C</sign>
        <line>1</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!--mezzo-soprano clef (C clef on 4th line from top)-->
      <clef>
        <sign>C</sign>
        <line>2</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!-- alto clef -->
      <clef>
        <sign>C</sign>
        <line>3</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!-- treble-tenor clef (treble clef with 8va sign) -->
      <clef>
        <sign>G</sign>
        <line>2</line>
        <octaveChange>-1</octaveChange>
      </clef>
      <!-- tenor clef (C clef on 2nd line from top)-->
      <clef>
        <sign>C</sign>
        <line>4</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!-- baritone clef (C clef on top line)-->
      <clef>
        <sign>C</sign>
        <line>5</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!-- bass clef -->
      <clef>
        <sign>F</sign>
        <line>4</line>
        <octaveChange>0</octaveChange>
      </clef>
      <!-- bass clef with 8va sign below -->
      <clef>
        <sign>F</sign>
        <line>4</line>
        <octaveChange>-1</octaveChange>
      </clef>
      <!-- percussion clef -->
      <clef>
        <sign>Percussion</sign>
        <line>3</line>
        <octaveChange>0</octaveChange>
      </clef>
    </xsl:variable>

    <xsl:variable name="barlineStyles">
		  <!-- normal bar line -->
		  <barlineStyle>
        <bar-style>regular</bar-style>
		  </barlineStyle>
		  <!-- double bar line -->
		  <barlineStyle>
        <bar-style>light-light</bar-style>
		  </barlineStyle>
		  <!-- final double bar line -->
		  <barlineStyle>
			  <bar-style>light-heavy</bar-style>
      </barlineStyle>
      <!-- heavy double bar line -->
		  <barlineStyle>
			  <bar-style>heavy-heavy</bar-style>
		  </barlineStyle>
		  <!-- repeat-left double bar line (||:) -->
		  <barlineStyle>
        <bar-style>heavy-light</bar-style>
        <repeat direction="forward"/>
		  </barlineStyle>
		  <!-- repeat-right double bar line (:||) -->
		  <barlineStyle>
			  <bar-style>light-heavy</bar-style>
			  <repeat direction="backward"/>
      </barlineStyle>
      <!-- repeat-both double bar line (:||:) still not sure about this one-->
		  <barlineStyle>
        <bar-style>light-light</bar-style>
			  <repeat direction="forward"/>
		  </barlineStyle>
    </xsl:variable>
    
    <xsl:variable name="notelistLines" select='tokenize($notelistFile, $newline)'/>
    <xsl:variable name="numNotelistLines" as="xs:integer*" select="count($notelistFile)"/>
 
    <!-- build an map on measures, based on times, really all we care about are the indexes, 
    to allow us to lookup a notelist line index based on time position -->
    <xsl:variable name="measures" as="xs:integer*">
      <xsl:for-each select='tokenize($notelistFile, $newline)'>
        <xsl:analyze-string select="." regex="/ t=(\d+) type=(\d+)">
          <xsl:matching-substring>
            <xsl:variable name="measureT"><xsl:number value="regex-group(1)" format="1"/></xsl:variable>
            <xsl:sequence select="$measureT"/>
          </xsl:matching-substring>
        </xsl:analyze-string>
      </xsl:for-each>
    </xsl:variable>
    
    <!--get raw partstaves from notelist -->
    <xsl:variable name="partstaves">
      <xsl:analyze-string select="$notelistFile" regex="^%%Notelist-V(\d+) file=(.+) partstaves=(.+) startmeas=(.+)">
        <xsl:matching-substring>
          <xsl:value-of select="regex-group(3)"/>
        </xsl:matching-substring>
      </xsl:analyze-string>
    </xsl:variable>
  
    <!-- make a sequence out of partstaves -->
    <xsl:variable name="partstavesseq" as="xs:integer*">
      <xsl:for-each select="tokenize($partstaves,' ')">
        <xsl:sequence select="xs:integer(.)"/>
      </xsl:for-each>
    </xsl:variable>
    
    <xsl:variable name="numstaves" as="xs:integer*" select="sum($partstavesseq)"/>
    <!-- in notelist, last value in list is a 0 terminator, so count up and subtract 1 -->
    <xsl:variable name="numparts" as="xs:integer*" select="count($partstavesseq) - 1"/>
    <!-- staff map 
    <xsl:variable name="partstaves">9 3 2 0</xsl:variable>

      implement staff-to-staff map 
       in music XML, staff numbers begin incrementing again from 1 with each new
         part, but in notelist stafff numbers increment globally across all parts 

      make a map out of partstaves
      which can then be queried with with xpath, like:
      
      for example:

      for this stf in notelist
      <xsl:variable name="nightingaleStaff">2</xsl:variable>

      to get musicxml staff
      <xsl:value-of select="$staffmaps/part[position()=$part]/staffmap[@nightingale=$nightingaleStaff]/@musicxml"/>
      or simply
       <xsl:value-of select="$staffmaps/part/staffmap[@nightingale=$nightingaleStaff]/@musicxml"/>

      to get musicxml part
      <xsl:value-of select="$staffmaps/part/staffmap[@nightingale=$nightingaleStaff]/../@id"/>      
    -->
    <xsl:variable name="staffmaps">
      <xsl:for-each select="$partstavesseq">
        <xsl:variable name="this_pos" select="position()"/>
        <part>
          <xsl:attribute name="id">
            <xsl:value-of select="$this_pos"/>
          </xsl:attribute>
          <xsl:for-each select="1 to xs:integer(.)">
            <staffmap>
              <xsl:attribute name="musicxml">
                <xsl:value-of select="position()"/>
              </xsl:attribute>
              <xsl:attribute name="nightingale">
                <xsl:value-of select="position() + sum($partstavesseq[position() = (1 to ($this_pos - 1))])"/>
              </xsl:attribute>
            </staffmap>
          </xsl:for-each>
        </part>
      </xsl:for-each>
    </xsl:variable>
    
    
  <!-- main template, parse and process notelist -->
	<xsl:template name="main">
    <score-timewise version="2.0">
      <xsl:for-each select="tokenize($notelistFile, '/')">
				<!-- Structured Comment -->
				<xsl:if test="starts-with(., '%%')">
					<xsl:analyze-string select="." regex="%%Notelist-V(\d+) file=(.+) partstaves=(.+) startmeas=(.+)">
						<xsl:matching-substring>
							<xsl:variable name="notelistVersion" select="regex-group(1)"/>
							<xsl:variable name="file" select="regex-group(2)"/>
							<xsl:variable name="partstaves" select="regex-group(3)"/>
							<xsl:variable name="startmeas" select="regex-group(4)"/>
              <work>
                <work-title>
                <xsl:value-of select="$file"/>
                </work-title>
              </work>
              <identification>
                <encoding>
                  <software>NightXML 0.3</software>
                  <encoding-date><xsl:value-of select="current-date()"/></encoding-date>
                </encoding>
              </identification>
              <xsl:variable name="tokenizedPartstaves" select="tokenize($partstaves,' ')"/>
              <part-list>
              <xsl:for-each select="$tokenizedPartstaves">
                <xsl:if test=". ne '0'">
                  <score-part>
                    <xsl:attribute name="id">P<xsl:value-of select="position()"/></xsl:attribute>
                    <part-name>Part <xsl:value-of select="position()"/></part-name>
                  </score-part>  
                </xsl:if>
              </xsl:for-each>
              </part-list>
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:if>        

				<!-- Barline, starts with '/', but we've already stripped those out -->

        <xsl:variable name="notelistChunk" select="."/>
        <xsl:analyze-string select="$notelistChunk" regex="^ t=(\d+) type=(\d+)">
          <xsl:matching-substring>
            <xsl:variable name="t" select="regex-group(1)"/>
            <xsl:variable name="type" select="xs:integer(regex-group(2))" as="xs:integer"/>
            <!-- don't output extra empty measure at end -->
            <xsl:if test="index-of($measures, xs:integer($t))[1] lt index-of($measures, $measures[last()])[last()]">    
              <measure>
                <xsl:attribute name="number">
                  <xsl:value-of select="index-of($measures, xs:integer($t))[1] + 1"/>
                </xsl:attribute>
                <xsl:call-template name="parseNotelistMeasure">
                  <xsl:with-param name="notelistStr" select="$notelistChunk" />
                  <xsl:with-param name="barlineType" select="$type" />
                </xsl:call-template>
              </measure>
            </xsl:if>
          </xsl:matching-substring>
          <xsl:non-matching-substring>
            <!--first measure-->
    				<xsl:if test="starts-with($notelistChunk,'%%')">
              <measure number="1">
                <xsl:call-template name="parseNotelistMeasure">
                  <xsl:with-param name="notelistStr" select="$notelistChunk" />
                  <xsl:with-param name="firstMeasure" select="1"/>
                </xsl:call-template>
              </measure>
            </xsl:if>
          </xsl:non-matching-substring>
        </xsl:analyze-string>
      </xsl:for-each>
    </score-timewise>
	</xsl:template>
  


 <!-- process a chunk of notelist staff by staff-->
  <xsl:template name="notelistStaffCompositor">
    <xsl:param name="notelistStr"/>
    <xsl:param name="staffNum" as="xs:integer"/>
    <xsl:for-each select="tokenize($notelistStr, $newline)"> 
      <xsl:choose>
        <!-- if staffNum is -1, output all without staff number (and those without times), except measures -->
        <xsl:when test="$staffNum eq -1">
          <xsl:analyze-string select="." regex="(^.*stf=.*|^ t=\d+ type=\d+)">
            <xsl:non-matching-substring>
              <xsl:call-template name="parseNotelistChunk">
                <xsl:with-param name="notelistStr"  select="."/>
              </xsl:call-template>
            </xsl:non-matching-substring>
          </xsl:analyze-string>        
        </xsl:when>
        <!--output items on this staff -->
        <xsl:otherwise>
          <xsl:analyze-string select="." regex="(^.*stf={$staffNum}.*)">
            <xsl:matching-substring>
              <xsl:call-template name="parseNotelistChunk">
                <xsl:with-param name="notelistStr"  select="regex-group(1)"/>
              </xsl:call-template>
            </xsl:matching-substring>
          </xsl:analyze-string>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="parseNotelistMeasure">
    <xsl:param name="notelistStr"/>
    <xsl:param name="barlineType" as="xs:integer">1</xsl:param>
    <xsl:param name="firstMeasure">0</xsl:param>
    <!-- match all lines for each nightingale staff -->
    <xsl:for-each select="1 to $numparts">
     <xsl:variable name="thisPartNum" select="."/>
      <part id="1">      
        <xsl:attribute name="id"><xsl:text>P</xsl:text><xsl:value-of select="$thisPartNum"/></xsl:attribute>
        <xsl:if test="$firstMeasure">
          <attributes>
            <divisions>32</divisions>
            <staves><xsl:value-of select="$partstavesseq[position()=$thisPartNum]"/></staves>
          </attributes>
        </xsl:if>
        <!--output all elements without stf and/or voice-->
        <xsl:if test=". eq 1">
          <xsl:call-template name="notelistStaffCompositor">
            <xsl:with-param name="notelistStr" select="$notelistStr" />
            <xsl:with-param name="staffNum" select="-1"/>
          </xsl:call-template>
        </xsl:if>
        <!-- call compositor for each staff in this part, map nightingale staff to musicxml part -->
        <xsl:for-each select="$thisPartNum to ($thisPartNum + $partstavesseq[position()=$thisPartNum] - 1)">
          <!-- do <backup> tag for voices, to rewind to start of measure -->
          <xsl:if test=". gt 1">
            <xsl:call-template name="doBackupStaff">
              <xsl:with-param name="notelistStr"  select="$notelistStr"/>
              <xsl:with-param name="staff" select="xs:integer(.)-1"/>
              <xsl:with-param name="part" select="$thisPartNum"/>          
            </xsl:call-template>
          </xsl:if>

          <xsl:call-template name="notelistStaffCompositor">
            <xsl:with-param name="notelistStr" select="$notelistStr" />
            <xsl:with-param name="staffNum" select="."/>
          </xsl:call-template>
        </xsl:for-each>
        <barline location="right">
          <xsl:copy-of select="$barlineStyles/barlineStyle[position()=$barlineType]/child::*"/>          
        </barline>
      </part>
    </xsl:for-each>
    <!--could there be any remaining non-matching lines? -->
  </xsl:template>

  <!-- process a chunk of notelist -->
  <xsl:template name="parseNotelistChunk">
    <xsl:param name="notelistStr"/>
    <!--assume notelist is multiline, but will be handled identically if only a single line-->
    <xsl:for-each select="tokenize($notelistStr, $newline)">
    
			<xsl:choose>
				<!-- Note or Gracenote -->
				<xsl:when test="starts-with(.,'N') or starts-with(.,'G')">

          <xsl:call-template name="processNote">
            <xsl:with-param name="notelistLine" select="."/>
          </xsl:call-template>
				</xsl:when> 
				<!-- Rest -->
				<xsl:when test="starts-with(., 'R')">
  				<xsl:variable name="notelistLine" select="."/>
          <xsl:analyze-string select="." regex="R t=(\d+) v=(\d+) npt=(\d+) stf=(\d+) dur=(\d+) dots=(\d+) (\.{{6}}) appear=(\d+)(.*)">
						<xsl:matching-substring>
							<xsl:variable name="t" select="regex-group(1)"/>
							<xsl:variable name="v" select="regex-group(2)"/>
							<xsl:variable name="npt" select="regex-group(3)"/>
							<xsl:variable name="stf" select="regex-group(4)"/>
							<xsl:variable name="dur"><xsl:number value="regex-group(5)" format="1"/></xsl:variable>
							<xsl:variable name="dots" select="regex-group(6)"/>
							<xsl:variable name="flags" select="regex-group(7)"/>
							<xsl:variable name="appearance" select="regex-group(8)"/>
              <xsl:variable name="mods" select="substring-after(regex-group(9), 'mods=')"/>

              <xsl:variable name="thisLineIdx">
                <xsl:call-template name="notelistLineIdx">
                  <xsl:with-param name="line" select="$notelistLine"/>
                </xsl:call-template>
              </xsl:variable>

              <!-- do backup takes for voices other that voice 1 -->
              <xsl:variable name="backupDuration">
                <xsl:call-template name="doBackup">
                  <xsl:with-param name="lineIdx" select="$thisLineIdx"/>
                  <xsl:with-param name="time" select="$t"/>
                  <xsl:with-param name="part" select="$npt"/>
                  <xsl:with-param name="staff" select="$stf"/>
                  <xsl:with-param name="voice" select="$v"/>
                 </xsl:call-template>          
                </xsl:variable>
                <xsl:if test="$backupDuration ne '0' and string-length($backupDuration) gt 0">
                  <backup>
                    <duration>
                      <xsl:value-of select="$backupDuration"/>
                    </duration>
                  </backup>          
                </xsl:if>

                <note>
                  <rest/>
                  <xsl:choose>
                    <xsl:when test="$dur eq format-number (-2, '#')">
                      <measure-style>
                      <multiple-rest><xsl:value-of select="$dur"/></multiple-rest>
                      </measure-style>
                    </xsl:when>
                    <xsl:otherwise>
                      <duration>
                        <xsl:value-of select="$durations/duration[position()=($dur + 1)]"/>
                      </duration>
                      <voice>
                        <xsl:value-of select="$v"/>
                      </voice>
                      <type>
                        <xsl:value-of select="$durationTypes/durationType[position()=($dur + 1)]"/>
                      </type>
                      <xsl:for-each select="1 to xs:integer($dots)">
                        <dot/>
                      </xsl:for-each>

                      <xsl:analyze-string select="$flags" regex="(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})">
                        <xsl:matching-substring>           
                          <xsl:variable name="flag2" select="regex-group(2)"/>
                          <xsl:variable name="flag3" select="regex-group(3)"/>
                          <xsl:variable name="flag4" select="regex-group(4)"/>
                          <xsl:variable name="flag5" select="regex-group(5)"/>
                          <xsl:variable name="flag6" select="regex-group(6)"/>
                          <xsl:if test="$flag6 eq 'T'">
                            <xsl:variable name="tupletLine">
                              <xsl:call-template name="allPreviousTuplet">
                                <xsl:with-param name="lineIdx" select="xs:integer($thisLineIdx) - 1"/>
                                <xsl:with-param name="time" select="$t"/>
                                <xsl:with-param name="part" select="$npt"/>
                                <xsl:with-param name="voice" select="$v"/>
                              </xsl:call-template>
                            </xsl:variable>
                            <xsl:analyze-string select="$tupletLine" regex="P v=(\d+) npt=(\d+) num=(\d+) denom=(\d+) appear=(\d+)">
                              <xsl:matching-substring>
                              
                                <xsl:variable name="v" select="regex-group(1)"/>
                                <xsl:variable name="npt" select="regex-group(2)"/>
                                <xsl:variable name="num" select="regex-group(3)"/>
                                <xsl:variable name="denom" select="regex-group(4)"/>

                                  <time-modification>
                                    <actual-notes><xsl:value-of select="$num"/></actual-notes>
                                    <normal-notes><xsl:value-of select="$denom"/></normal-notes>
                                  </time-modification>
                              </xsl:matching-substring>
                            </xsl:analyze-string>
                          </xsl:if>
                          <staff>
                            <xsl:value-of select="$staffmaps/part/staffmap[@nightingale=$stf]/@musicxml"/>
                          </staff>
                          <xsl:if test="$flag2 ne '.' or $flag3 ne '.' or $flag4 ne '.' or $flag5 ne '.'">
                            <notations>
                              <!-- tied to the preceding note -->
                              <xsl:if test="$flag2 eq ')'">
                                <tied type="stop"/>
                              </xsl:if>
                              <xsl:if test="$flag3 eq '('">
                                <tied type="start"/>
                              </xsl:if>

                              <!--TODO slur number count for part/voice -->
                              <!-- slurred to the preceding note-->
                              <xsl:if test="$flag4 eq $greaterThan">
                                <slur type="stop"/>
                              </xsl:if>
                              <!-- slurred to the following note-->
                              <xsl:if test="$flag5 eq $lessThan">
                              <slur type="start"/>
                              </xsl:if>
                            </notations>                
                          </xsl:if>
                        </xsl:matching-substring>
                      </xsl:analyze-string>
                    </xsl:otherwise>
                  </xsl:choose>                
                 <xsl:call-template name="outputMods">
                   <xsl:with-param name="modString" select="$mods"/>
                 </xsl:call-template>
                </note>            
              <xsl:value-of select="$newlineOut"/>
            </xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>

				<!-- Clef -->
				<xsl:when test="starts-with(., 'C')">
					<xsl:analyze-string select="." regex="C stf=(\d+) type=(\d+)">
						<xsl:matching-substring>
							<xsl:variable name="stf" select="regex-group(1)"/>
							<xsl:variable name="type"><xsl:number value="regex-group(2)" format="1"/></xsl:variable>
              <xsl:variable name="octaveChange" select="$clefs/clef[position()=$type]/octaveChange"/>
               <attributes>
                  <clef number="1">
                    <xsl:attribute name="number" select="$staffmaps/part/staffmap[@nightingale=$stf]/@musicxml"/>
                    <sign><xsl:value-of select="$clefs/clef[position()=$type]/sign"/></sign>
                    <line><xsl:value-of select="$clefs/clef[position()=$type]/line"/></line>
                    <xsl:if test="$octaveChange ne '0'">
                      <clef-octave-change><xsl:value-of select="$octaveChange"/></clef-octave-change>
                    </xsl:if>
                  </clef>
               </attributes>                       
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>

				<!-- Key Signature -->
				<xsl:when test="starts-with(., 'K')">
					<xsl:analyze-string select="." regex="K stf=(\d+) KS=(\d+) (.{{1}})(.*)">
						<xsl:matching-substring>
							<xsl:variable name="stf" select="regex-group(1)"/>
							<xsl:variable name="numAcc" as="xs:integer"><xsl:number value="regex-group(2)" format="1"/></xsl:variable>
              <xsl:variable name="shpFlt" select="regex-group(3)"/>
							<xsl:variable name="filler" select="regex-group(4)"/>
              <xsl:if test="$numAcc ne 0">
                <attributes>
                  <key>
                     <fifths>
                      <xsl:choose>
                        <xsl:when test="$shpFlt eq 'b'">
                          <xsl:value-of select="$numAcc * -1"/>
                        </xsl:when>
                        <xsl:otherwise>
                          <xsl:value-of select="$numAcc"/>                  
                        </xsl:otherwise>
                      </xsl:choose>
                     </fifths>
                  </key>
                </attributes>
              </xsl:if>
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>
				
				<!-- Time Signature -->
				<xsl:when test="starts-with(., 'T')">
					<xsl:analyze-string select="." regex="T stf=(\d+) num=(\d+) denom=(\d+)">
						<xsl:matching-substring>
							<xsl:variable name="stf" select="regex-group(1)"/>
							<xsl:variable name="num" select="regex-group(2)"/>
							<xsl:variable name="denom" select="regex-group(3)"/>
               <attributes>
                  <time>
                    <beats><xsl:value-of select="$num"/></beats>
                    <beat-type><xsl:value-of select="$denom"/></beat-type>
                  </time>
               </attributes>              
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>

				<!-- Dynamic -->
				<xsl:when test="starts-with(., 'D')">
					<xsl:analyze-string select="." regex="D stf=(\d+) dType=(\d+)">
						<xsl:matching-substring>
							<xsl:variable name="stf" select="regex-group(1)"/>
							<xsl:variable name="type"><xsl:number value="regex-group(2)" format="1"/></xsl:variable>              
               <direction placement="below">
                  <xsl:choose>
                    <xsl:when test="$type eq '22' or $type eq '23'">
                      <direction-type>
                        <wedge>
                            <xsl:attribute name="type" select="$dynamicsMaps/dynamicsMap[position()=$type]"/>
                        </wedge>
                      </direction-type>
                    </xsl:when>
                    <xsl:otherwise>
                      <direction-type>
                        <dynamics default-y="-81">
                          <xsl:element name="{$dynamicsMaps/dynamicsMap[position()=$type]}"/>
                        </dynamics>
                      </direction-type>
                    </xsl:otherwise>
                  </xsl:choose>
                  <staff><xsl:value-of select="$staffmaps/part/staffmap[@nightingale=$stf]/@musicxml"/></staff>
               </direction>        
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>

				<!-- Text -->
				<xsl:when test="starts-with(., 'A')">
					<xsl:analyze-string select="." regex="A v=(-*\d+) npt=(-*\d+) stf=(-*\d+) ([a-zA-Z]{{1}})(\d?) '([^']*)'">
						<xsl:matching-substring>
							<xsl:variable name="v" select="regex-group(1)"/>
							<xsl:variable name="npt" select="regex-group(2)"/>
							<xsl:variable name="stf" select="regex-group(3)"/>
							<xsl:variable name="code" select="regex-group(4)"/>
							<xsl:variable name="style" select="regex-group(5)"/>
							<xsl:variable name="textStr" select="regex-group(6)"/>

              <!-- lyrics are output within note context, so don't output here, 
              if 'L'yric has no association to a note (part or staff are -2), output here anyway -->
              <xsl:if test="$code ne 'L' or xs:integer($npt) lt 0 or xs:integer($stf) lt 0">
                <direction placement="above">
                  <direction-type>
                    <words><xsl:value-of select="$textStr"/></words>
                  </direction-type>
                  <staff><xsl:value-of select="$staffmaps/part/staffmap[@nightingale=$stf]/@musicxml"/></staff>
                </direction>
              </xsl:if>
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>

				<!-- Tempo Mark -->
				<xsl:when test="starts-with(., 'M')">
					<xsl:analyze-string select="." regex="M stf=(\d+) '([^']*)' (\w{{1}})(.?)=(\w*)">
						<xsl:matching-substring>
							<xsl:variable name="stf" select="regex-group(1)"/>
							<xsl:variable name="tempoStr" select="regex-group(2)"/>
							<xsl:variable name="metroUnit" select="regex-group(3)"/>
							<xsl:variable name="dot" select="regex-group(4)"/>							
							<xsl:variable name="dotted" select="string-length(regex-group(4)) gt 0"/>
							<xsl:variable name="metroStr" select="regex-group(5)"/>
              <direction placement="above">
                <direction-type>
                  <words><xsl:value-of select="$tempoStr"/> <xsl:value-of select="$metroStr"/></words>
                </direction-type>
                <sound tempo="{$metroStr}"/>
              </direction>              
              <!--		TODO: still need to properly translate Notelist note equals string
                    and handle durations other than quarter note =
              -->
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>

				<!-- Could match tuplet here, but they're done from the context of a note-->
        <!--				<xsl:when test="starts-with(., 'P')"> -->
        
				<!-- % notelist Comment -->
				<xsl:when test="starts-with(., '% ')">
					<xsl:analyze-string select="." regex="%(.*)">
						<xsl:matching-substring>
							<xsl:variable name="comment" select="regex-group(1)"/>
							<xsl:value-of select="concat($greaterThan, '!--', $comment , '-->')"/>
						</xsl:matching-substring>
					</xsl:analyze-string>
				</xsl:when>

			</xsl:choose>
		</xsl:for-each>   
  </xsl:template>


  <!-- this is really inefficient, but kinda works, just doensn't account for non-unique lines, which are possible -->
  <xsl:template name="notelistLineIdx">
    <xsl:param name="line"/>
    <xsl:value-of select="index-of($notelistLines, $line)[1]"/>
  </xsl:template>

  <xsl:template name="notelistLine">
    <xsl:param name="index"/>
    <xsl:value-of select="$notelistLines[position()=$index]"/>
  </xsl:template>

  <xsl:template name="doBackup">
    <xsl:param name="lineIdx"/>
    <xsl:param name="time"/>
    <xsl:param name="part"/>
    <xsl:param name="staff"/>
    <xsl:param name="voice"/>
    <xsl:param name="backupDuration">0</xsl:param>

    <xsl:variable name="thisLine">
      <xsl:call-template name="notelistLine">
        <xsl:with-param name="index" select="xs:integer($lineIdx)"/>
      </xsl:call-template>
    </xsl:variable>
    <!--recurse: keep stepping back a line a time, until we:
       reach another time
     -->    
    <xsl:choose>
      <!-- prevent an endress roop -->
      <xsl:when test="xs:integer($lineIdx) lt 0">
        <xsl:value-of select="xs:integer($backupDuration)"/>
      </xsl:when>   
      <xsl:when test="starts-with($thisLine, '/')">
      <!-- reached start of the next measure, or beginning (first line) of notelist do nothing, return
           this shouldn' happen, but just to be safe -->
        <xsl:value-of select="xs:integer($backupDuration)"/>    
      </xsl:when>
      <xsl:otherwise>
        <!-- match any line with a time-->
        <xsl:analyze-string select="$thisLine" regex=".* t=(\d+) .*">
          <xsl:matching-substring>
          <!-- match any line at _this_ time-->
            <xsl:analyze-string select="$thisLine" regex=".* t=({$time}) .*">
              <!-- match any note/rest -->
              <xsl:matching-substring>
                <xsl:analyze-string select="$thisLine" regex="([GNR]{{1}}) t=(\d+) v=(\d+) npt=(\d+) stf=(\d+) dur=(\d+) dots=(\d+) .*">
                  <xsl:matching-substring>
                    <xsl:variable name="firstChar" select="regex-group(1)"/>
                    <xsl:variable name="t" select="regex-group(2)"/>
                    <xsl:variable name="v" select="regex-group(3)"/>
                    <xsl:variable name="npt" select="regex-group(4)"/>
                    <xsl:variable name="stf" select="regex-group(5)"/>
                    <xsl:variable name="dur"><xsl:number value="regex-group(6)" format="1"/></xsl:variable>
                    <xsl:choose>
                      <!-- add other voices notes' (at same time position) durations to backup, recurse -->            
                      <xsl:when test="$voice ne $v and $part eq $npt and $staff eq $stf">
                        <xsl:call-template name="doBackup">
                          <xsl:with-param name="lineIdx" select="xs:integer($lineIdx) - 1"/>
                          <xsl:with-param name="time" select="$time"/>
                          <xsl:with-param name="part" select="$part"/>
                          <xsl:with-param name="staff" select="$staff"/>
                          <xsl:with-param name="voice" select="$voice"/>
                          <xsl:with-param name="backupDuration" select="xs:integer($backupDuration) + xs:integer($durations/duration[position()=$dur + 1])"/>
                         </xsl:call-template>          
                      </xsl:when>
                      <!--anthing else at this, recurse without increasing backup duration -->
                      <xsl:otherwise>
                        <xsl:call-template name="doBackup">
                          <xsl:with-param name="lineIdx" select="xs:integer($lineIdx) - 1"/>
                          <xsl:with-param name="time" select="$time"/>
                          <xsl:with-param name="part" select="$part"/>
                          <xsl:with-param name="staff" select="$staff"/>
                          <xsl:with-param name="voice" select="$voice"/>
                          <xsl:with-param name="backupDuration" select="$backupDuration"/>
                        </xsl:call-template>
                      </xsl:otherwise>
                    </xsl:choose>
                  </xsl:matching-substring>          
                </xsl:analyze-string>
              </xsl:matching-substring>          
              <!-- timed element, but time is too far back, so just return value-->
              <xsl:non-matching-substring>
                <xsl:value-of select="xs:integer($backupDuration)"/>
              </xsl:non-matching-substring>
            </xsl:analyze-string>
          </xsl:matching-substring>
          <xsl:non-matching-substring>
              <!-- we have a line without a time, so return-->
              <xsl:value-of select="xs:integer($backupDuration)"/>
          </xsl:non-matching-substring>
        </xsl:analyze-string>
      </xsl:otherwise>
    </xsl:choose> 
  </xsl:template>

  <xsl:template name="addDots" >
    <xsl:param name="dotDuration">0</xsl:param>
    <xsl:param name="currentDur">0</xsl:param>
    <xsl:param name="dotsCounter">0</xsl:param>
    <!--recurse -->
    <xsl:choose>
      <xsl:when test="$dotsCounter gt 0">
        <xsl:call-template name="addDots">
          <xsl:with-param name="dotDuration" select="$dotDuration div 2" />        
          <xsl:with-param name="currentDur" select="$currentDur + $dotDuration div 2" />
          <xsl:with-param name="dotsCounter" select="$dotsCounter - 1" />
        </xsl:call-template>
      </xsl:when>
      <!--output final value -->
      <xsl:otherwise>
        <xsl:value-of select="$currentDur" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="doBackupStaff">
    <xsl:param name="notelistStr"/>  
    <xsl:param name="part"/>
    <xsl:param name="staff"/>
    <xsl:param name="voice">1</xsl:param>
      
    <xsl:variable name="durations" as="xs:integer*">
      <xsl:for-each select="tokenize($notelistStr, $newline)">
        <xsl:analyze-string select="." regex="^.*v={$voice} npt={$part} stf={$staff} dur=(\d+) dots=(\d+)">
          <xsl:matching-substring>
            <xsl:variable name="baseDur" select="$durations/duration[position()=(xs:integer(regex-group(1)) + 1)]"/>
            <xsl:variable name="duration">
              <xsl:call-template name="addDots">
                <xsl:with-param name="currentDur" select="$baseDur"/>
                <xsl:with-param name="dotDuration" select="$baseDur"/>      
                <xsl:with-param name="dotsCounter" select="xs:integer(regex-group(2))"/>
              </xsl:call-template> 
            </xsl:variable>
            <xsl:sequence select="$duration"/>
          </xsl:matching-substring>
        </xsl:analyze-string>
      </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="sumDur" select="sum($durations)"/>
    <xsl:if test="xs:integer($sumDur) gt 0">
      <backup>
        <duration><xsl:value-of select="$sumDur"/></duration>
      </backup>
    </xsl:if>
  </xsl:template>  

  <xsl:template name="previousLyric">
    <xsl:param name="lineIdx"/>
    <xsl:param name="time"/>
    <xsl:param name="part"/>
    <xsl:param name="staff"/>

    <xsl:variable name="thisLine">
      <xsl:call-template name="notelistLine">
        <xsl:with-param name="index" select="xs:integer($lineIdx)"/>
      </xsl:call-template>
    </xsl:variable>

    <!--recurse: keep stepping back a line a time, until we either:
     1) reach a lyric at for this staff/part or
     2) time no longer matches
     -->    
    <!-- if we have a line with a time ...-->
    <xsl:analyze-string select="$thisLine" regex=".* t=(\d+) .*">
      <xsl:matching-substring>
        <xsl:analyze-string select="$thisLine" regex=".* t=({$time}) .*">
          <xsl:matching-substring>
          <!-- ... and the time is equal to our starting time, then recurse, decrementing line index-->
            <xsl:call-template name="previousLyric">
              <xsl:with-param name="lineIdx" select="xs:integer($lineIdx) - 1"/>
              <xsl:with-param name="time" select="$time"/>
              <xsl:with-param name="part" select="$part"/>
              <xsl:with-param name="staff" select="$staff"/>
            </xsl:call-template>
          </xsl:matching-substring>
         <!-- ... if the time not the same as our starting time, give up and return empty-->
         <!-- do nothing -->
        </xsl:analyze-string>
      <!-- if we _don't_ have a time in this line, which includes lyric lines, see if it's a lyric -->
      </xsl:matching-substring>
      <xsl:non-matching-substring>
        <xsl:analyze-string select="$thisLine" regex="A v=(-*\d+) npt=(-*\d+) stf=(-*\d+) ([a-zA-Z]{{1}})(\d?) '([^']*)'">
          <xsl:matching-substring>
            <xsl:variable name="v" select="regex-group(1)"/>
            <xsl:variable name="npt" select="regex-group(2)"/>
            <xsl:variable name="stf" select="regex-group(3)"/>
            <xsl:variable name="code" select="regex-group(4)"/>
            <xsl:variable name="style" select="regex-group(5)"/>
            <xsl:variable name="textStr" select="regex-group(6)"/>

            <!-- it's a lyric and part and staff match, so return full notelist line containing lyric -->
            <xsl:if test="'L' eq regex-group(4) and $part eq regex-group(2) and $staff eq regex-group(3)">
              <xsl:value-of select="$thisLine"/>
            </xsl:if>
          </xsl:matching-substring>
        </xsl:analyze-string>
      </xsl:non-matching-substring>
    </xsl:analyze-string>    
  </xsl:template>

  <xsl:template name="previousTuplet">
    <xsl:param name="lineIdx"/>
    <xsl:param name="time"/>
    <xsl:param name="part"/>
    <xsl:param name="voice"/>

    <xsl:variable name="thisLine">
      <xsl:call-template name="notelistLine">
        <xsl:with-param name="index" select="xs:integer($lineIdx)"/>
      </xsl:call-template>
    </xsl:variable>

    <!--recurse: keep stepping back a line a time, until we either:
     1) reach a tuplet at for this voice/part or
     2) time no longer matches
     -->    
    <!-- if we have a line with a time ...-->
    <xsl:analyze-string select="$thisLine" regex=".* t=(\d+) .*">
      <xsl:matching-substring>
        <xsl:analyze-string select="$thisLine" regex=".* t=({$time}) .*">
          <xsl:matching-substring>
          <!-- ... and the time is equal to our starting time, then recurse, decrementing line index-->
            <xsl:call-template name="previousTuplet">
              <xsl:with-param name="lineIdx" select="xs:integer($lineIdx) - 1"/>
              <xsl:with-param name="time" select="$time"/>
              <xsl:with-param name="part" select="$part"/>
              <xsl:with-param name="voice" select="$voice"/>
            </xsl:call-template>
          </xsl:matching-substring>
         <!-- ... if the time not the same as our starting time, give up and return empty-->
         <!-- do nothing -->
        </xsl:analyze-string>
      <!-- if we _don't_ have a time in this line, which includes tuplet lines, see if it's a tuplet -->
      </xsl:matching-substring>
      <xsl:non-matching-substring>
        <xsl:analyze-string select="." regex="P v={$voice} npt={$part} num=(\d+) denom=(\d+) appear=(\d+)">
          <xsl:matching-substring>
            <xsl:value-of select="$thisLine"/>
          </xsl:matching-substring>
        </xsl:analyze-string>
      </xsl:non-matching-substring>
    </xsl:analyze-string>    
  </xsl:template>

  <xsl:template name="allPreviousTuplet">
    <xsl:param name="lineIdx"/>
    <xsl:param name="time"/>
    <xsl:param name="part"/>
    <xsl:param name="voice"/>

    <xsl:variable name="thisLine">
      <xsl:call-template name="notelistLine">
        <xsl:with-param name="index" select="xs:integer($lineIdx)"/>
      </xsl:call-template>
    </xsl:variable>

    <!--recurse: keep stepping back a line a time, until we either:
     1) reach a tuplet at for this voice/part or
     2) we reach the beginning of the measure or notelist
     -->    
    <!-- if we have a line with a time ...-->
     <xsl:choose>
      <xsl:when test="starts-with($thisLine, 'P')">
      <!--tuplet matches, return full line-->
        <xsl:analyze-string select="$thisLine" regex="P v={$voice} npt={$part} num=(\d+) denom=(\d+) appear=(\d+)">
          <xsl:matching-substring>
           <xsl:value-of select="$thisLine"/>
          </xsl:matching-substring>
        </xsl:analyze-string>
      </xsl:when>
      <xsl:when test="starts-with($thisLine, '/') or starts-with($thisLine, '%%')">
      <!-- reached start of measure, or beginning (first line) of notelist do nothing, return empty -->
           <!-- do nothing --> 
      </xsl:when>
      <xsl:otherwise>
      <!-- non-tuplet line, so recurse -->
        <xsl:choose>
          <!-- prevent an endress roop -->
          <xsl:when test="xs:integer($lineIdx) lt 0">
          <!--do nothing, stay empty, stay loose -->
          </xsl:when>
          <xsl:otherwise>
            <xsl:call-template name="allPreviousTuplet">
              <xsl:with-param name="lineIdx" select="xs:integer($lineIdx) - 1"/>
              <xsl:with-param name="time" select="$time"/>
              <xsl:with-param name="part" select="$part"/>
              <xsl:with-param name="voice" select="$voice"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="getNotelistLineByTime">
    <xsl:param name="time"/>
    <xsl:for-each select='tokenize($notelistFile, $newline)'>
      <xsl:analyze-string select="." regex="^.* t={$time}.*">
        <xsl:matching-substring>
          <xsl:value-of select="."/>
        </xsl:matching-substring>
      </xsl:analyze-string>
    </xsl:for-each>  
  </xsl:template>

  <xsl:template name="outputMods">  
    <xsl:param name="modString"/>
    <xsl:if test="string-length($modString) gt 0">          
      <notations>
        <xsl:for-each select="tokenize($modString, ',')">
          <xsl:if test="string-length(.) gt 0">
            <xsl:variable name="index" select="xs:integer(.)" as="xs:integer"/>
            <xsl:choose>
              <xsl:when test="string-length($noteModParentTags/noteModParentTag[position()=$index]) gt 0">
                <xsl:element name="{$noteModParentTags/noteModParentTag[position()=$index]}">
                    <xsl:copy-of select="$noteModTags/noteModTag[position()=$index]/child::*"/>
                </xsl:element>
              </xsl:when>
              <xsl:otherwise>
                <xsl:copy-of select="$noteModTags/noteModTag[position()=$index]/child::*"/>
              </xsl:otherwise>
            </xsl:choose>                    
          </xsl:if>
        </xsl:for-each>
      </notations>
    </xsl:if>
  </xsl:template>

  <xsl:template name="processNote">
    <xsl:param name="notelistLine"/>
      
    <xsl:analyze-string select="$notelistLine" regex="([GN]{{1}}) t=(\d+) v=(\d+) npt=(\d+) stf=(\d+) dur=(\d+) dots=(\d+) nn=(\d+) acc=(\d+) eAcc=(\d+) pDur=(\d+) vel=(\d+) (.{{6}}) appear=(\d+)(.*)">
      <xsl:matching-substring>
        <xsl:variable name="firstChar" select="regex-group(1)"/>
        <xsl:variable name="t" select="regex-group(2)"/>
        <xsl:variable name="v" select="regex-group(3)"/>
        <xsl:variable name="npt" select="regex-group(4)"/>
        <xsl:variable name="stf" select="regex-group(5)"/>
        <xsl:variable name="dur"><xsl:number value="regex-group(6)" format="1"/></xsl:variable>
        <xsl:variable name="dots" select="regex-group(7)"/>
        <xsl:variable name="nn"><xsl:number value="regex-group(8)" format="1"/></xsl:variable>
        <xsl:variable name="acc" select="xs:integer(regex-group(9))"/>
        <xsl:variable name="eAcc" select="xs:integer(regex-group(10))"/>
        <xsl:variable name="pDur" select="regex-group(11)"/>
        <xsl:variable name="vel" select="regex-group(12)"/>
        <xsl:variable name="flags" select="regex-group(13)"/>
        <xsl:variable name="appearance" select="xs:integer(regex-group(14))"/>
        <xsl:variable name="mods" select="substring-after(regex-group(15), 'mods=')"/>

              

          <xsl:variable name="midiNoteIdx" select="$nn - ((floor($nn div 12)) * 12) + 1"/>


          <xsl:variable name="accidental">
           <xsl:choose>
             <xsl:when test="$acc ge 1">
               <xsl:value-of select="$acc"/>
             </xsl:when>
             <xsl:when test="$eAcc ge 1">
               <xsl:value-of select="$eAcc"/>
             </xsl:when>               
             <xsl:otherwise>0</xsl:otherwise>               
           </xsl:choose>
          </xsl:variable>

          <xsl:variable name="thisLineIdx">
            <xsl:call-template name="notelistLineIdx">
              <xsl:with-param name="line" select="$notelistLine"/>
            </xsl:call-template>
          </xsl:variable>
                
          <xsl:variable name="lyricLine">
            <xsl:call-template name="previousLyric">
              <xsl:with-param name="lineIdx" select="xs:integer($thisLineIdx) - 1"/>
              <xsl:with-param name="time" select="$t"/>
              <xsl:with-param name="part" select="$npt"/>
              <xsl:with-param name="staff" select="$stf"/>
            </xsl:call-template>
          </xsl:variable>

          <xsl:variable name="tupletLine">
            <xsl:call-template name="previousTuplet">
              <xsl:with-param name="lineIdx" select="xs:integer($thisLineIdx) - 1"/>
              <xsl:with-param name="time" select="$t"/>
              <xsl:with-param name="part" select="$npt"/>
              <xsl:with-param name="voice" select="$v"/>
            </xsl:call-template>
          </xsl:variable>
        
          <!-- do backup takes for voices -->
          <xsl:variable name="backupDuration">
            <xsl:call-template name="doBackup">
              <xsl:with-param name="lineIdx" select="$thisLineIdx"/>
              <xsl:with-param name="time" select="$t"/>
              <xsl:with-param name="part" select="$npt"/>
              <xsl:with-param name="staff" select="$stf"/>
              <xsl:with-param name="voice" select="$v"/>
            </xsl:call-template>          
          </xsl:variable>
          <xsl:if test="$backupDuration ne '0' and string-length($backupDuration) gt 0">
            <backup>
              <duration>
                <xsl:value-of select="$backupDuration"/>
              </duration>
            </backup>          
          </xsl:if>
          <note>
            <!--chord flags-->
            <xsl:analyze-string select="$flags" regex="(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})">
              <xsl:matching-substring>           
                <xsl:variable name="flag1" select="regex-group(1)"/>
                <!-- main note (carrying the stem) in a chord-->
                <xsl:if test="$flag1 eq '+'">
                 <!--   <chord/>-->
                </xsl:if>
                <!--  other note in a chord -->                
                <xsl:if test="$flag1 eq '-'">
                  <chord/>
                </xsl:if>
              </xsl:matching-substring>
            </xsl:analyze-string>
            
            <pitch>
             <step>
                <xsl:choose>
                  <xsl:when test="$accidentalVals/accidentalVal[position()=$accidental] eq 'sharp'">
                    <xsl:value-of select="$midiNotes/midiNote[position()=$midiNoteIdx]/letterSharp"/>
                  </xsl:when>
                  <xsl:when test="$accidentalVals/accidentalVal[position()=$accidental] eq 'flat'">
                    <xsl:value-of select="$midiNotes/midiNote[position()=$midiNoteIdx]/letterFlat"/>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$midiNotes/midiNote[position()=$midiNoteIdx]/letterSharp"/>                      
                  </xsl:otherwise>
                </xsl:choose>
              </step>                  
              <xsl:choose>
                <xsl:when test="$accidentalVals/accidentalVal[position()=$accidental] eq 'sharp' and $midiNotes/midiNote[position()=$midiNoteIdx]/flat eq 'true'">
                  <alter>1</alter>
                </xsl:when>
                <xsl:when test="$accidentalVals/accidentalVal[position()=$accidental] eq 'flat' and $midiNotes/midiNote[position()=$midiNoteIdx]/sharp eq 'true'">
                  <alter>-1</alter>
                </xsl:when>
              </xsl:choose>                
              <octave>
                <xsl:value-of select="floor($nn div 12) - 1"/>
              </octave>    
            </pitch>
            <xsl:choose>
              <xsl:when test="$firstChar eq 'G'">
                <grace/>
              </xsl:when>
              <xsl:otherwise>
                <duration>
                  <xsl:value-of select="$durations/duration[position()=($dur + 1)]"/>
                </duration>
              </xsl:otherwise>
            </xsl:choose>
            <voice>
              <xsl:value-of select="$v"/>
            </voice>              
            <type>
              <xsl:value-of select="$durationTypes/durationType[position()=($dur + 1)]"/>
            </type>
            <xsl:for-each select="1 to xs:integer($dots)">
              <dot/>
            </xsl:for-each>
            <xsl:value-of select="$newlineOut"/>

            <xsl:variable name="isFilled" select="$noteheadTagsFills/noteheadTagsFill[position()=$appearance]"/>
                        
            <xsl:if test="string-length($isFilled) gt 1">
              <notehead filled="yes">
                <xsl:attribute name="filled" select="$isFilled"/>
              </notehead>           
            </xsl:if>

            <xsl:analyze-string select="$flags" regex="(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})">
              <xsl:matching-substring>           
                <xsl:variable name="flag2" select="regex-group(2)"/>
                <xsl:variable name="flag3" select="regex-group(3)"/>
                <xsl:variable name="flag4" select="regex-group(4)"/>
                <xsl:variable name="flag5" select="regex-group(5)"/>
                <xsl:variable name="flag6" select="regex-group(6)"/>
                <xsl:if test="$flag6 eq 'T'">
                  <xsl:variable name="tupletLine">
                    <xsl:call-template name="allPreviousTuplet">
                      <xsl:with-param name="lineIdx" select="xs:integer($thisLineIdx) - 1"/>
                      <xsl:with-param name="time" select="$t"/>
                      <xsl:with-param name="part" select="$npt"/>
                      <xsl:with-param name="voice" select="$v"/>
                    </xsl:call-template>
                  </xsl:variable>
                  <xsl:analyze-string select="$tupletLine" regex="P v=(\d+) npt=(\d+) num=(\d+) denom=(\d+) appear=(\d+)">
                    <xsl:matching-substring>
                      <xsl:variable name="v" select="regex-group(1)"/>
                      <xsl:variable name="npt" select="regex-group(2)"/>
                      <xsl:variable name="num" select="regex-group(3)"/>
                      <xsl:variable name="denom" select="regex-group(4)"/>

                      <time-modification>
                        <actual-notes><xsl:value-of select="$num"/></actual-notes>
                        <normal-notes><xsl:value-of select="$denom"/></normal-notes>
                      </time-modification>
                    </xsl:matching-substring>
                  </xsl:analyze-string>
                </xsl:if>
                <staff>
                  <xsl:value-of select="$staffmaps/part/staffmap[@nightingale=$stf]/@musicxml"/>
                </staff>
                <xsl:if test="$flag2 ne '.' or $flag3 ne '.' or $flag4 ne '.' or $flag5 ne '.'">
                  <notations>
                    <!-- tied to the preceding note -->
                    <xsl:if test="$flag2 eq ')'">
                      <tied type="stop"/>
                    </xsl:if>
                    <xsl:if test="$flag3 eq '('">
                      <tied type="start"/>
                    </xsl:if>

                    <!--TODO slur number count for part/voice -->
                    <!-- slurred to the preceding note-->
                    <xsl:if test="$flag4 eq $greaterThan">
                      <slur type="stop"/>
                    </xsl:if>
                    <!--  slurred to the following note-->
                    <xsl:if test="$flag5 eq $lessThan">
                      <slur type="start"/>
                    </xsl:if>
                  </notations>                
                </xsl:if>
              </xsl:matching-substring>
            </xsl:analyze-string>

           <!-- tuplets -->
 					 <xsl:if test="string-length($tupletLine) gt 0">
            <xsl:analyze-string select="$tupletLine" regex="P v=(\d+) npt=(\d+) num=(\d+) denom=(\d+) appear=(\d+)">
              <xsl:matching-substring>
              
                <xsl:variable name="v" select="regex-group(1)"/>
                <xsl:variable name="npt" select="regex-group(2)"/>
                <xsl:variable name="num" select="regex-group(3)"/>
                <xsl:variable name="denom" select="regex-group(4)"/>
                <xsl:variable name="appearance" select="regex-group(5)"/>

                <xsl:variable name="bracket">
                  <xsl:choose>
                    <xsl:when test="substring($appearance, 3, 1) eq '1'">yes</xsl:when>
                    <xsl:otherwise>no</xsl:otherwise>
                  </xsl:choose>
                </xsl:variable>

                <xsl:variable name="shownumber">
                  <xsl:choose>
                    <xsl:when test="substring($appearance, 1, 1) eq '1' and substring($appearance, 2, 1) eq '0'">actual</xsl:when>
                    <xsl:when test="substring($appearance, 1, 1) eq '1' and substring($appearance, 2, 1) eq '1'">both</xsl:when>
                    <xsl:otherwise>none</xsl:otherwise>
                  </xsl:choose>
                </xsl:variable>
                
                <notations>
                  <tuplet bracket="no" number="1" placement="above" show-number="no" type="start">
                    <xsl:attribute name="bracket" select="$bracket"/>
                    <xsl:attribute name="number" select="$num"/>
                    <xsl:attribute name="show-number" select="$shownumber"/>                  
                  </tuplet>
                </notations>                
              </xsl:matching-substring>
            </xsl:analyze-string>
          </xsl:if>
          <!-- tuplet closing tag -->
          <!--
          <xsl:analyze-string select="$flags" regex="(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})(.{{1}})">
            <xsl:matching-substring>           
              <xsl:if test="regex-group(6) eq 'T'">
                <xsl:call-template name="tryClosingTuplet">
                  <xsl:with-param name="lineIdx" select="xs:integer($thisLineIdx) - 1"/>
                  <xsl:with-param name="time" select="$t"/>
                  <xsl:with-param name="part" select="$npt"/>
                  <xsl:with-param name="voice" select="$v"/>
                </xsl:call-template>
              </xsl:if>
            </xsl:matching-substring>
          </xsl:analyze-string>
        -->
          
          <!-- note modifiers -->
          <xsl:call-template name="outputMods">
            <xsl:with-param name="modString" select="$mods"/>
          </xsl:call-template>

          <!-- lyric -->
          <xsl:if test="string-length($lyricLine) gt 0">
            <xsl:analyze-string select="$lyricLine" regex="A v=(-*\d+) npt=(-*\d+) stf=(-*\d+) ([a-zA-Z]{{1}})(\d?) '([^']*)'">
              <xsl:matching-substring>
                <xsl:variable name="v" select="regex-group(1)"/>
                <xsl:variable name="npt" select="regex-group(2)"/>
                <xsl:variable name="stf" select="regex-group(3)"/>
                <xsl:variable name="code" select="regex-group(4)"/>
                <xsl:variable name="style" select="regex-group(5)"/>
                <xsl:variable name="textStr" select="regex-group(6)"/>
                <xsl:if test="$code eq 'L'">
                  <lyric number="1">
                    <xsl:attribute name="number" select="$v"/>
                    <syllabic>single</syllabic>
                    <text><xsl:value-of select="$textStr"/></text>
                  </lyric>                
                </xsl:if>
              </xsl:matching-substring>
            </xsl:analyze-string>
          </xsl:if>
        </note>
      </xsl:matching-substring>
    </xsl:analyze-string>
  </xsl:template>
</xsl:stylesheet>
