Node.js - Parsovanie MIDI súboru

Zápisník experimentátora

Hierarchy: Node.js

V tomto článku si ukážeme, ako sa dá parsovať MIDI súbor pomocou javascriptu. Ako MIDI súbor použijeme stupnicu, ktorú si vygenerujeme v programe MuseScore. Na parsovanom obsahu si ukážeme, čo sa v samotnom súbore skrýva.

Vygenerovaný súbor má 2 takty, obsahuje niekoľko nôt zo stupnice C dur, ktoré postupne menia hlasitosť a paralelne s nimi hrá akord C (noty C, E, G), ktorý je o oktávu nižšie. Na vyskúšanie možností MIDI je to dostatočné.

Program

Program využíva knižnicu midi-parser-js. Vidíte, že MIDI súbory obsahujú hlavičku, niekoľko stôp a v každej stope sú rôzne eventy, ktoré sú od seba oddelené časom, kedy sa majú prehrať. Ten čas je trošku podivná veličina, ktorá môže byť závislá od rôznych faktorov. Pre zjednodušenie nám stačí vedieť, že eventy, ktoré sú vzdialené o delta 0 sa majú zahrať súčasne. Tie čo majú deltu nenulovú, musia počkať príslušný čas a prehrať sa až potom.

Na prehrávanie jednotlivých nôt je podstatný event typu 9 (note on) a event typu 8 (note off). Ten je ale často nahradený eventom typu 9 s hlasitosťou nastavenou na 0, čo znamená tiež to isté.

let midiParser  = require('midi-parser-js');
let fs = require('fs');

let data = fs.readFileSync('./stupnica.mid');
let midiArray = midiParser.parse(data);

console.log(`Tracks: ${midiArray.tracks}, TimeDivision: ${midiArray.timeDivision}`);
for(let i in midiArray.track) {
  console.log(`Track ${i}`);
  for(let j in midiArray.track[i].event) {
    let event = midiArray.track[i].event[j];
    switch(event.type) {
      case 8: // note off
      case 9: // note on
      case 11: // controller
      case 12: // program change
        console.log(` ${j} t:${event.type} ch:${event.channel} delta:${event.deltaTime} - ${event.data}`);
        break;
      case 255: // meta event
        console.log(` ${j} t:${event.type} m:${event.metaType} delta:${event.deltaTime} - ${event.data}`);
        break;
      default:
        console.log(` ${j} t:${event.type} delta:${event.deltaTime} - ${event.data}`);
        break;
      }
  }
}

Výstup z programu

Program treba najprv nainštalovať príkazom npm install a potom spustiť príkazom node index. Vo výpise vidíte, že noty sú umiestnené do dvoch stôp. Na začiatku každej stopy sú systémové eventy, ktoré nás nemusia zaujímať a na konci každej stopy je event, ktorý znamená koniec stopy. Tento MIDI súbor som vygeneroval pre BPB 120. Hodnota je v eventoch trochu skrytá, ale pre účely nášho článku nám stačí vedieť, že jedna štvrťová nota v tomto prípade trvá 480 tikov akéhosi pomyselného timera. Keď sa pozriete poriadne na event 9, vidíte, že každá nota má dva eventy. A keď budete počítať, tak delty pre noty sú 455 + 25 = 480. To znamená len to, že nota sa nehrá až úplne do konca a po každej note je kratučká pauza. Keby som v notovom zápise vyznačil artikuláciu legato (v reči hudobníkov to znamená hru spojito, keď každá nota nadväzuje na tú predchádzajúcu bez počuteľnej prestávky), bolo by trvanie každej noty o čosi dlhšie.

d:\arduino\arduinoslovakia\midi\file\nodejs\midi-parser>npm install
npm WARN npm npm does not support Node.js v12.16.1
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm Supported releases of Node.js are the latest release of 6, 8, 9, 10, 11.
npm WARN npm You can find the latest version at https://nodejs.org/
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN midi-parser@1.0.0 No description
npm WARN midi-parser@1.0.0 No repository field.

added 1 package from 1 contributor in 2.223s
[+] no known vulnerabilities found [1 packages audited]

d:\arduino\arduinoslovakia\midi\file\nodejs\midi-parser>node index
Tracks: 2, TimeDivision: 480
Track 0
 0 t:255 m:88 delta:0 - 4,2,24,8
 1 t:255 m:89 delta:0 - 0
 2 t:255 m:81 delta:0 - 500000
 3 t:11 ch:1 delta:0 - 121,0
 4 t:12 ch:1 delta:0 - 0
 5 t:11 ch:1 delta:0 - 7,100
 6 t:11 ch:1 delta:0 - 10,64
 7 t:11 ch:1 delta:0 - 91,0
 8 t:11 ch:1 delta:0 - 93,0
 9 t:255 m:33 delta:0 - 0
 10 t:9 ch:1 delta:0 - 60,49
 11 t:9 ch:1 delta:455 - 60,0
 12 t:9 ch:1 delta:25 - 62,53
 13 t:9 ch:1 delta:455 - 62,0
 14 t:9 ch:1 delta:25 - 64,57
 15 t:9 ch:1 delta:455 - 64,0
 16 t:9 ch:1 delta:25 - 65,62
 17 t:9 ch:1 delta:455 - 65,0
 18 t:9 ch:1 delta:25 - 67,66
 19 t:9 ch:1 delta:455 - 67,0
 20 t:9 ch:1 delta:25 - 69,71
 21 t:9 ch:1 delta:455 - 69,0
 22 t:9 ch:1 delta:25 - 71,75
 23 t:9 ch:1 delta:455 - 71,0
 24 t:9 ch:1 delta:25 - 72,80
 25 t:9 ch:1 delta:455 - 72,0
 26 t:255 m:47 delta:1 - undefined
Track 1
 0 t:255 m:89 delta:0 - 0
 1 t:255 m:33 delta:0 - 0
 2 t:9 ch:1 delta:0 - 48,49
 3 t:9 ch:1 delta:0 - 52,49
 4 t:9 ch:1 delta:0 - 55,49
 5 t:9 ch:1 delta:3647 - 48,0
 6 t:9 ch:1 delta:0 - 52,0
 7 t:9 ch:1 delta:0 - 55,0
 8 t:255 m:47 delta:1 - undefined

Zdrojový kód

Zdrojový kód sa nachádza na serveri GitHub.


20.07.2020


Menu