Node.js - Parsování MIDI souborů

Zápisník experimentátora

Hierarchy: Node.js

V tomto článku si ukážeme, jak se dá parsovat MIDI soubor pomocí javascriptu. Jako MIDI soubor použijeme stupnici, kterou si vygenerujeme v programu MuseScore. Na parsování obsahu si ukážeme, co se v samotném souboru skrývá.

Vygenerovaný soubor má 2 takty, obsahuje několik not ze stupnice C dur, které postupně mění hlasitost a paralelně s nimi hraje akord C (noty C, E, G), který je o oktávu níže. Na vyzkoušení možností MIDI je to dostatečné.

Program

Program využívá knihovnu midi-parser-js. Vidíte, že MIDI soubory obsahují hlavičku, několik stop a v každé stopě jsou různé eventy, které jsou od sebe odděleny časem, kdy se mají přehrát. Ten čas je trošku podivná veličina, která může být závislá na různých faktorech. Pro zjednodušení nám stačí vědět, že eventy, které jsou vzdáleny o delta 0 se mají zahrát současně. Ty co mají deltu nenulovou musí počkat příslušný čas a přehrát se až potom.

Na přehrávání jednotlivých not je podstatný event typu 9 (note on) a event typu 8 (note off). Ten je ale často nahrazen eventem typu 9 s hlasitostí nastavenou na 0, což znamená také totéž.

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 je třeba nejprve nainstalovat příkazem NPM install a potom spustit příkazem node index. Ve výpisu vidíte, že noty jsou umístěny do dvou stop. Na začátku každé stopy jsou systémové eventy, které nás nemusí zajímat a na konci každé stopy je event, který znamená konec stopy. Tento MIDI soubor jsem vygeneroval pro BPB 120. Hodnota je v eventech trochu skrytá, ale pro účely našeho článku nám stačí vědět, že jedna čtvrťová nota v tomto případě trvá 480 tiků jakéhosi pomyslného timeru. Když se podíváte pořádně na event 9, vidíte, že každá nota má dva eventy. A když budete počítat, tak delty pro noty jsou 455 + 25 = 480. To znamená jen to, že nota se nehraje až úplně do konce a po každé note je kratičká pauza. Kdybych v notovém zápisu vyznačil artikulaci legato (v řeči hudebníků to znamená hru spojitě, když každá nota navazuje na tu předchozí bez slyšitelné přestávky), bylo by trvání každé noty o něco delší.

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 se nachází na serveru GitHub.


20.07.2020


Menu