iOS中MusicXML的解析和使用

iOS中MusicXML的解析和使用

MusicXML

维基上MusicXML的解释是:(英语:Music Extensible Markup Language,音乐扩展标记语言)是一个开放的基于XML的记录西式乐谱的文件格式。该格式是完全自由、开放记录的,并依据W3C社区的许可协议自由使用。
简单的来说,MusicXML其实就是XML,只不过承载的是乐谱信息的XML。在我们需要绘制或者创建六线谱之类的时候,可以通过MusicXML来记录我们需要绘制或者创建的信息。目的是为音乐符号创造一种通用格式。(本文是基于MusicXML 3.0和2.0,所以可能会有一些出入。)因为项目中用到的是吉他谱,就以吉他谱的含义来进行说明和解释。

一 文件解析

MusicXML本质也是XML,所以文件上的解析可以按XML的解析来。
XML的解析在iOS里面有两种解析方式,一个SAX解析,一个DOM解析。

方式一:SAX解析

SAX解析的特点是逐行进行解析。也就是一边读取一边处理。对于大文件,极大的提高了解析效率。

方式二:DOM解析

DOM解析的特点是通过节点解析。需要一次性读取整个XML文件并形成一个节点树,通过遍历树结构可以检索任意XML节点,读取它的属性和值。
比如第三方:GDataXMLNode

在这里我用的SAX解析,具体可以去看下这里,是我之前用来解析MusicXML文档写的。

  • 注意点:因为是使用的utf8编码,所以一旦XML里面出现了其他的编码方式,就有可能造成解析失败,所以在解析前最好将xml处理一遍。

二 属性解析

MusicXML本质上还是XML,所以文件结构是和XML一样的,这个是XML文档所需要的XML声明。声明用的xml版本是1.0和xml传输数据的时候的字符编码。(假如文档里有中文,编码方式不是UTF-8,显示上就会乱码)

<?xml version="1.0" encoding="UTF-8" ?>

这里是说明当前使用的MusicXML版本是什么,标签里面包含的内容就是MusicXML的内容

 <score-partwise version =“ 3.0”>
  ...
 </score-partwise>

