Playing base64 strings in Node to external devices

Low level MIDI support for Node.js

Playing base64 strings in Node to external devices

Postby davidlav » Tue Oct 11, 2016 4:02 pm

Hi, I'm working on a project to procedurally generate music live in Node. The goal is to continually assemble MIDI data as base64 strings (with something like MidiWriterJS, https://github.com/grimmdude/MidiWriterJS) that I can then feed to something like jazz-midi's MidiOutRaw() function to be played by a VST or external MIDI device.

This example (http://jazz-soft.net/demo/PlayMidiFile.html) proved to me that it's possible to play base64 strings to external MIDI devices, but I can't seem to replicate the example in a Node project.

I'm confused by the use of "JZZ.Midi.js" and "JZZ.MidiFile.js" as they don't seem to appear anywhere in any of the documentation. Are they necessary for converting the base64 string into a datatype that MidiOutRaw() can take as an argument?

I've tried replicating the "Play MIDI File" example in node and have the following code:

Code: Select all
const mozart='\
 TVRoZAAAAAYAAQALAPBNVHJrAA
...
lJAgXCeRmR4jkZAAP8vAA==';

const Jazz = require('jazz-midi');
const JZZ_ = require('./JZZ.MidiFile');

const midi = new Jazz.MIDI();
midi.MidiOutOpen(0);

const midifile = new JZZ_.MidiFile(JZZ_.MidiFile.fromBase64(mozart));


The last line gives me this error though:

Code: Select all
const midifile = new JZZ_.MidiFile(JZZ_.MidiFile.fromBase64(mozart));
                                                ^
TypeError: Cannot read property 'fromBase64' of undefined
    at Object.<anonymous> (D:\Webstorm Projects\JazzMIDI\index.js:287:49)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.runMain (module.js:575:10)
    at run (bootstrap_node.js:352:7)
    at startup (bootstrap_node.js:144:9)
    at bootstrap_node.js:467:3


Do I need to use the "JZZ.Midi.js" and "JZZ.MidiFile.js" in order to play back base64 data to an external MIDI device?

Thanks for the help!
davidlav
 
Posts: 4
Joined: Tue Oct 11, 2016 2:30 pm

Re: Playing base64 strings in Node to external devices

Postby sema » Tue Oct 11, 2016 6:14 pm

JZZ.Midi.js and JZZ.MidiFile.js are a bit outdated. Try to use JZZ.js instead.
If you are doing your own time management, call port.send(...) to play messages.
sema
Site Admin
 
Posts: 315
Joined: Mon Oct 17, 2011 7:28 pm

Re: Playing base64 strings in Node to external devices

Postby davidlav » Tue Oct 11, 2016 6:49 pm

So if JZZ.Midi.js and JZZ.MidiFile.js are deprecated, how do I use JZZ.js to convert a base64 string into something that can be played? I've been looking at the documentation page for JZZ.js and I don't see anything equivalent to the fromBase64() method.

For example, how could you rewrite the Play MIDI File example (http://jazz-soft.net/demo/PlayMidiFile.html) to play the Mozart piece in base64 without needing to use the line:

Code: Select all
var midifile = new JZZ_.MidiFile(JZZ_.MidiFile.fromBase64(mozart));


Could you give a minimum working example of how to play the Mozart base64 string from that example with JZZ.js?
davidlav
 
Posts: 4
Joined: Tue Oct 11, 2016 2:30 pm

Re: Playing base64 strings in Node to external devices

Postby sema » Wed Oct 12, 2016 7:13 am

It will take me some time to write a working example.
Do you really need to pack your MIDI messages into the file and then unpack them?
Why don't send the messages directly to the player?
sema
Site Admin
 
Posts: 315
Joined: Mon Oct 17, 2011 7:28 pm

Re: Playing base64 strings in Node to external devices

Postby davidlav » Wed Oct 12, 2016 8:24 am

What I'd like to be able to do is dynamically generate 4 or 8 bar long "segments" of MIDI data using the MidiWriterJS package (https://github.com/grimmdude/MidiWriterJS) and be able to string those "blocks" of MIDI into a piece of continuous, procedurally generated music by queuing them up and letting the play back one after another in sequence.

However, MidiWriterJS is only able to output base64 strings and Uint8Arrays (https://github.com/grimmdude/MidiWriterJS#midiwriterwritertracks) and jazz-midi is the only JavaScript program I can find that seems to be able to play base64 strings to external MIDI devices.

Maybe there's another solution to my problem, but I don't know enough to know if there is.

The reason I'd rather not send messages directly to the player is because I want to be able to play back pieces of MIDI as "blocks" or "chunks" sequentially rather than on a note-by-note basis, if that makes sense. So for example, MidiWriterJS shows how you can render a short bit of music into a base64 string in this example (https://github.com/grimmdude/MidiWriterJS#hot-cross-buns). And what I would like to do is to repeatedly play that piece of music back over and over again, each time modifying pieces of it dynamically so it changes over time. If I have to send messages directly to the player, then I have to basically program a whole timing system to keep track of what beat and measure of the music I'm in, rather than just being able to edit or modify an already existing "chunk" of music, and immediately play the next chunk of music once the current one has finished.

Thanks for taking the time to read all this and help! I'm sure there's a way to do what I want, I just don't know enough about MIDI playback in JavaScript to know how to put all the programming pieces together to do it.
davidlav
 
Posts: 4
Joined: Tue Oct 11, 2016 2:30 pm

Re: Playing base64 strings in Node to external devices

Postby sema » Wed Oct 12, 2016 9:38 am

How are the data formatted in those Uint8Arrays?
sema
Site Admin
 
Posts: 315
Joined: Mon Oct 17, 2011 7:28 pm

Re: Playing base64 strings in Node to external devices

Postby davidlav » Wed Oct 12, 2016 8:07 pm

I'm happy to say I solved my problem! Luckily the writer of the excellent MidiWriterJS library also wrote a MidiPlayerJS library which "plays back" base64 strings and fires off JSON events as it "plays" each MIDI event. I just listened for the events and mapped Note-on's and Note-off's to JZZ's port.send() function. Here's a minimum working example in Node:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Code: Select all
const zelda = 'data:audio/midi;base64,TVRoZAAAAAYAAQACAIBNVHJrAAADoQDAAQCQRn+CAIBGfwCQRn9AgEZ/AJBBf0CAQX8AkEF/QIBBfwCQRn9AgEZ/AJBEfyCARH8AkEJ/IIBCfwCQRH+DAIBEf0CQRn+CAIBGfwCQRn9AgEZ/AJBBf0CAQX8AkEF/QIBBfwCQRn9AgEZ/AJBFfyCARX8AkEN/IIBDfwCQRX+BQIBFf4IAkEUBhACARQGEAJBGf4EAgEZ/AJBBf4FAgEF/AJBGf0CARn8AkEZ/IIBGfwCQSH8ggEh/AJBKfyCASn8AkEt/IIBLfwCQTX+CAIBNf0CQTX9AgE1/AJBNf0CATX8AkE5/IIBOfwCQUH8ggFB/AJBSf4IAgFJ/QJBSf0CAUn8AkFJ/QIBSfwCQUH8ggFB/AJBOfyCATn8AkFB/YIBQfwCQTn8ggE5/AJBNf4IAgE1/AJBNf4EAgE1/AJBLf2CAS38AkE1/IIBNfwCQTn+CAIBOfwCQTX9AgE1/AJBLf0CAS38AkEl/YIBJfwCQS38ggEt/AJBNf4IAgE1/AJBLf0CAS38AkEl/QIBJfwCQSH9ggEh/AJBKfyCASn8AkEx/ggCATH8AkE9/gQCAT38AkE1/QIBNfwCQQX8ggEF/AJBBfyCAQX8AkEF/QIBBfwCQQX8ggEF/AJBBfyCAQX8AkEF/QIBBfwCQQX8ggEF/AJBBfyCAQX8AkEF/QIBBfwCQQX9AgEF/AJBGf4EAgEZ/AJBBf4FAgEF/AJBGf0CARn8AkEZ/IIBGfwCQSH8ggEh/AJBKfyCASn8AkEt/IIBLfwCQTX+CAIBNf0CQTX9AgE1/AJBNf0CATX8AkE5/IIBOfwCQUH8ggFB/AJBSf4MAgFJ/AJBVf4EAgFV/AJBUf4EAgFR/AJBRf4IAgFF/AJBNf4EAgE1/AJBOf4MAgE5/AJBSf4EAgFJ/AJBRf4EAgFF/AJBNf4IAgE1/AJBNf4EAgE1/AJBOf4MAgE5/AJBSf4EAgFJ/AJBRf4EAgFF/AJBNf4IAgE1/AJBKf4EAgEp/AJBLf4MAgEt/AJBOf4EAgE5/AJBNf4EAgE1/AJBJf4IAgEl/AJBGf4EAgEZ/AJBIf2CASH8AkEp/IIBKfwCQTH+CAIBMfwCQT3+BAIBPfwCQTX9AgE1/AJBBfyCAQX8AkEF/IIBBfwCQQX9AgEF/AJBBfyCAQX8AkEF/IIBBfwCQQX9AgEF/AJBBfyCAQX8AkEF/IIBBfwCQQX9AgEF/AJBBf0CAQX8A/y8ATVRyawAACUMAwAEAkCpAgQCAKkAAkDVAgQCANUAAkDpAggCAOkAAkClAgQCAKUAAkDNAgQCAM0AAkDhAggCAOEAAkCdAgQCAJ0AAkDFAgQCAMUAAkDpAggCAOkAAkCpAgQCAKkAAkDVAgQCANUAAkDpAggCAOkAAkC5AQIAuQACQLkAggC5AAJApQCCAKUAAkC5AQIAuQACQLkAggC5AAJApQCCAKUAAkC5AQIAuQACQLkAggC5AAJApQCCAKUAAkC5AIIAuQACQKUAggClAAJAuQCCALkAAkClAIIApQACQLkBAgC5AAJAuQCCALkAAkClAIIApQACQLkBAgC5AAJAuQCCALkAAkClAIIApQACQLkBAgC5AAJAuQCCALkAAkClAIIApQACQLkAggC5AAJApQCCAKUAAkC5AIIAuQACQKUAggClAAJAuQECALkAAkC5AIIAuQACQKUAggClAAJAuQECALkAAkC5AIIAuQACQKUAggClAAJAuQECALkAAkC5AIIAuQACQKUAggClAAJAuQCCALkAAkClAIIApQACQLkAggC5AAJApQCCAKUAAkCxAQIAsQACQLEAggCxAAJAnQCCAJ0AAkCxAQIAsQACQLEAggCxAAJAnQCCAJ0AAkCxAQIAsQACQLEAggCxAAJAnQCCAJ0AAkCxAIIAsQACQJ0AggCdAAJAsQCCALEAAkCdAIIAnQACQKkBAgCpAAJAqQCCAKkAAkCVAIIAlQACQKkBAgCpAAJAqQCCAKkAAkCVAIIAlQACQKkBAgCpAAJAqQCCAKkAAkCVAIIAlQACQKkAggCpAAJAlQCCAJUAAkCpAIIAqQACQJUAggCVAAJAxQECAMUAAkDFAIIAxQACQLEAggCxAAJAxQECAMUAAkDFAIIAxQACQLEAggCxAAJAxQECAMUAAkDFAIIAxQACQLEAggCxAAJAxQCCAMUAAkCxAIIAsQACQMUAggDFAAJAsQCCALEAAkC9AQIAvQACQL0AggC9AAJAqQCCAKkAAkC9AQIAvQACQL0AggC9AAJAqQCCAKkAAkC9AQIAvQACQL0AggC9AAJAqQCCAKkAAkC9AIIAvQACQKkAggCpAAJAvQCCAL0AAkCpAIIAqQACQLkBAgC5AAJAuQCCALkAAkClAIIApQACQLkBAgC5AAJAuQCCALkAAkClAIIApQACQLkBAgC5AAJAuQCCALkAAkClAIIApQACQLkAggC5AAJApQCCAKUAAkC5AIIAuQACQKUAggClAAJAwQECAMEAAkDBAIIAwQACQK0AggCtAAJAwQECAMEAAkDBAIIAwQACQK0AggCtAAJAwQECAMEAAkDBAIIAwQACQK0AggCtAAJAwQCCAMEAAkCtAIIArQACQMEAggDBAAJArQCCAK0AAkClAQIApQACQOUAggDlAAJA5QCCAOUAAkDhAQIA4QACQOEAggDhAAJA4QCCAOEAAkDdAQIA3QACQN0AggDdAAJA3QCCAN0AAkDZAQIA2QACQKUBAgClAAJAuQECALkAAkC5AIIAuQACQKUAggClAAJAuQECALkAAkC5AIIAuQACQKUAggClAAJAuQECALkAAkC5AIIAuQACQKUAggClAAJAuQCCALkAAkClAIIApQACQLkAggC5AAJApQCCAKUAAkCxAQIAsQACQLEAggCxAAJAnQCCAJ0AAkCxAQIAsQACQLEAggCxAAJAnQCCAJ0AAkCxAQIAsQACQLEAggCxAAJAnQCCAJ0AAkCxAIIAsQACQJ0AggCdAAJAsQCCALEAAkCdAIIAnQACQKkBAgCpAAJAqQCCAKkAAkCpAIIAqQACQKkBAgCpAAJAqQCCAKkAAkCpAIIAqQACQKkBAgCpAAJAqQCCAKkAAkCpAIIAqQACQKkAggCpAAJAqQCCAKkAAkCpAIIAqQACQKkAggCpAAJApQECAKUAAkClAIIApQACQKUAggClAAJApQECAKUAAkClAIIApQACQKUAggClAAJApQECAKUAAkClAIIApQACQKUAggClAAJApQCCAKUAAkClAIIApQACQKUAggClAAJApQCCAKUAAkChAQIAoQACQKEAggChAAJAoQCCAKEAAkChAQIAoQACQKEAggChAAJAoQCCAKEAAkChAQIAoQACQKEAggChAAJAoQCCAKEAAkChAIIAoQACQKEAggChAAJAoQCCAKEAAkChAIIAoQACQKUBAgClAAJApQCCAKUAAkClAIIApQACQKUBAgClAAJApQCCAKUAAkClAIIApQACQKUBAgClAAJApQCCAKUAAkClAIIApQACQKUAggClAAJApQCCAKUAAkClAIIApQACQKUAggClAAJAoQECAKEAAkChAIIAoQACQKEAggChAAJAoQECAKEAAkChAIIAoQACQKEAggChAAJAoQECAKEAAkChAIIAoQACQKEAggChAAJAoQCCAKEAAkChAIIAoQACQKEAggChAAJAoQCCAKEAAkClAQIApQACQKUAggClAAJApQCCAKUAAkClAQIApQACQKUAggClAAJApQCCAKUAAkClAQIApQACQKUAggClAAJApQCCAKUAAkClAIIApQACQKUAggClAAJApQCCAKUAAkClAIIApQACQL0BAgC9AAJAvQCCAL0AAkC9AIIAvQACQL0BAgC9AAJAvQCCAL0AAkC9AIIAvQACQL0BAgC9AAJAvQCCAL0AAkC9AIIAvQACQL0AggC9AAJAvQCCAL0AAkC9AIIAvQACQL0AggC9AAJAuQECALkAAkC5AIIAuQACQLkAggC5AAJAuQECALkAAkC5AIIAuQACQLkAggC5AAJAuQECALkAAkC5AIIAuQACQLkAggC5AAJAuQCCALkAAkC5AIIAuQACQLkAggC5AAJAuQCCALkAAkDBAQIAwQACQMEAggDBAAJAwQCCAMEAAkDBAQIAwQACQMEAggDBAAJAwQCCAMEAAkDBAQIAwQACQMEAggDBAAJAwQCCAMEAAkDBAIIAwQACQMEAggDBAAJAwQCCAMEAAkDBAIIAwQACQKUBAgClAAJA5QCCAOUAAkDlAIIA5QACQOEBAgDhAAJA4QCCAOEAAkDhAIIA4QACQN0BAgDdAAJA3QCCAN0AAkDdAIIA3QACQNkBAgDZAAJApQECAKUAA/y8A';

const MidiPlayer = require('midi-player-js');
const JZZ = require('jzz');

console.log(JZZ().info().outputs);
port = JZZ().openMidiOut('Microsoft GS Wavetable Synth'); // or 'loopMIDI' (in my case) to send MIDI messages out to a Virtual Instrument (or VST)

const Player = new MidiPlayer.Player(function(event) {
    if(event.name === 'Note on') port.send([0x90, `${event.noteNumber}`, `${event.velocity}`]);
    else if(event.name === 'Note off') port.send([0x80, `${event.noteNumber}`, `${event.velocity}`]);
    // more lines to catch Program Changes or whatever other events you want to forward
});

Player.loadDataUri(zelda);
Player.play();
davidlav
 
Posts: 4
Joined: Tue Oct 11, 2016 2:30 pm

Re: Playing base64 strings in Node to external devices

Postby sema » Thu Oct 13, 2016 7:31 am

Excellent!
sema
Site Admin
 
Posts: 315
Joined: Mon Oct 17, 2011 7:28 pm


Return to jazz-midi

Who is online

Users browsing this forum: No registered users and 1 guest

cron