<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Find Lab</title>
  <icon>https://findlab.github.io/images/favicon.svg</icon>
  
  <link href="https://findlab.github.io/atom.xml" rel="self"/>
  
  <link href="https://findlab.github.io/"/>
  <updated>2026-05-02T02:54:17.445Z</updated>
  <id>https://findlab.github.io/</id>
  
  <author>
    <name>FindLab</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>A concise representation of sheet music vertical structure</title>
    <link href="https://findlab.github.io/2021/10/24/staff-layout/"/>
    <id>https://findlab.github.io/2021/10/24/staff-layout/</id>
    <published>2021-10-24T12:50:29.000Z</published>
    <updated>2026-05-02T02:54:17.445Z</updated>
    
    <content type="html"><![CDATA[<p>In the previous post <a href="/2020/11/15/music-layout-language/">A domain-specific language for sheet music paragraph layout</a>,we discussed how to concisely represent sheet music paragraph structure in computer.Orthogonally, we also need to express the sheet music vertical structure: instruments, staves, voices and their relationship.</p><figure>    <a href="/images/conductor-music-score-sample.png" target="_blank">        <img src="/images/conductor-music-score-sample.png" class="figure" width="480" alt="conductor music score sample">    </a>    <figcaption>        An example for sheet music vertical structure,<br />        we represents this by <em><[-]----><[-]--[-]->{-}</em>    </figcaption></figure><p>We aim to do this concisely and intuitively.And this will be a meta-language which can be exported to other music languges,such as <a href="https://lilypond.org/">Lilypond</a>, <a href="https://www.musicxml.com/">MusicXML</a> and <a href="https://music-encoding.org/">MEI</a>.</p><span id="more"></span><h2 id="The-first-example"><a href="#The-first-example" class="headerlink" title="The first example"></a>The first example</h2><p>I call this mini language <em>staff layout code</em>. This is our ‘hello world’:</p><div class="vue-component staff-layout-viewer" data-init-code="a,b,c" data-read-only="1"></div><p>We can name every staff by an identifier, a string made up with alphabet, number and underscore.</p><h2 id="Conjunctions"><a href="#Conjunctions" class="headerlink" title="Conjunctions"></a>Conjunctions</h2><div class="vue-component staff-layout-viewer" data-init-code="a-b.c,d" data-read-only="1"></div><p>We define barlines between staves in 3 types: solid <code>-</code>, dashed <code>.</code> and blank <code>,</code>.And the blank type is default, can be ignored:</p><div class="vue-component staff-layout-viewer" data-init-code="a b c" data-read-only="1"></div><h2 id="Anonymous-staves"><a href="#Anonymous-staves" class="headerlink" title="Anonymous staves"></a>Anonymous staves</h2><div class="vue-component staff-layout-viewer" data-init-code=" , , " data-read-only="1"></div><p>Staff names is not required to specify. Unnamed staves have number name by default.As a result, the empty string “” is a valid staff layout code, and it represents an anonymous single staff:</p><div class="vue-component staff-layout-viewer" data-init-code=" " data-read-only="1"></div><h2 id="Brackets"><a href="#Brackets" class="headerlink" title="Brackets"></a>Brackets</h2><p>The grand staff:</p><div class="vue-component staff-layout-viewer" data-init-code="{RH-LH}" data-read-only="1"></div><p>We have 3 types of brackets: bracket <code>&lt;&gt;</code>, brace <code>&#123;&#125;</code> and square bracket <code>[]</code>.</p><p>And you can imagine that rotate the code by 90&deg; to corresponds the sheet music:</p><div class="vue-component staff-layout-viewer" data-init-code="<[-].> {-} <>" data-read-only="1" data-show-annotation="1"></div><h1 id="Instrument-names"><a href="#Instrument-names" class="headerlink" title="Instrument names"></a>Instrument names</h1><p>Beside staff layout code, we can define the instrument names by a name dictionary.</p><div class="vue-component staff-layout-viewer" data-init-code=" ,{ - }" data-init-name-dict="{1: 'Voice', '2-3': 'Piano'}" data-read-only="1"></div><p>For <a href="/images/conductor-music-score-sample.png">the example picture</a> above, the complete representation is:</p><div class="vue-component staff-layout-viewer" data-init-code="<[fl-cl]-bcl-asx-tsx-tr> <[vl1-vl2]-viola-[cello1-cello2]-cb> {p1-p2}" data-init-name-dict="{fl: 'Flute 1', cl: 'Clarinet 1', bcl:'Bass Clarinet', asx: 'Alto Saxophone', tsx: 'Tenor Saxophone', tr: 'Trumpet', vl1: 'Violin 1', vl2: 'Violin 2', viola: 'Viola', cello1: 'Cello 1', cello2: 'Cello 2', cb: 'Contrabass', 'p1-p2': 'Piano'}" data-scale="0.7" data-read-only="1"></div><h2 id="Try-it-yourself"><a href="#Try-it-yourself" class="headerlink" title="Try it yourself"></a>Try it yourself</h2><p>Try to customize your own staff layout in below.</p><div class="vue-component staff-layout-viewer" data-init-code="{-}{-}" data-init-name-dict="{'1-2': 'Piano I', '3-4': 'Piano II'}"></div><p>We will open source the language library after some arrangement work.</p><script src="/vue/chunk-vendors.js"></script><script src="/vue/staff-layout-viewer.js"></script>]]></content>
    
    
    <summary type="html">&lt;p&gt;In the previous post &lt;a href=&quot;/2020/11/15/music-layout-language/&quot;&gt;A domain-specific language for sheet music paragraph layout&lt;/a&gt;,
we discussed how to concisely represent sheet music paragraph structure in computer.
Orthogonally, we also need to express the sheet music vertical structure: instruments, staves, voices and their relationship.&lt;/p&gt;
&lt;figure&gt;
    &lt;a href=&quot;/images/conductor-music-score-sample.png&quot; target=&quot;_blank&quot;&gt;
        &lt;img src=&quot;/images/conductor-music-score-sample.png&quot; class=&quot;figure&quot; width=&quot;480&quot; alt=&quot;conductor music score sample&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt;
        An example for sheet music vertical structure,&lt;br /&gt;
        we represents this by &lt;em&gt;&lt;[-]----&gt;&lt;[-]--[-]-&gt;{-}&lt;/em&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;We aim to do this concisely and intuitively.
And this will be a meta-language which can be exported to other music languges,
such as &lt;a href=&quot;https://lilypond.org/&quot;&gt;Lilypond&lt;/a&gt;, &lt;a href=&quot;https://www.musicxml.com/&quot;&gt;MusicXML&lt;/a&gt; and &lt;a href=&quot;https://music-encoding.org/&quot;&gt;MEI&lt;/a&gt;.&lt;/p&gt;</summary>
    
    
    
    
    <category term="sheet music" scheme="https://findlab.github.io/tags/sheet-music/"/>
    
    <category term="DSL" scheme="https://findlab.github.io/tags/DSL/"/>
    
  </entry>
  
  <entry>
    <title>A domain-specific language for sheet music paragraph layout</title>
    <link href="https://findlab.github.io/2020/11/15/music-layout-language/"/>
    <id>https://findlab.github.io/2020/11/15/music-layout-language/</id>
    <published>2020-11-15T16:55:39.000Z</published>
    <updated>2026-05-02T02:54:17.445Z</updated>
    
    <content type="html"><![CDATA[<style>    .highlight .gutter pre    {        color: #86919433;    }</style><h2 id="Motivation"><a href="#Motivation" class="headerlink" title="Motivation"></a>Motivation</h2><p>To avoid redundant writing, there are several repeat types in sheet music to organize paragraph layout.So when performing music, instead of simply from beginning to the end in order, one should obey musical signs to jump position.Probably we can separate music paragraph layout information from music staff content when recording a sheet music.I.e., create a new tiny domain-specific language to express sheet music structure.It’s especially meaningful for computer musical lanugages, such as <a href="https://lilypond.org/">Lilypond</a> and <a href="http://abcnotation.com/">ABC Notation</a>.Consider this: for a multiple voices music, in voice-wise form, we must record the repeat symbols in every voice,and carefully keep them consistent to avoid weird errors.And for the languages’ implementation, it’s troublesome to handle this kind semantic error.For users, it’s covert and confused.Once we can record the music paragraph layout individually, we can simply record multiple voice staff in a 2-d table form, a measure-voice matrix, like this:</p><table><thead><tr><th align="center"></th><th align="center">measure 1</th><th align="center">measure 2</th><th align="center">measure 3</th><th align="center">…</th></tr></thead><tbody><tr><td align="center"><strong>voice 1</strong></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td></tr><tr><td align="center"><strong>voice 2</strong></td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td></tr><tr><td align="center">…</td><td align="center"></td><td align="center"></td><td align="center"></td><td align="center"></td></tr></tbody></table><p>This regular form will facilitate music score clipping&#x2F;slicing, which is useful for music education courseware and instrument training.And it also facilitates music-related deep learning tasks, such as <a href="https://en.wikipedia.org/wiki/Optical_music_recognition">OMR</a>, AI music composition and so on.</p><h2 id="How-to-express-a-music-paragraph-layout"><a href="#How-to-express-a-music-paragraph-layout" class="headerlink" title="How to express a music paragraph layout"></a>How to express a music paragraph layout</h2><p>We should design this language as intuitive as possible, make it understandable to users without any computer programming knowledges.</p><p>Let’s start with a simple example:</p><h3 id="Example-1"><a href="#Example-1" class="headerlink" title="Example 1"></a>Example 1</h3><p><img src="/images/music-score/layout-sample-simple.svg" alt="layout-sample-simple"></p><p>Code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1, 2, 3, 4</span><br></pre></td></tr></table></figure><p>The code is simply the list of measure indices.</p><p>Before more complicated examples, let’s take this two-parts score as a transition:</p><h3 id="Example-2"><a href="#Example-2" class="headerlink" title="Example 2"></a>Example 2</h3><p><img src="/images/music-score/layout-sample-2-segments.svg" alt="layout-sample-2-segments"></p><p>Code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[1, 2, 3, 4], [5, 6, 7, 8]</span><br></pre></td></tr></table></figure><p>Here brackets ‘[]’ are used to segment measure indices into paragraphs.</p><p>For a long score, writing all serial numbers is tedious, so we adopt this brief form as a syntactic sugar:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[1..4], [5..8]</span><br></pre></td></tr></table></figure><span id="more"></span><p>Till now we call these code as <em>index-wise</em> form.You may notice that this form has an implicit rule that users must keep numbers continuous themselves,theoretically someone can write a semantic-ill code like <code>1, 3, 2, 4</code> or <code>[1..4], [3..6]</code>, which make no sense.So we create another <em>segment-wise</em> form, which may be more favourite for some developers. For <em>example 2</em>, it’s like:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s: 4 4</span><br></pre></td></tr></table></figure><p>Here <code>4</code> stands for a measure segment with length 4.To distinguish against index-wise, we must use a prefix of <code>s:</code>. And here are 2 tips:</p><ul><li>Also you can use <code>i:</code> to explicitly specify form for index-wise, but because it’s the default form, so can be ignored.</li><li>You can also write brackets around every number in segment-wise code, but we prefer the brief form to ignore them.  And also for brief and distinguishing, no commas.</li></ul><p>However, we think to write measure indices explicitly for measure ranges is an advantage in most of time, so we adopt the index-wise as the default form.</p><p>Next, the repeat example:</p><h3 id="Example-3-simple-repeat"><a href="#Example-3-simple-repeat" class="headerlink" title="Example 3, simple repeat"></a>Example 3, simple repeat</h3><p><img src="/images/music-score/layout-sample-volta.svg" alt="layout-sample-volta"></p><p>Index-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2*[1, 2], 3</span><br></pre></td></tr></table></figure><p>Segment-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s: 2*[2] 1</span><br></pre></td></tr></table></figure><p><code>n*</code> stands for repeat a measure segment <em>n</em> times.After <code>n*</code>, there must be a bracketed measure segment.</p><p>The expanded measure index list will be:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1 2 | 1 2 | 3</span><br></pre></td></tr></table></figure><p>Notice that the <em>expanded measure index list</em> is <strong>not</strong> a part of our new language, just a text for illustration.</p><p>Repeat with alternative postfixes:</p><h3 id="Example-4-repeat-alternative"><a href="#Example-4-repeat-alternative" class="headerlink" title="Example 4, repeat-alternative"></a>Example 4, repeat-alternative</h3><p><img src="/images/music-score/layout-sample-alternative.svg" alt="layout-sample-alternative"></p><p>Index-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2*[1, 2]&#123;3, 4&#125;</span><br></pre></td></tr></table></figure><p>Segment-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s: 2*[2]&#123;1 1&#125;</span><br></pre></td></tr></table></figure><p>Expanded measure index list:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1 2 | 3 | 1 2 | 4</span><br></pre></td></tr></table></figure><p>Inside braces <code>&#123;&#125;</code> should be 2 or more measure segments or single measure indices.</p><p>Next, for some advanced repeat types.We observed that, all the forms of <em>Da Capo</em>&#x2F;<em>Dal Segno</em> <em>al</em> <em>Fine</em>&#x2F;<em>Coda</em> can be abstracted into an ‘ABA’ type:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;A, B&gt; =&gt; A B A</span><br></pre></td></tr></table></figure><p>Here <code>A</code> <code>B</code> stand for 2 measure segments.</p><p>For instance, that’s:</p><table><thead><tr><th align="center">Music form</th><th align="center">Expanded segments</th></tr></thead><tbody><tr><td align="center"><strong>A</strong> <code>Fine</code> <strong>B</strong> <code>D.C. al Fine</code></td><td align="center"><strong>A B A</strong></td></tr><tr><td align="center">X &#x1D10B; <strong>A</strong> <code>Fine</code> <strong>B</strong> <code>D.S. al Fine</code></td><td align="center">X <strong>A B A</strong></td></tr><tr><td align="center"><strong>A</strong> &#x1D10C; <strong>B</strong> <code>D.C. al Coda</code> &#x1D10C; Y</td><td align="center"><strong>A B A</strong> Y</td></tr><tr><td align="center">X &#x1D10B; <strong>A</strong> &#x1D10C; <strong>B</strong> <code>D.S. al Coda</code> &#x1D10C; Y</td><td align="center">X <strong>A B A</strong> Y</td></tr></tbody></table><p>If you know some exceptional cases, please tell us.</p><p>Take these 2 examples to illustrate it:</p><h3 id="Example-5-Da-Capo-al-Fine"><a href="#Example-5-Da-Capo-al-Fine" class="headerlink" title="Example 5, Da Capo al Fine"></a>Example 5, Da Capo al Fine</h3><p><img src="/images/music-score/layout-sample-DCalFine.svg" alt="layout-sample-DCalFine"></p><p>Index-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;[1, 2], 3, 4&gt;</span><br></pre></td></tr></table></figure><p>Segment-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s: &lt;2 2&gt;</span><br></pre></td></tr></table></figure><p>Expanded measure index list:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1 2 | 3 4 | 1 2</span><br></pre></td></tr></table></figure><p>Inside chevrons <code>&lt;&gt;</code> is a list of measure segments, which the first item of the list will be repeated once.</p><h3 id="Example-6-Dal-Segno-al-Coda"><a href="#Example-6-Dal-Segno-al-Coda" class="headerlink" title="Example 6, Dal Segno al Coda"></a>Example 6, Dal Segno al Coda</h3><p><img src="/images/music-score/layout-sample-DSalCoda.svg" alt="layout-sample-DSalCoda"></p><p>Index-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1..4, &lt;[5, 6], 7..12&gt;, 13, 14</span><br></pre></td></tr></table></figure><p>Segment-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s: 4 &lt;2 6&gt; 2</span><br></pre></td></tr></table></figure><p>Expanded measure index list:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1 2 3 4 | 5 6 | 7 8 9 10 11 12 | 5 6 | 13 14</span><br></pre></td></tr></table></figure><p>At last, let’s show a miscellaneous example.</p><h3 id="Example-7"><a href="#Example-7" class="headerlink" title="Example 7"></a>Example 7</h3><p>The music score is too long to show, click this link to see the sheet: <a href="/images/music-score/ma-vlast.svg"><em>Má vlast</em></a></p><p>Index-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1, &lt;[2*[2..8]&#123;9, 10&#125;, 11..27], 2*[28..34]&#123;35, 36&#125;, 37&gt;, 38..61</span><br></pre></td></tr></table></figure><p>Segment-wise code:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s: 1 &lt;[2*[7]&#123;1 1&#125; 17] 2*[7]&#123;1 1&#125; 1&gt; 24</span><br></pre></td></tr></table></figure><p>Expanded measure index list:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">1</span><br><span class="line">2 3 4 5 6 7 8 | 9 | 2 3 4 5 6 7 8 | 10</span><br><span class="line">11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27</span><br><span class="line">28 29 30 31 32 33 34 | 35 | 28 29 30 31 32 33 34 | 36</span><br><span class="line">37</span><br><span class="line">2 3 4 5 6 7 8 | 10 | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27</span><br><span class="line">38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61</span><br></pre></td></tr></table></figure><h2 id="Grammar-live-test"><a href="#Grammar-live-test" class="headerlink" title="Grammar live test"></a>Grammar live test</h2><p>We have implemented a basic grammar parser by <a href="https://zaa.ch/jison/">JISON</a> (the javascript version of BISON).Try it yourself at this link:</p><p><a href="https://k-l-lambda.github.io/klstudio/jison-debugger/#grammar=https%3A%2F%2Fraw.githubusercontent.com%2Fk-l-lambda%2Flotus%2Fmaster%2Fjison%2FmeasureLayout.jison|2*%5B1..4%5D%7B5%2C6%7D"><strong>JISON debugger</strong></a></p><h2 id="An-application-demo"><a href="#An-application-demo" class="headerlink" title="An application demo"></a>An application demo</h2><p>This is a video demo to illustrate how our new language code is working with Lilypond when composing a music score.</p><div class="video-container"><iframe src="https://www.youtube.com/embed/uUOV-Kjrt4M" frameborder="0" allowfullscreen></iframe></div><h2 id="Next-step"><a href="#Next-step" class="headerlink" title="Next step"></a>Next step</h2><p>It still leaves over some pending issues with this language, we are considering some more grammar elements to express:</p><ul><li>   Unspecified index list, to allow user to ignore indices at score boundary, as <code>..</code> instead of <code>1..8</code>, and <code>2*[..4], 5..</code> instead of <code>2*[1..4], 5..8</code>.</li><li>   Time signature change</li><li>   Partial measures &amp; sub-measure time mark</li><li>   Anacrusis (upbeat beginning) music</li></ul><p>Welcome to discuss any more features you want.</p>]]></content>
    
    
    <summary type="html">&lt;style&gt;
    .highlight .gutter pre
    {
        color: #86919433;
    }
&lt;/style&gt;

&lt;h2 id=&quot;Motivation&quot;&gt;&lt;a href=&quot;#Motivation&quot; class=&quot;headerlink&quot; title=&quot;Motivation&quot;&gt;&lt;/a&gt;Motivation&lt;/h2&gt;&lt;p&gt;To avoid redundant writing, there are several repeat types in sheet music to organize paragraph layout.
So when performing music, instead of simply from beginning to the end in order, one should obey musical signs to jump position.
Probably we can separate music paragraph layout information from music staff content when recording a sheet music.
I.e., create a new tiny domain-specific language to express sheet music structure.
It’s especially meaningful for computer musical lanugages, such as &lt;a href=&quot;https://lilypond.org/&quot;&gt;Lilypond&lt;/a&gt; and &lt;a href=&quot;http://abcnotation.com/&quot;&gt;ABC Notation&lt;/a&gt;.
Consider this: for a multiple voices music, in voice-wise form, we must record the repeat symbols in every voice,
and carefully keep them consistent to avoid weird errors.
And for the languages’ implementation, it’s troublesome to handle this kind semantic error.
For users, it’s covert and confused.
Once we can record the music paragraph layout individually, we can simply record multiple voice staff in a 2-d table form, a measure-voice matrix, like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;center&quot;&gt;&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;measure 1&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;measure 2&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;measure 3&lt;/th&gt;
&lt;th align=&quot;center&quot;&gt;…&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;voice 1&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;voice 2&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot;&gt;…&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This regular form will facilitate music score clipping&amp;#x2F;slicing, which is useful for music education courseware and instrument training.
And it also facilitates music-related deep learning tasks, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Optical_music_recognition&quot;&gt;OMR&lt;/a&gt;, AI music composition and so on.&lt;/p&gt;
&lt;h2 id=&quot;How-to-express-a-music-paragraph-layout&quot;&gt;&lt;a href=&quot;#How-to-express-a-music-paragraph-layout&quot; class=&quot;headerlink&quot; title=&quot;How to express a music paragraph layout&quot;&gt;&lt;/a&gt;How to express a music paragraph layout&lt;/h2&gt;&lt;p&gt;We should design this language as intuitive as possible, make it understandable to users without any computer programming knowledges.&lt;/p&gt;
&lt;p&gt;Let’s start with a simple example:&lt;/p&gt;
&lt;h3 id=&quot;Example-1&quot;&gt;&lt;a href=&quot;#Example-1&quot; class=&quot;headerlink&quot; title=&quot;Example 1&quot;&gt;&lt;/a&gt;Example 1&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;/images/music-score/layout-sample-simple.svg&quot; alt=&quot;layout-sample-simple&quot;&gt;&lt;/p&gt;
&lt;p&gt;Code:&lt;/p&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1, 2, 3, 4&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;The code is simply the list of measure indices.&lt;/p&gt;
&lt;p&gt;Before more complicated examples, let’s take this two-parts score as a transition:&lt;/p&gt;
&lt;h3 id=&quot;Example-2&quot;&gt;&lt;a href=&quot;#Example-2&quot; class=&quot;headerlink&quot; title=&quot;Example 2&quot;&gt;&lt;/a&gt;Example 2&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;/images/music-score/layout-sample-2-segments.svg&quot; alt=&quot;layout-sample-2-segments&quot;&gt;&lt;/p&gt;
&lt;p&gt;Code:&lt;/p&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;[1, 2, 3, 4], [5, 6, 7, 8]&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;p&gt;Here brackets ‘[]’ are used to segment measure indices into paragraphs.&lt;/p&gt;
&lt;p&gt;For a long score, writing all serial numbers is tedious, so we adopt this brief form as a syntactic sugar:&lt;/p&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;[1..4], [5..8]&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;</summary>
    
    
    
    
    <category term="sheet music" scheme="https://findlab.github.io/tags/sheet-music/"/>
    
    <category term="lilypond" scheme="https://findlab.github.io/tags/lilypond/"/>
    
    <category term="DSL" scheme="https://findlab.github.io/tags/DSL/"/>
    
  </entry>
  
  <entry>
    <title>We ported Lilypond to Android</title>
    <link href="https://findlab.github.io/2020/10/23/lilypond-android/"/>
    <id>https://findlab.github.io/2020/10/23/lilypond-android/</id>
    <published>2020-10-23T22:48:31.000Z</published>
    <updated>2026-05-02T02:54:17.445Z</updated>
    
    <content type="html"><![CDATA[<div class="video-container"><iframe src="https://www.youtube.com/embed/ay13Dk6D60M" frameborder="0" allowfullscreen></iframe></div><figure><figcaption>The Android porting of Lilypond has been done by us, you're welcome.</figcaption></figure><p>As a sheet music program, <a href="https://lilypond.org/">Lilypond</a> is high-quality and sophisticated, but not as modern as its several competitors,such as <a href="https://www.verovio.org/index.xhtml">Verovio</a> and <a href="https://opensheetmusicdisplay.org/">OSMD</a>.For nowadays, let’s consider a good sheet music engine:working with HTML5 facilitates animating features development, and mobile devices are the best choice for instruments playing assistance.Yes, serving requests online is an option, but the service is inevitably expensive and slow.Computing on the device is still the best practice.</p><span id="more"></span><p>This attempt is a start. We demonstrated that porting Lilypond to Android can be got through.Certainly it can be implemented in a neater, official way.For future, we are considering these issues:</p><ul><li><p>Porting Lilypond to iOS.</p></li><li><p>Accelerating Lilypond engraving, possibly by accelerating its Scheme virtual machine.If this can be done, it will improve Lilypond’s competitivity greatly.</p></li><li><p>Can we manipulate graph music elements from an intermediate representation,so that avoid re-parsing ly code every time for trivial change?Also possibly we can implement an HTML5 renderer for this intermediate format.</p></li></ul><p>This is our <a href="https://gitlab.com/k.l.lambda/lilypond">forked repository of Lilypond on GitLab</a>.Welcome to disucss technical details here.</p>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;video-container&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/ay13Dk6D60M&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;figure&gt;
&lt;figcaption&gt;The Android porting of Lilypond has been done by us, you&#39;re welcome.&lt;/figcaption&gt;
&lt;/figure&gt;


&lt;p&gt;As a sheet music program, &lt;a href=&quot;https://lilypond.org/&quot;&gt;Lilypond&lt;/a&gt; is high-quality and sophisticated, but not as modern as its several competitors,
such as &lt;a href=&quot;https://www.verovio.org/index.xhtml&quot;&gt;Verovio&lt;/a&gt; and &lt;a href=&quot;https://opensheetmusicdisplay.org/&quot;&gt;OSMD&lt;/a&gt;.
For nowadays, let’s consider a good sheet music engine:
working with HTML5 facilitates animating features development, and mobile devices are the best choice for instruments playing assistance.
Yes, serving requests online is an option, but the service is inevitably expensive and slow.
Computing on the device is still the best practice.&lt;/p&gt;</summary>
    
    
    
    
    <category term="sheet music" scheme="https://findlab.github.io/tags/sheet-music/"/>
    
    <category term="lilypond" scheme="https://findlab.github.io/tags/lilypond/"/>
    
  </entry>
  
  <entry>
    <title>A proposal for content based MIDI files indexing and retrieving on piano</title>
    <link href="https://findlab.github.io/2020/03/08/midi-indexing/"/>
    <id>https://findlab.github.io/2020/03/08/midi-indexing/</id>
    <published>2020-03-08T13:12:57.000Z</published>
    <updated>2026-05-02T02:54:17.445Z</updated>
    
    <content type="html"><![CDATA[<figure>    <picture>        <source srcset="/images/gfind-crystal.webp" type="image/webp" />        <source srcset="/images/gfind-crystal.png" type="image/png" />        <img src="/images/gfind-crystal.png" class="figure" width="400" alt="smart piano">    </picture>    <figcaption>A smart piano.</figcaption></figure><h2 id="Motivation"><a href="#Motivation" class="headerlink" title="Motivation"></a>Motivation</h2><p>Imagine you have a smart piano at home, which is connected with a huge music staff library.Once, you want to play some music opus on a whim, and it’s so bothering to retrieve music staff in either category menus or a long favorite list,therefore, you just play by memory directly.But the piano is so smart. Just a few seconds later, it understands what you are playing and displays the staff automatically.</p><p>Let’s look at another case: you see a nice piano when hanging out downtown and you are just in a mood to play a piece of music and show off your talent to passers.When you sit and play, surprisingly, the piano displays the music information about what you are playing.When you finish, it says, well done! Your performance beat 95% players on this opus.</p><p>Imaginary scenes above are coming true. Now let’s talk about some ideas for implementing such a technique.</p><span id="more"></span><h2 id="Related-work"><a href="#Related-work" class="headerlink" title="Related work"></a>Related work</h2><p>Early in 1999, Cavalcanti et al. proposed a MIDI indexing system scheme[^1].The system converts a melody notes sequence into a new sequence of 7 dimensional[^2] wavelet transformed vectors,then match a piece of query melody notes by measuring Euclidean distance between feature vectors.This scheme has several advantages:</p><ul><li><p>Local matching. Query melody can be a short fragment, whose length is just enough to distinguish source music from other similar ones.</p></li><li><p>Key insensitive, i.e. the query melody can be on a different key with source melody.Because wavelet transformed vectors only extract relative pitch information.</p></li><li><p>Pitch error tolerance. Euclidean distance magnitude of feature vectors reflects the similarity of melody fragments.If query melody has slight off-pitch from correct source melody, distance loss will keep tiny.</p></li></ul><p>However, for our particular purpose of MIDI retrieving for piano playing, there are some issues in this scheme:</p><ul><li><p>Wavelet transform is performing on a single melody line, while a piano music opus usually has rich harmony texture,and splitting melody voice from the whole music texture is troublesome:some polyphony music piece has no definite main melody line,some MIDI files made from piano staff splits tracks by left&#x2F;right hand, not voices.</p></li><li><p>Furthermore, harmony voices are meaningful, but ignored by this scheme.Most of popular songs have several versions sharing the same melody, but with different harmony arrangements.Query notes in harmony voice can be just a fingerprint of the user’s searching goals.</p></li><li><p>The notes sequence processing is sensitive to omit&#x2F;extra note.Though a deviated note can be tolerant by this scheme, but omit&#x2F;extra ones are not.Because note count change will break fragments splitting, especially when an interval between 2 neighbor error places is less than fragment length 2<sup>k</sup>.</p></li></ul><p>We propose a new approach to deal with MIDI retrieving with input interface of piano playing, which divides this task into 2 phases:pitch frequency indexing (rough phase) and music fuzzy matching (fine phase). The fine phase is also a robust score following algorithm,which plays a key role in the smart piano user interactive system, also a pending patent.I hope there is another opportunity to talk about the details of the score following method. In this article, we focus on the rough phase.</p><h2 id="How-it-works"><a href="#How-it-works" class="headerlink" title="How it works"></a>How it works</h2><p>A score following program is an agent to guess where place in a specific music score, the user is playing at right now.As hint by the word <em>guess</em> (or <em>fuzzy</em>), the program will output a confidence value to tell how confident it believes itself result.</p><p>Now, what if we use a wrong score to follow? Obviously, any possible guessing won’t be with high confidence.Probably some fragment in user playing sequence is similar to the (wrongly) specific score someplace, but the matching must be highly fragmentized.If we measure the typical continuous following length with a proper confidence threshold, a normal score following will completely beat a wrong score following.</p><p>So now we have a touchstone to check how well a music score matches what the user is playing, and if we run this program on all scores we possess simultaneously,we are able to pick the best matching score by results sorting. Certainly, it’s not practicable&#x1f604;.However, if we sieve off those obvious impossible candidates, and a small left magnitude can be affordable.So this is the rough phase, the design aim is fast and concurrency, not precise. And for possible candidates, rather let it go than kill.</p><p>To construct a MIDI indexing, available properties of music piece include pitch, time and velocity (strength).Velocity&#x2F;strength is out firstly because of its highly mutable.Time property is valuable to identify a score, but the time data recorded from human playing is usually recorded in millisecond or microsecond,which is very continuous (in contrast, pitch values from keyboard instruments are always discrete in semitone), and difficult to extract identifying information.However, time information utilizing is an open problem to exploit in the future.</p><p>Inevitably, pitch is the last option.To fast index scores, we convert the pitch characteristic of entire candidate score (or user playing) notes into several integer numbers.The filter operation, pass or failure judgment is done by binary number calculation, which is fast and constant to single score length($O(n)$ to candidate scores count, but can be optimized by concurrency).</p><p>The pitch characteristic is accumulative to notes, and a music piece with more notes has stronger characteristics,i.e. as the user keeps playing, more and more candidate scores will be sieved off.Once candidate scores count is lower than an affordable threshold, we will run the fine phase.</p><p>We define an efficiency benchmark:</p><p>$$ \textrm{filter stregth} :&#x3D; 1 - \frac{\textrm{left candidate count}}{\textrm{total candidate count}} $$</p><p>As long as we didn’t miss the potential goal score, we will do our best to enhance the filter strength.</p><h2 id="Pitch-frequency-indexing"><a href="#Pitch-frequency-indexing" class="headerlink" title="Pitch frequency indexing"></a>Pitch frequency indexing</h2><p>For a particular MIDI file, the attendance frequency of every pitch can be used as a unique signature.Try to play this MIDI file, and the histogram below will illustrate what is <em>pitch frequency</em> we talk about.</p><div class="vue-component midi-pitches-counter" data-midi-url="/midi/Minuets_in_G_major.mid"></div><p>When someone is playing a song A, let’s use $\textbf{A}$ to denote the notes set of song A,and $\textbf{B}$ to denote the notes set which the user has played by now.Supposing the user’s playing has no errors, we have $\textbf{B} \subseteq \textbf{A}$.And for another different song C, we have some chance that $\textbf{B} \nsubseteq \textbf{C}$,or $\textbf{B} \cap \overline{\textbf{C}} \neq \phi$.As playing goes on, the probability of B over C keeps increasing.</p><p>We can just compare every pitch frequency one by one to perform the checking,but dozens integer comparing per song has heavy costs for a large library.We optimize this by coarsening pitch frequency histogram to several bit mask codes.A piano has 88 keys, rather than to store 88 numbers vertically, we can also store the information horizontally,i.e. by an 88 bits binary number, whose each bit represents one pitch’s attendance&#x2F;absence.Furthermore, we set <strong>T</strong> thresholds (for example T&#x3D;4),and use T bit mask codes to store whether each pitch frequency number is over the corresponding threshold.</p><p>To choose these thresholds reasonably, we plot the pitch frequency distribution graph for a typical music set,which contains hundreds of popular classical and modern songs.</p><figure>    <div class="vue-component chart" data-type="Line" data-source="/charts/score-pitch-frequency-dist.json"></div>    <figcaption>        Concat all pitch frequency columns of 243 popular songs togather, and sort them by value.    </figcaption></figure><p>To tolerate sporadic error notes, we set the lowest threshold to 4. And for columns above 4, we divide pitch columns into four sections equally.Then the values on every boundary are our thresholds. Coincidentally, they are exactly on powers of 2.</p><p>Here is an example, the entire MIDI’s pitch frequency histogram of <em>Minuet in G Major</em>:</p><div class="vue-component chart" data-source="/charts/pitch-histogram-minuet-in-Gmajor.json"></div><p>And the coarsen result:</p><div class="vue-component chart" data-source="/charts/pitch-mask-minuet-in-Gmajor.json"></div><p>All frequency columns are coarsened to four ranks according to thresholds of 4, 8, 16, 32.Finally, we get four bitmasks (converting black blocks to 1, white blocks to 0):</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">0b0000000000000000000000100000010101101011010101101011110101101010000000000000000000000000</span><br><span class="line">0b0000000000000000000000000000010001101011010001101011110101100000000000000000000000000000</span><br><span class="line">0b0000000000000000000000000000000000101011010000101011010100000000000000000000000000000000</span><br><span class="line">0b0000000000000000000000000000000000000000000000101011010000000000000000000000000000000000</span><br></pre></td></tr></table></figure><p>Then we can simply define the check function like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">maskCheck = <span class="function">(<span class="params">query, song</span>) =&gt;</span> (query &amp; ~song) == <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">songCheck = <span class="function">(<span class="params">queryMasks, songMasks</span>) =&gt;</span></span><br><span class="line">   <span class="title function_">maskCheck</span>(queryMasks[<span class="number">0</span>], songMasks[<span class="number">0</span>])</span><br><span class="line">&amp;&amp; <span class="title function_">maskCheck</span>(queryMasks[<span class="number">1</span>], songMasks[<span class="number">1</span>])</span><br><span class="line">&amp;&amp; <span class="title function_">maskCheck</span>(queryMasks[<span class="number">2</span>], songMasks[<span class="number">2</span>])</span><br><span class="line">&amp;&amp; <span class="title function_">maskCheck</span>(queryMasks[<span class="number">3</span>], songMasks[<span class="number">3</span>]);</span><br></pre></td></tr></table></figure><p>So we store pitch frequency masks for every song in DB, and we compute masks for user played notes in real-time.Then we can do a high-performance music indexing.</p><p>Technically, we can encode these mask codes into 11 32-bits integers (88&times;4&#x3D;32&times;11),ordered by from center to both sides (because the center area has more 1s than margins usually).To reduce calculation, we exclude pure zeros in query mask codes before comparing, because zero mask won’t sieve off any songs.And we can perform multiple passes for each query code, every pass is only performed on the rest songs after prior sifts.However, all the above are suggestions, the algorithm details should depend on your hardware implementation and low-level APIs.</p><p>Here is a live demo to illustrate how this work:</p><figure>    <datalist id="midi-list">        <option value="/midi/Turkish_Rondo.mid">        <option value="/midi/Minuets_in_G_major.mid">        <option value="/midi/Fur_Elise.mid">        <option value="/midi/Chopin_Nocturne_in_E_flat_major.mid">        <option value="/midi/Ballade_pour_Adeline.mid">        <option value="/midi/Wings_of_Silence.mid">    </datalist>    <div class="vue-component midi-pitches-mask" data-source-list="#midi-list"></div>    <figcaption style="text-align: left">        <span style="color: #3ea6ef">&#x275a;</span> coarse pitch histogram of candidate MIDI<br/>        <span style="color: #00e5b0">&#x275a;</span> full pitch histogram of query MIDI<br/>        <span style="color: red">&#x275a;</span> coarse pitch histogram of query MIDI<br/>    </figcaption></figure><p>You may notice that some song takes quite a long time to exclude all other songs.Firstly, our purpose for this phase is not to exclude all other songs, but shrink the possible range into an affordable size.Secondly, we have another supplementary trick in the next chapter.</p><h2 id="Head-pitch-mask-indexing"><a href="#Head-pitch-mask-indexing" class="headerlink" title="Head pitch mask indexing"></a>Head pitch mask indexing</h2><p>In most cases, people play a piece of music from the beginning rather than from somewhere middle.Pitches combination to the head a few notes is also a characteristic signature.So we can use the head pitch mask indexing as an alternative music sift method,if this failed, i.e. too many songs left or none left (maybe the user is not playing from the beginning),we then perform pitch frequency indexing.</p><p>In head pitch mask indexing, we only store one mask number to represent the attendance&#x2F;absence of each pitch.We pick notes from the head of a song, according to these rules:</p><ol><li><p>Pick 10 notes at most, because people have 10 fingers, and for piano score, 10 notes must contain the entire first chord.[^3]</p></li><li><p>Unless conflicted with <em>rule 1</em>, pick <strong>N</strong> difference pitches at least. N is a constant which we will mention later.</p></li><li><p>Unless conflicted with <em>rule 1</em>, end of picked notes must contain an entire chord.To tolerate tendency order error when user play chord, arpeggio or some fast music progress,we choose an tolerance interval $\epsilon$ (for example, $\epsilon$&#x3D;120ms),the last picked note’s begin time $t_x$ must satisfy:$$t_{x+1} - t_{x} &gt; \epsilon$$</p></li></ol><p>For generating masks of candidate songs, we obey all rules.And for query mask, we ignore <em>rule 3</em> to guarantee query mask is a subset of candidate mask for the same song.</p><p>Here are examples:</p><ul><li><p><em>Butterfly Lovers (梁祝)</em></p><div class="vue-component midi-head-mask" data-time-scale="0.018">  {      "notes": [{"start":90,"duration":680,"velocity":56,"pitch":74},{"start":632.5,"duration":610,"velocity":63,"pitch":71},{"start":1145,"duration":587.5,"velocity":73,"pitch":69},{"start":1742.5,"duration":585,"velocity":38,"pitch":55},{"start":1752.5,"duration":2230,"velocity":53,"pitch":67},{"start":2370,"duration":577.5,"velocity":45,"pitch":62},{"start":2850,"duration":552.5,"velocity":68,"pitch":59},{"start":3305,"duration":615,"velocity":64,"pitch":57},{"start":3907.5,"duration":2385,"velocity":47,"pitch":55},{"start":4522.5,"duration":657.5,"velocity":76,"pitch":69},{"start":5022.5,"duration":632.5,"velocity":84,"pitch":66},{"start":5530,"duration":550,"velocity":81,"pitch":64},{"start":6080,"duration":2265,"velocity":50,"pitch":62},{"start":6597.5,"duration":655,"velocity":59,"pitch":57},{"start":7157.5,"duration":567.5,"velocity":61,"pitch":54},{"start":7672.5,"duration":557.5,"velocity":51,"pitch":52},{"start":8242.5,"duration":1367.5,"velocity":43,"pitch":50},{"start":8955,"duration":537.5,"velocity":69,"pitch":78},{"start":9450,"duration":502.5,"velocity":89,"pitch":76},{"start":9952.5,"duration":562.5,"velocity":95,"pitch":78}]  }</div></li><li><p><em>Étude Op. 10, No. 3 (Chopin)</em></p><div class="vue-component midi-head-mask" data-time-scale="0.03">  {      "notes": [{"start":93.75,"duration":243.75,"velocity":41,"pitch":59},{"start":984.375,"duration":1338.541666666666,"velocity":49,"pitch":64},{"start":1015.625,"duration":1635.416666666666,"velocity":25,"pitch":40},{"start":1027.083333333333,"duration":692.708333333333,"velocity":32,"pitch":56},{"start":1667.708333333333,"duration":697.9166666666661,"velocity":34,"pitch":59},{"start":1677.083333333333,"duration":741.6666666666661,"velocity":24,"pitch":47},{"start":2183.333333333333,"duration":659.375,"velocity":53,"pitch":63},{"start":2183.333333333333,"duration":702.083333333333,"velocity":34,"pitch":56},{"start":2704.166666666666,"duration":648.9583333333321,"velocity":51,"pitch":64},{"start":2704.166666666666,"duration":765.6249999999991,"velocity":36,"pitch":59},{"start":2704.166666666666,"duration":797.9166666666661,"velocity":23,"pitch":47},{"start":3258.333333333332,"duration":644.791666666667,"velocity":29,"pitch":57},{"start":3268.749999999999,"duration":2665.624999999999,"velocity":51,"pitch":66},{"start":3280.208333333332,"duration":2803.125,"velocity":36,"pitch":63},{"start":3301.041666666665,"duration":1448.958333333333,"velocity":28,"pitch":35},{"start":3852.083333333332,"duration":396.875,"velocity":30,"pitch":59},{"start":3862.499999999999,"duration":471.8749999999991,"velocity":24,"pitch":47},{"start":4344.791666666664,"duration":596.875,"velocity":28,"pitch":57},{"start":4857.291666666664,"duration":705.2083333333339,"velocity":28,"pitch":59},{"start":4867.70833333333,"duration":422.9166666666679,"velocity":26,"pitch":47}]  }</div></li><li><p><em>Fur Elise</em></p><div class="vue-component midi-head-mask" data-time-scale="0.04">  {      "notes": [{"start":91.66666666666652,"duration":374.99999999999955,"velocity":41,"pitch":76},{"start":419.79166666666606,"duration":329.16666666666697,"velocity":68,"pitch":75},{"start":698.958333333333,"duration":301.04166666666606,"velocity":55,"pitch":76},{"start":941.6666666666661,"duration":309.375,"velocity":51,"pitch":75},{"start":1197.916666666666,"duration":292.70833333333394,"velocity":52,"pitch":76},{"start":1439.583333333333,"duration":293.75,"velocity":48,"pitch":71},{"start":1668.75,"duration":317.70833333333303,"velocity":59,"pitch":74},{"start":1904.166666666666,"duration":273.95833333333394,"velocity":48,"pitch":72},{"start":2150,"duration":239.58333333333303,"velocity":56,"pitch":69},{"start":2184.375,"duration":835.4166666666661,"velocity":34,"pitch":45},{"start":2408.333333333333,"duration":565.625,"velocity":45,"pitch":52},{"start":2642.708333333333,"duration":139.58333333333303,"velocity":45,"pitch":57},{"start":2888.541666666666,"duration":286.45833333333303,"velocity":57,"pitch":60},{"start":3115.624999999999,"duration":403.125,"velocity":65,"pitch":64},{"start":3356.249999999999,"duration":285.41666666666606,"velocity":65,"pitch":69},{"start":3578.124999999999,"duration":754.166666666667,"velocity":62,"pitch":71},{"start":3602.083333333332,"duration":197.91666666666697,"velocity":41,"pitch":40},{"start":3843.749999999999,"duration":201.04166666666697,"velocity":44,"pitch":52},{"start":4061.458333333333,"duration":59.375,"velocity":60,"pitch":56},{"start":4290.625,"duration":362.5,"velocity":48,"pitch":64}]  }</div></li></ul><p>To choose a proper value for <strong>N</strong>, we plot the diversity graph of head pitch masks.</p><figure>    <div class="vue-component chart" data-source="/charts/head-pitch-mask-set.json"></div>    <figcaption>        Counts of unique head pitch masks to every N value, in a 4013 songs MIDI library.    </figcaption></figure><p>We want to maximize head pitch mask diversity, i.e. minimize the cases of duplicated masks for different MIDI files.So we choose N&#x3D;5, which coincide with my intuition.But a little surprised, we observed that the diversity to N of greater than 5 decreases quickly.</p><h2 id="Next-step"><a href="#Next-step" class="headerlink" title="Next step"></a>Next step</h2><p>In our experiment, we run our retrieving program on a MIDI music library of about 6,000 songs.We try <em>head pitch mask indexing</em> + <em>score following evaluation</em> firstly.If this failed (usually by no any song left after indexing[^4], or all score following evaluation’s result values are too low),we try <em>pitch frequency indexing</em> every 16 notes by user playing, once left songs count is less than 100, then run score following evaluation.We observed that about 60% of tests can be accomplished by the first method (head + following),and among the rest of the cases, about 80% of tests can be accomplished in the first 2 attempts (32 notes).Benefit from high-performance score following algorithm, most retrieving tests can be accomplished in 20 seconds (from when first note played).</p><p>There are also some pending issues, such as the splitting problem.When our program continuously listens to multiple songs from a user, how to precisely determine where is the songs’ boundary?Regarding people playing’s improvisity, score following won’t give a reasonable answer always.When to break the score following state and return to a new retrieving, that’s an open question.I think we need a sophisticated policy to integrate score following results and notes’ interval information.</p><hr><p>[^1]: Paper: <a href="http://www.scielo.br/scielo.php?script=sci_arttext&pid=S0104-65001999000300002">MIDIZ: content based indexing and retrieving MIDI files</a>[^2]: MIDIZ use 2<sup>k</sup>-1 dimensional vectors, usually set k&#x3D;3.[^3]: The notes count up limit is to avoid some song with too many repeat pitches at the head, which may delay query.[^4]: Probably because of user played error notes in the head.</p><script src="/vue/chunk-vendors.js"></script><script src="/vue/midi-pitches-counter.js"></script><script src="/vue/midi-pitches-mask.js"></script><script src="/vue/chart.js"></script><script src="/vue/midi-head-mask.js"></script><script src="/vue/soundfont-loader.js"></script>]]></content>
    
    
    <summary type="html">&lt;figure&gt;
    &lt;picture&gt;
        &lt;source srcset=&quot;/images/gfind-crystal.webp&quot; type=&quot;image/webp&quot; /&gt;
        &lt;source srcset=&quot;/images/gfind-crystal.png&quot; type=&quot;image/png&quot; /&gt;
        &lt;img src=&quot;/images/gfind-crystal.png&quot; class=&quot;figure&quot; width=&quot;400&quot; alt=&quot;smart piano&quot;&gt;
    &lt;/picture&gt;
    &lt;figcaption&gt;A smart piano.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;Motivation&quot;&gt;&lt;a href=&quot;#Motivation&quot; class=&quot;headerlink&quot; title=&quot;Motivation&quot;&gt;&lt;/a&gt;Motivation&lt;/h2&gt;&lt;p&gt;Imagine you have a smart piano at home, which is connected with a huge music staff library.
Once, you want to play some music opus on a whim, and it’s so bothering to retrieve music staff in either category menus or a long favorite list,
therefore, you just play by memory directly.
But the piano is so smart. Just a few seconds later, it understands what you are playing and displays the staff automatically.&lt;/p&gt;
&lt;p&gt;Let’s look at another case: you see a nice piano when hanging out downtown and you are just in a mood to play a piece of music and show off your talent to passers.
When you sit and play, surprisingly, the piano displays the music information about what you are playing.
When you finish, it says, well done! Your performance beat 95% players on this opus.&lt;/p&gt;
&lt;p&gt;Imaginary scenes above are coming true. Now let’s talk about some ideas for implementing such a technique.&lt;/p&gt;</summary>
    
    
    
    
    <category term="music" scheme="https://findlab.github.io/tags/music/"/>
    
    <category term="midi" scheme="https://findlab.github.io/tags/midi/"/>
    
  </entry>
  
  <entry>
    <title>FindLab blog founded</title>
    <link href="https://findlab.github.io/2020/02/18/founded/"/>
    <id>https://findlab.github.io/2020/02/18/founded/</id>
    <published>2020-02-18T20:03:42.000Z</published>
    <updated>2026-05-02T02:54:17.445Z</updated>
    
    <content type="html"><![CDATA[<p>Here, <a href="/about/">we</a> founded <a href="https://findlab.github.io/">this blog</a>,and we will successively publish some novel ideas and discussions on topic of deep learning, music related algorithm and piano.Thanks for your reading, enjoy&#x1F60E;.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;Here, &lt;a href=&quot;/about/&quot;&gt;we&lt;/a&gt; founded &lt;a href=&quot;https://findlab.github.io/&quot;&gt;this blog&lt;/a&gt;,
and we will successively publish some novel ideas and discussions on topic of deep learning, music</summary>
        
      
    
    
    
    
  </entry>
  
</feed>