score-partwise元素里面的有几个大元素:

  1. work元素,work-title里面内容是这个xml的名字

     <work>
        <work-title>Aloha oe</work-title>
     </work>
    
  2. identification,这里是文档的一些编辑信息,比如编辑日期,是用什么软件编辑的

     <identification>
         <encoding>
          <encoding-date>2019-10-08</encoding-date>
          <software>Guitar Pro 7.0.9</software>
          <encoder></encoder>
         </encoding>
     </identification>
    
  3. defaults,这里是一些页面的宽高信息

     <defaults>
          <scaling>
           <millimeters>6.4</millimeters>
           <tenths>40</tenths>
          </scaling>
          <page-layout>
           <page-height>1850</page-height>
           <page-width>1310</page-width>
          </page-layout>
     </defaults>
    
  4. part-list,这里面是一些乐器类型,MIDI信息

    <part-list>
      <score-part id="P1">
       <part-name>Ukulele</part-name>
       <part-abbreviation>uke.</part-abbreviation>
       <midi-instrument id="P1">
        <midi-channel>1</midi-channel>
        <midi-bank>1</midi-bank>
        <midi-program>25</midi-program>
        <volume>80</volume>
        <pan>0</pan>
       </midi-instrument>
    </score-part>
    
  5. part,这里面是音符信息,默认是只有一个part的,所以大多数MusicXML里面是只有一个part元素,比如:

    <score-partwise>
         <part id="P1">
            ...
         </part>
     </score-partwise>
    
    但有可能会出现多个part,具体看制谱的时候是怎么做的,比如:
    <score-partwise>
        <part id="P1">
            ...
        </part>
        <part id="P2">
            ...
        </part>
    </score-partwise>
    
  • measure元素,part里面是小节measure元素,比如一首谱子有24个小节,那么就会有24个measure,measure里面的属性number等于多少是可以自己定义的,比如从0开始,比如从1开始。measure里面包含了一个小节里面所有的信息。

    • attributes,先看measure里面第一个元素attributes,一般出现在第一个小节中,它里面是该乐谱的基本信息。
      1. divisions,divisions表示的是一个四分音符的时值,每个小节可能有不同的值,比如说在第一个小节中

         <divisions>1</divisions>
        

        表示的是当前小节中一个四分音符的时值是1个单位,divisions是要配合note中的duration看的,比如在4/4的谱子中,下面这个四分音符note的duration就是1,

        <note>
             <duration>1</duration>
             <type>quarter</type>
        </note>
        

        而下面这个全音符的duration就是4,因为4/4是以四分音符为一拍,每小节四拍。所以全音符的话时值相当于四个四分音符,所以它的duration就是4。

        <note>
            <duration>4</duration>
            <type>whole</type>
        </note>
        

    再比如如果当前音符存在附点,附点的时值是当前音符的一半,因为按上下文当前divisions还是1,而在当前出现了附点,divisions要变为2,所以在接下来会变成下面这样

          ```
           <divisions>2</divisions>
              <note>
              <dot/>
              <duration>3</duration>
              <type>quarter</type>
              </note>
          ```
    

    再比如如果当前小节存在十六分音符:

          ```
          <divisions>4</divisions>
              <note>
              <duration>1</duration>
              <type>16th</type>
           </note>
          ```
    
      1. key,key元素表示乐谱的升降号情况,fifths为0表示不升不降,一般正数表示升调的个数,负数表示降调的个数,这个元素还有一个属性`mode/type`来表示此调为大调(major)还是小调。
        
          ```
              <key>
               <fifths>0</fifths>
               <mode>major</mode>
              </key>
          ```
      2. time,time元素里面是这首曲子拍速等一些相关的信息,比如下面的含义就是以8分音符为一拍,每小节6拍。
          ```
              <time>
               <beats>6</beats>//每个小节有几个拍
               <beat-type>8</beat-type>//以哪种音符为一拍
              </time>
          ```
      3. clef,clef里面是谱号信息。
          
          ```
              <clef number="1">
               <sign>TAB</sign>
               <line>5</line>
              </clef>
          ```
      4. staff-details,staff-details这里是空弦的时候每根弦的音名。
          *staff-lines,staff-lines元素指定了行数
    
    • harmony,和弦图元素
    • note,然后接下来是<note>标签,这里面是每个音符的一些信息。
      • chord,这个元素可以理解为和弦,叠音,也就是说当这个标签出现的时候,竖直方向是有多个音的,用叠音描述会形象一些,也就是几个音叠在一起;相反如果没有这个元素,可以大致认为当前这个音符是根音,也就是在最底部的音。比如:

         <note>
          <chord/>
          <type>quarter</type>
          <stem>up</stem>
          <notations>
           <technical>
            <string>4</string>
            <fret>2</fret>
           </technical>
          </notations>
         </note>
        
      • rest,这个元素是休止符的表示,比如下面表示一个二分休止符:

         <note>
          <rest/>
          <duration>2</duration>
          <type>half</type>
         </note>
        
      • duration,上面divisions元素中已经说过了,表示当前音符的时值,也就是这个音符的持续时间。具体值是通过divisions来计算。

      • type,表示当前音符是什么类型,比如<type>half</type>,表示的是个二分音符。type里面的值是有固定的,大致是这些

        • whole:全音符,也就是占一个小节
        • half:二分音符
        • quarter:四分音符
        • eighth:八分音符
        • 16th:16分音符
        • 32th:32分音符
          如果出现了更小的音符,基本就是以数字+th为名字。
      • pitch,音高,里面是音、调的一些信息。

        • step:表示是abcdefg哪个调。

        • alter:表示升降,作为音高的一部分,-2或2表示重降和重升。

        • octave:表示在哪个八度上。
          比如:

           <pitch>
            <step>F</step>
            <alter>-2</alter>
            <octave>4</octave>
           </pitch>
          
      • stem:符干。

      • voice:声部。

      • dot:附点,表示当前音符的时值增加一半。比如下面例子,某个小节中的一个四分音符,如果divisions为2的话,它的时值duration是3。divisions表示的,可以理解成一个四分音符的时值。那么当前这个小节中的四分音符加个附点的话,它时值就是一个四分的1.5倍,也就是3。

         <note>
            <duration>3</duration>
            <type>quarter</type>
            <dot/>
         </note>
        
      • tie:表示一个连音的开始和结束。可能会存在多个,有个number属性可以用来区分或者标识具体的tie元素。
        比如下面表示一个连音:

        <note>
         <tie type="start"/>
        </note>
        <note>
         <tie type="stop"/>
         <tie type="start"/>
        </note>
        <note>
         <tie type="stop"/>
        </note>
        
      • lyric:歌词。

        <note>
         <lyric>
             <syllabic>begin</syllabic>
             <text>我爱的</text>//这里是具体的歌词内容
         </lyric>
         </note>
        
      • beam:桥梁,可能存在多个,用来显示八音符,十六分音符底部横梁等。

         <note>
         <beam number="1">begin</beam>
         </note>
         
         <note>
         <beam number="1">continue</beam>
         <beam number="2">begin</beam>
         </note>
        
         <note>
         <beam number="1">continue</beam>
         <beam number="2">end</beam>
         </note>
        
      • notations:里面包含的是这个音符具体的一些信息,比如几弦几品,是什么音之类的信息。具体是下面这些元素:

        • brush:扫弦。因为用的GuitarPro7软件制谱,所以GP7导出的xml里面扫弦是导出是长下面这样的,其他软件不大确定。

          • type:扫弦的方向,
            * down说明是向上扫弦,箭头向上;
            * up说明是向下扫弦,箭头向下。
            <notations>
           <?GP7 <root><brush type="down"/></root>?>
           </notations>
          
        • arpeggiate:琶音。

          • direction:琶音方向,
            * up是向上琶音,箭头向上。
            * down是向下琶音,箭头向下。
            <notations>
              <arpeggiate direction="up"/>
            </notations>
          
        • tuplet:三连音,基本能遇到的就两种吧? 一个是: 八分音符样子的三个,就是一拍的三连音;另外一个是:四分音符样子的三个,就是两排拍的三连音,和beats,beat-type无关。

          • type:来标识三连音的开始和结束,start,stop。
          • number:来区别哪个三连音。
          • placement:支架朝向above-below。
          • bracket:是否显示支架 yes-no。
            ```
             <notations>
             <tuplet type="start" number="1" bracket="yes" placement="below"/>
             <notations>
            ```
        * slide:滑弦,开始音品数大于终止音品数,则是下滑音,否则是上滑音。
            * type:滑音的开始或者结束,start,stop。
            * number:标识。
            
        * slur:连接符,这里一般特指滑音或者击勾弦的连接符,实际使用中貌似可以忽略它的存在,因为slide或者hammer-on元素里面的type属性已经能完整的告诉我们他们的开始和结束了。可能我还没遇到slur的特定情况吧。
            * type:连接的开始或者结束。
        
            ```
             <notations>
             <slur type="start"/>//连接符
             <slide number="5" type="start"/>
             </notations>
            ```
        * tied:这里的tied元素含义和外层tie元素意思是一样的,都是用来表示连音的开始和结束。
                        
            ```
             <notations>
                <tied type="start"/>
             </notations>
            ```
        * technical:这个元素里面是几弦几品,手指,推弦,泛音等一些信息。
            
            ```
             <technical>
              <string>3</string>
              <fret>2</fret>
             <fingering>2</fingering>
             <pluck></pluck>
             </technical>
            ```

            * string:告诉我们这个音符是几弦。
            * fret:告诉我们这个音符是几品。
            * fingering:告诉我们按哪个手指。
            * pluck:左手哪根手指。
            * bend:推弦,推全音或者推半音
                    * bend_alter:推半音还是全音标识,全音2,半音1,回原位0
                    * isRelease:推弦回原位标识,有这个标识是会原位,否则不会。
                    
                    <technical>
                      <bend>
                       <bend-alter>2</bend-alter>
                      </bend>
                      <bend>
                       <bend-alter>0</bend-alter>
                       <release/>
                      </bend>
                     </technical>
                    
            * harmonic,natural:泛音。
                
                ```
                <technical>
                  <harmonic>
                   <natural/>
                   <base-pitch/>
                  </harmonic>
                 </technical>
                ```
            * hammer-on:击勾弦,用的是同一个字段,<fret>品数由小到大是击弦,品数由大到小是勾弦。也可以直接根据hammer-on元素中的内容判断,是`H`基本上就是击弦;勾弦的话内容就是`P`的标识。
                * number:标识。
                * type:击勾弦的开始结束,start,stop。
                比如下面这个,是一个击弦,
        ```
        <note>
            <notations>
             <technical>
              <hammer-on number="1" type="start">H</hammer-on>
              <string>2</string>
              <fret>0</fret>
             </technical>
             <slur type="start"/>
            </notations>
        </note>
        <note>
            <notations>
             <technical>
              <hammer-on number="1" type="stop"/>
              <string>2</string>
              <fret>2</fret>
             </technical>
             <slur type="stop"/>
            </notations>
         </note>
        ```

基本能用到的大多数就是这么多了,更多详细的可以查看MusicXML的官网文档

三 (六线谱)吉他谱绘制

绘制的话,看具体的需求了,可以尝试在layer上异步绘制,然后在需要的情况下再渲染到view上。比如用CAShapeLayer,轻量,性能又好。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容