fbpx
Skip to main content

MIDI Forum

Looking for a javas...
 
Notifications
Clear all

Looking for a javascript midiparser

14 Posts
3 Users
0 Reactions
9,938 Views
Jonas
Posts: 207
Reputable Member
Topic starter
 

I am writing a midisequenser in javascript for my own use and joy, i have written midimessage parser eons ago, and i remember how tedious it was. So i though i look for parser on net, and i rather soon realised that i just do not get that object oriented code.

Well until i found.

https://tonejs.github.io/Midi/

But as i saw the tone.js example did actually parse out the content of the file to a text area above, i thought oh i could use that textstring and reparse it to fit my sequenser. Because i understood it, but looking closer upon the textoutput i realised i do not see/find the channel information for the notes and instruments?
So does the above hold channel information for instruments and notes???

Normally?? the instrument channel is the first byte in a message ranging 192-207. At least that is how i change the instrument on a midichannel on my hardware using javascript.
And the notemessages first byte also the channel, i use/save both ON 144-159 and OFF 128-143 " your program use duration here instead of "OFF" works fine with me".
Because then i only need to convert delta time for on notes to the absolute time my sequenser use.

But i can't see these messages for channel in the textoutput where do they hide, could you give me direction howto read out tone.js "objects?"
I am simple man i will just list the messages in an array, but without midichannel information for instruments and notes, i am lost.

Here is my halfbaked javascript attempt so far, i do not use miditime "parts per quarter?", just absolute time.
But it could change i have a metronome that i removed in favour of prerendered absolute time.

https://midisequenser.000webhostapp.com/

Best regards Jonas Thörnvall

 
Posted : 13/11/2019 6:39 am
Geoff
Posts: 1047
Noble Member
 

Hello,

I don't want to get too bogged down regarding js, however...

The first byte is NOT the channel. The first byte will probably comprise two 4 bit numbers, the first part is the command, i.e. 9 for Note On, the second 4 bits will be the channel. dealing with this byte as 192 to 207 will be confusing. Surely? as Decimal even worse. So &H90 is Note On on channel 0, I suspect that the data you're seeing has this data already translated, so you don't see the (for example) 192 any more, but a reference to Note On, and somewhere a channel? In any case, 192 is not &H9x, but &HC0 - Program Change. So the decimal numbers you show are prob all correct, just not how they'd normally show.

In any case, the translation would prob not show the command number, just a channel. Somewhere?

Geoff

 
Posted : 13/11/2019 12:09 pm
Jonas
Posts: 207
Reputable Member
Topic starter
 

https://tonejs.github.io/Midi/

Well just click the github link, and you can see what it parse out.
I can't see any channel information either for notes or instruments "just on / off".

But you are correct he has already translated note off into duration.

Jonas

 
Posted : 13/11/2019 6:10 pm
Jonas
Posts: 207
Reputable Member
Topic starter
 

Geoff 192-207 is the first byte, and denotes which channel "a change of instrument" take place on.
.
Javascript made it very easy to handle midi, someone was smart, all messages or message chain either consist off two or three byte values.
Instrument change is a two byte value. Where the first byte if between 192-207 denotes which channel the change occure on.

So the **first byte** do denote channel.

CC 176-191
instrument 192-207
Note On 144-159
Note Off 128-143

The use of byte values made it very easy program midi in javascript.

Second byte is CC type, Note value or program.

Third byte "if there is one" is the range, so they gained alot by using bytes. And doing it using stringified decimals, compared to hex, of course one use decimals.
Because then you can actually read the code.

Best regards Jonas Thörnvall

 
Posted : 13/11/2019 6:31 pm
Jonas
Posts: 207
Reputable Member
Topic starter
 

Of course you may see a deeper meaning within the bit to byte structure "first four bits message type last four midichannel" then me, but it is however true that for the ranges within first byte above they do denote the midichannel weither it was intended or not.

And you have to admit Geoff it is much easier to work with bytes then bits, and i can't see why anyone would prefer bits,hex bytes to decimal byte values.

CC 176-191
instrument change 192-207
Note On 144-159
Note Off 128-143
Pitchbend 224-239
Polyphonic key pressure 160-175
Channel pressure 208-223

