XQuery/MusicXML to Arduino

      Motivation

      You want to play music available in MusicXML format on an Arduino.

      ↑Jump back a section

      Approach

      Fetch the Music XML file (either plain XML or compressed) and transform one monophic part to code to be included in an Arduino sketch.

      ↑Jump back a section

      Script

      (: ~
       : convert a monotonic part in a MusicXML score to an Arduino code fragment suitable to include in a sketch 
       :
       :@param uri - the uri of the MusicXML file
       :@param part - the id of the part to be converted to midi notes
       :@return text containing Arduino statements to :
       :     set the tempo, 
       :     define the array of midi notes a
       :     define a parallel array of note durations in beats 
       :@author Chris Wallace
       :)
       
      (: offsets of the letters ABCDEFG from C :)
      declare namespace fw = "http://www.cems.uwe.ac.uk/xmlwiki/fw";
       
      declare variable $fw:step2offset := (9,11,0,2,4,5,7);  
       
      declare function fw:filter($path as xs:string, $type as xs:string, $param as item()*) as xs:boolean {
       (: pass all :)
       true()
      };
       
      declare function fw:process($path as xs:string,$type as xs:string, $data as item()? , $param as item()*) {
       (: return the XML :)
       $data
      };
       
      declare function fw:unzip($uri) {
      let $zip := httpclient:get(xs:anyURI($uri), true(), ())/httpclient:body/text()
      let $filter := util:function(QName("http://www.cems.uwe.ac.uk/xmlwiki/fw","fw:filter"),3)
      let $process := util:function(QName("http://www.cems.uwe.ac.uk/xmlwiki/fw","fw:process"),4)
      let $xml := compression:unzip($zip,$filter,(),$process,())
      return $xml
      };
       
       
      declare function fw:MidiNote($thispitch as element() ) as xs:integer {
        let $step := $thispitch/step
        let $alter :=
          if (empty($thispitch/alter)) then 0
          else xs:integer($thispitch/alter)
        let $octave := xs:integer($thispitch/octave)
        let $pitchstep := $fw:step2offset [ string-to-codepoints($step) - 64]
        return 12 * ($octave + 1) + $pitchstep + $alter
      } ;
       
      declare function fw:mxl-to-midi ($part) {
        for $note in $part//note
        return 
          element note {
             attribute midi { if ($note/rest) then 0 else fw:MidiNote($note/pitch)},
             attribute duration { ($note/duration, 1) [1] }
          }
      };
       
      declare function fw:notes-to-arduino ($notes as element(note)*) as element(code) {
      (: create the two int arrays for inclusion in an Arduino sketch :)
      <code>
      int note_midi[] = {{&#10; { 
         string-join(
            for $midi at $i in $notes/@midi
            return 
              concat(if ($i  mod 10 eq 0) then "&#10;" else (),$midi)
            ,", ")
          }
      }};
       
      int note_duration[] = {{&#10; {
          string-join(
            for $duration at $i in $notes/@duration
            return 
              concat(if ($i  mod 10 eq 0) then "&#10;" else (),$duration)
            ,", ")
          } 
      }}; 
      </code>
      };
       
      declare option exist:serialize "method=text media-type=text/text";
       
      let $uri := request:get-parameter("uri",())
      let $part := request:get-parameter("part","P1")
      let $format := request:get-parameter("format","xml")
      let $doc := 
          if ($format = "xml")
          then doc ($uri)
          else if ($format = "zip")
          then fw:unzip($uri)
          else ()
      (: get the requested part :)
      let $part := $doc//part[@id = $part]
      (: use the data in the first measure to set the temp :)
      let $measure := $part/measure[1]
      let $tempo := (xs:integer($measure/sound/@tempo), 100)[1]
      (: convert the notes into an internal XML format :)
      let $notes := fw:mxl-to-midi($part)
      return
       
      (: generate the sketch fragmemt:)
        <sketch>
      int tempo = {$tempo};
      {fw:notes-to-arduino($notes) }
        </sketch>
      
      ↑Jump back a section
      Last modified on 2 December 2010, at 13:39