originally i've posted this here but who cares?
I've been working on this little idea of mine, a game where you play piano for at least half a year now.
It all started in may 2021 when i've figured WEB Midi - exists. And that could allow me to listen to midi keyboard inputs, so if i could render a rock band 3 chart (which is a midi file + ogg stems) for PRO KEYS MODE - that would be freaking great.
and many months of dread since, a lot of things are done, but nothing is really DONE done.
To put my mind elsewhere, but not too far away I start this "PIANO ROCKER DEV DIARY" series, where i blabber about technology, development, music games and yknow.. whatever comes to my mind.
Case study of the day:
Sheet music - exists, like it or not, playing keyboard is very tightly coupled with reading sheet music. All the exceptions, jazz legends who all "learnt it by ear", just make the overall rule stronger. I must render sheet music in some shape or form :(
Trust me, i did try to dodge this bullet, but I don't think i can, not anymore.
There are other "alternative" notations worth mentioning. Most curious ones are ABC Notation, the top-down charts a-la keyboardmania that were made popular by Synthesia and the new-emerging craze of VIRTUAL PIANO (playing piano on ascii keyboard, it is a thing, people actually do it. Even crazier, they do it in ROBLOX
I have seen yousician, simply piano, pianoo and such, all rendering sheet music, and after a bit of digging in local cache of yousician windows app i can assure you - they all parse music XML.
Biggest public source of sheet music i'm aware of, provides scores downloadable as PDF (nope), MIDI (seems really good, HEY, i already have it implemented, but trust me, it's not, i might cover this as separate post someday), their proprietary format AAAND Music XML.
It's widely adopted, it's open as much as TEXT FILES can be, it's free - i just have to learn how to interpret it and draw notes. Just like all these guys already did, perhaps a bit more lively (hopefully).
I'm still stuck with this shit, real stuck, but here's what i have learnt so far:
jszip
to the resque, this wasn't too hard fast-xml-parser
for now Bravura
it works, using reference from smufl website it's possible to map anything you can imagine to a unicode symbol. Lets say you need a g-clef, go to this page, g clef is U+E050 (and U+1D11E), great, create your PIXI.Text('\uE050') - here's your g-clef (if you managed to preload the font)so far i havent even touched actual music XML contents yet, right? Oh shit! Here we go again!
so your typical music xml measure.note
would have pitch
, consisting of step
(of chromatic scale, C, C#, D, whatever it is) and octave
(int).
Then there's type
and duration
. Type is within: [whole
, half
, quarter
, .... 32nd
, 64th
..... 1024th
and so on ]. duration
is an int number.
Being an idiot i am, i didn't read the spec, i just debugged my twinkle-twinkle-little-star chart and decided empirically that 1 is quarter note, 2 is half, 4 is whole. Twinkle-twinkle never went smaller than quarters, worked great. I even wrote a string to int switch-case, basing time strictly on TYPE instead.. DUMB.
Hard truth incomming
This number is the smallest integer that can be divided without .decimals for the smallest note division present in sheet. So if all your notes don't go smaller than quarter notes = DIVISIONS=1 is good. Quarter is 1, half is 2, whole is 4. If you have 8th notes - DIVISIONS would be 2, if you want to have 16th notes - 4, 16th and TRIPLETS - something that can be divided by 2 AND 3 would be needed (24 is good)
Now lets take this example from https://www.w3.org/2021/06/musicxml40/tutorial/midi-compatible-part/
<attributes>
<divisions>24</divisions>
<key>
<fifths>-3</fifths>
<mode>minor</mode>
</key>
<time>
<beats>3</beats>
<beat-type>4</beat-type>
</time>
</attributes>
....
<note>
<pitch>
<step>G</step>
<octave>4</octave>
</pitch>
<duration>12</duration>
<lyric>
<syllabic>single</syllabic>
<text>Dans</text>
</lyric>
</note>
<note>
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>8</duration>
<lyric>
<syllabic>single</syllabic>
<text>un</text>
</lyric>
</note>
What we know about time so far, is: 3/4, divisions = 24 divisions per quarter note. Let's say, for this example BPM = 120.
Now how long exactly does first note play?
Divisions(perQuarterNote) = 24, BPM = 120, Duration = 12
timePerOneDivison = (60 / bpm) / Divisions
and then duration of this note, in seconds, is
duration * ((60 / bpm) / Divisions)
12 * ( (60 / 120) / 24 ) = 0.25 sec.
Based on which stave the note is (left or right hand) you add this duration to your gTime or fTime variable, and that would become the start time of next note. Cool right?
Kinda.. Since I'm also "playing" the notes using the glorious Tone.js something with my math is still not quite right, but visuals look correct, so i blame my audio code / use of transport for now.
I hope this helped somebody. As a final note - here's how it all looks like in current prototype (sheet music supports is a project separate from mainline game for now, i'll merge it in once it's done, or merge main game into this small clean boy.. )