I think i got all the all the supported midichannel messages there, and their range within first byte?

 
Posted : 13/11/2019 6:58 pm
Jonas
Posts: 207
Reputable Member
Topic starter
 

Looking at it again i can see the midi channel probably hides behind the label midi, but i do not get the range, how does he parse out the values?

https://tonejs.github.io/Midi/

"I guess it is a bit saving mechanism", so how does he parse out those values ranging 40-80 "estimation" out of the byte?

 
Posted : 13/11/2019 8:11 pm
Sema
 Sema
Posts: 182
Reputable Member
 

You may ant to ave a look at https://github.com/jazz-soft/JZZ and https://github.com/jazz-soft/JZZ-midi-SMF

 
Posted : 13/11/2019 9:42 pm
Jonas
Posts: 207
Reputable Member
Topic starter
 

I now realise of course it is HEX values for midchannel he use "i am just stuck with bytes in my head". But i don't get it the values is all over the place?
36 - 80
Look for the label midi on the notes i think that must be the channels, can some smart fellow tell me howto decode it?
I just do not get it his range much bigger then number of midichannels, so how to decode it "how did he encode it"?
Help please, it is detective work to figure out how he encoded it, because even if hex it really does not make sense?

Could he read out the bits wrong way back to front, but i still can't get it working maybe also multiply?

https://tonejs.github.io/Midi/

 
Posted : 14/11/2019 12:06 am
Geoff
Posts: 1047
Noble Member
 

Hello,

So, you don't want all the 'fun' of this for yourself?

I've been to the link you provide, and supplied a midi file. The process has provided a 'decode' of the data. This is a VERY verbose form of decode, and looks rather like a variant of the MusicXML format, although it's quite different in detail.

The file I supplied is fairly small, with 2 channels used ONLY.

I've saved the output to a file on my PC, using COPY/PASTE via NotePad. So I can 'play about' with the data.

I note there's a 'header section, then a section labeled 'tracks' which includes a further section labelled 'channel': 0.

Much further down there's another section labelled 'Channel': 1

So, the parsing process has divided the file by channel, giving you all the data channel by channel. This could be useful for some purposes, but surely not for others?? I'd need to experiment to determine if there is any connection between the layout of the original midi file. The file I used had 1 track, including use of two channels, so the track had data for two channels mixed, and ordered by time.

The important point regarding your question is that the data detail dies NOT show the channel except in that ALL the data within a part of the data is assigned to a specific channel as shown at the start of that section. So there is no point in showing the channel number again.

Aargh - I'm mixing myself up. I've just double checked, and my midi file is actually 3 tracks, header and two data tracks. The data tracks are respectively Ch 0 and Ch 1, so the decode has kept closely to this. My mind's eye however was seeing another decode, using a different piece of software, which DID re-arrange the data into time order, so that the data included mixed channels (each line labelled by channel as required). Generally, I would find the latter format FAR more useful, especially as all values are displayed as HEX numbers, as per the data in the midi file.

Is this helpful?

Geoff

 
Posted : 14/11/2019 11:09 am
Jonas
Posts: 207
Reputable Member
Topic starter
 

Yeah i think so Geoff it strange i just scrolled it thru in the HTML textarea but i had a rahter big midi file Queen Bohemina Rhapsody with dozens of instrument changes but i did not manage to catch the midi channel messages you speak of. Have to go back and do it again and paste into editor like you and search for channel information. Well this is what comes with being sloppy i guess.

Thanks Geoff

 
Posted : 14/11/2019 12:15 pm
Geoff
Posts: 1047
Noble Member
 

Jonas,

Hm, maybe not a good idea to be using a large file for your testing - the conversion is very verbose, and leave a massive pile of data to pore through.

Nothing to do with being 'sloppy', more like looking for a needle in a haystack?

On the basis of what you'd written before, I guess I'd instinctively wondered if the problem was that the channel marker was seperated - as it seems to be. I've spent a lot of time over a lot of years looking inside midi files, and messing with software (incl my own progs) to 'do things' with such files, incl play them. Even though I was scrolling through the initial file very quickly, I spotted something that made me stop and go back to where it said 'channel': 0 and I thought - Aha!

I don't want to get involved in programming with js, I'm dealing with enough other languages already. So best of luck with your project.

Geoff

 
Posted : 14/11/2019 5:39 pm
Geoff
Posts: 1047
Noble Member
 

Jonas,

Just a hint in case it helps.

You will ALWAYS need to split the command byte, into the command and the channel. It will NEVER be any use keeping this as a single value.

There are different ways to do this, I've seem variants where AND/OR is used to mask off some of the bits.

The way I prefer is somewhat clearer. Ensure that the byte value is an INT (integer) and divide by 16. This will give you the integer Command, i.e. 9 for Note On, regardless of channel. Then put this into another INT variable, and multiply by 16, and minus the result from the original byte value. This will give you the channel number, on its own. NB all the variables for this MUST be integers, you don't want any decimal places.

Regarding something you wrote earlier, if you check the official spec for midi files, there should be a piece of sample code for the read/translation of the timing bytes into something more useful, and it should not be a problem to convert the code into js. I have a working version in 'C' if that would be more help. The published version is in 'C' in the doc I have, but I think I changed it slightly.

Geoff

 
Posted : 16/11/2019 6:31 am
Jonas
Posts: 207
Reputable Member
Topic starter
 

Hello Geoff!

Just read your reply, working with javascript i can't see the necessity, but then again my sequenser is not midicompatible although it will import midifiles to play.
I can show you what is sent out to a port using javascript, and this works fine for every type of event i can find even bankchanges. You can see below it is silly simple dealing with it.
Only thing to realise that some messages 2 bytes instead of three, "program change, note off".
I just look at the range to determine the type of event, so do not need to split the byte.

Thanks again for the help Geoof, i think to Cristmas i will have a somewhat functional midisequenser load save edit and so on, i probably should have a timeview and a FPS view instead of just a barview. But the barview did seem most easy to start with.

Looking at the code below i do realise now i split, but i still think a decimal range is easier handled then pairing two 4-bit hexvalues.

Thanks again for the help Geoff!

function sendProgram() {
//Set program on the track
programNbr = document.getElementById("prog_sel").value;
//Set channel
midiCh = 192 + trackMidiCh-1;
//Build message for midi synth
settingChange = [midiCh, programNbr];
outportarr[outportindex].send(settingChange);
}

function setVol(){
CCchan=176+trackMidiCh-1;
CCtype=7;
CCvol=document.getElementById("volID").value;
settingChange=[CCchan,CCtype,CCvol];
outportarr[outportindex].send(settingChange);
}

function setPan(){
CCchan=176+trackMidiCh-1;
CCtype=10;
CCpan=document.getElementById("panID").value;
settingChange=[CCchan,CCtype,CCpan];
outportarr[outportindex].send(settingChange);
}

function setRev(){
CCchan=176+trackMidiCh-1;
CCtype=91;
CCrev=document.getElementById("revID").value;
settingChange=[CCchan,CCtype,CCrev];
outportarr[outportindex].send(settingChange);
}

function setChor(){
CCchan=176+trackMidiCh-1;
CCtype=93;
CCchor=document.getElementById("chorID").value;
settingChange=[CCchan,CCtype,CCchor];
outportarr[outportindex].send(settingChange);
}

function setMod(){
CCchan=176+trackMidiCh-1;
CCtype=1;
CCmod=document.getElementById("modID").value;
settingChange=[CCchan,CCtype,CCmod];
outportarr[outportindex].send(settingChange);
}

function setHold(){
CCchan=176+trackMidiCh-1;
CCtype=64;
CChold=document.getElementById("holdID").value;
settingChange=[CCchan,CCtype,CChold];
outportarr[outportindex].send(settingChange);
}

 
Posted : 19/11/2019 5:01 am
Jonas
Posts: 207
Reputable Member
Topic starter
 

https://midisequenser.000webhostapp.com/

Although i am not sure i hope you wow for my halfbaked attempt to a sequenser, full of bugs.
But to Christmas i hope most of them gone and editing, load save and midi file import fully functional.

 
Posted : 22/11/2019 5:24 am
Share: