this post was submitted on 11 Jun 2025
20 points (95.5% liked)

Programming

20943 readers
28 users here now

Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!

Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.

Hope you enjoy the instance!

Rules

Rules

  • Follow the programming.dev instance rules
  • Keep content related to programming in some way
  • If you're posting long videos try to add in some form of tldr for those who don't want to watch videos

Wormhole

Follow the wormhole through a path of communities [email protected]



founded 2 years ago
MODERATORS
 

I have created a new MIDI format to overcome both the limitations of the current one and the unwillingness of the International MIDI Consortium to develop a MIDI 2.0 file format. So I made my own for my game engine. I even added some primitive scripting features.

But here comes the big problem: now I need to develop an editor. While I created a textual representation of it, which is a weird mix of assembly with Lua influences and essentially musical notes and rhythm as values, but eventually it should have a full GUI editor.

The format so far has the following kind of commands:

  • Flow control commands
  • MIDI emit commands which can be either:
    • Note on and off commands
    • Velocity change (aftertouch)
    • Program change
    • Control change
    • Pitch bend
    • A few other less important commands (SysEx, etc.)
  • Commands for the scripting (Arithmetic commands on writable registers, compare and branch, etc.)
  • The ever important wait command, on which the whole system depends, as it tells the sequencer how much clock cycles have to wait between two commands

I have to process these commands for two display widgets, one displays the notes in a piano roll format, one displays any other commands. However, thanks to the way things work, I usually cannot just process MIDI commands directly. For example, notes are defined by a note-on and note-off event (often with aftertouch), no duration. And then comes editing. And then comes to editing around various wait commands. And then comes to editing around various conditional jump commands.

I started to work on a system that converted and separated each command for display, but it's a bit time consuming, and adds extra complexity. But modifying it a bit and adding a "transpiler" to the two systems would make editing pretty easy to implement. I already added "macro"-like features to the textual representation of the format. Could this work?

top 6 comments
sorted by: hot top controversial new old
[–] [email protected] 5 points 5 days ago* (last edited 5 days ago)

Well, first I gotta ask, is any of this really necessary or worth it? You want to resolve some limitations with the standard MIDI format, but are those limitations worth this much trouble to fix? "Buy dont build" is an important principle for any developer to take to heart because we all want to just do it ourselves, dive into the challenge, fix the little gripes, etc. But sometimes good is good enough and there's no reason to retread the same ground someone else has. If you absolutely need something standard MIDI format can't give you or available editors dont meet your needs, then sure, build away. But otherwise, save yourself the trouble, put your focus on the more important aspect of your project and just use the standard format.

And dont fall for the sunk cost fallacy. You have already invested time into this, and that time is gone. But that doesn't necessarily mean that you should sink in more time if the outcome is not going to justify the additional time cost. It is okay to just shelf it for now. You can always come back to it if you need to later as well.

[–] [email protected] 7 points 5 days ago* (last edited 5 days ago) (1 children)

Man I have no idea but I read your entire post and it seems like you need to pause that work for a day or two. Do something else, touch grass, then come back and I'm sure you'll have your answers.

Also sounds like one of those rare times when talking to a yellow duck would help. And splitting it all into smallest possible problems. Then solve one after another without thinking of the whole.

[–] [email protected] 2 points 5 days ago

I did the "do something else", and I'm still stuck...🙁

[–] [email protected] 0 points 5 days ago* (last edited 5 days ago) (1 children)

Honestly a lot of this post is very inside-baseball with a lot of lingo, and the last paragraph is very dense, so it's hard to know what you mean, especially by the term "transpiler". What is it transpiling to & from, and where does this happen in the overall process of implementing the editor?

I'm sorry I don't have a lot of insight other than: it sounds like you know better than anyone here, so just try it and see what works. Sometimes rewriting a system is unavoidable as you figure out the logic of it.

Also as someone with some interest in programming my own physical MIDI instruments, I'd be interested to hear what limitations of MIDI you're talking about and what your system does differently. It sounds like you've got a pretty advanced use-case if MIDI isn't up to the task.

[–] [email protected] 2 points 3 days ago (1 children)

Basically by transpiling, I'm converting commands to a format with absolute time position rather than the current relative one, so I don't have to deal too much with the relative wait commands, seeking would be easier to implement rather than one using relative positions, and I wouldn't really have the issue with inserting extra commands when relative jump commands exist. As I said, the textual format already have some macros that function in similar vein, such as the [0]: note 0 0x7FFF s.:a-5 macro, that automatically inserts noteon and noteoff commands at the appropriate places when processed, and also jump commands use labels similar to some unstructured programming stuff.

I think I'll try to work on a game for a while, then peek into someone else's code that had similar problems on how they actually did it.

As for the MIDI 1.0 limitations:

  • More than 16 channel implementation is a bit tricky, and I really didn't want the composer to rely on automatic polyphony handling real time (which would likely conflict with sound effects, etc.), nor wanted to deal with that too on top of everything else.
  • Precision issues with Control Change commands, and I wanted most if not all things to be controlled via MIDI easily rather than aggressive preset swapping or SysEx commands. Some special functionality still uses SysEx, like global waveform changing in the FM synth, where you basically command to change one of the 128 possible waveforms to be changed to a custom parameter-generated one. The only thing that cannot be done from MIDI is specifying path for files, which is intentional since it would mess with real-time features.
  • Adaptive soundtracks. To my knowledge, there's not a whole lot of formats for this, let alone ones that are known to be open, and even then many don't go much farther than maybe mixing a few extra tracks they can swap-in, mute, etc., while mine could manipulate instrument parameters, pitch, etc. Instead of going the route of downloading easymp3playback.dll and easymp3playback.h (originally I used sdl-audio), I went with my own audio solution, and since my engine already was custom tailored for "retro pixelart", I doubled down in that direction, and went with a pretty lo-fi sampler and an FM synth so far.
[–] [email protected] 1 points 2 days ago* (last edited 2 days ago)

Okay, that's all very interesting and I love the idea about dynamic music, I've had similar thoughts myself but wouldn't have thought to go this far to make it happen. I'd love to see what you come up with!

My only real thoughts are about the transpiling, so the editor uses relative time codes but the format itself uses absolute, if I understand you, and you're converting between the two?

That to me hints of code smell, because I wonder why that's necessary. For example, could you program the editor to display and work in absolute time codes, or is there something stopping that from happening?

Alternatively you could simply make the format capable of natively understanding both relative and absolute commands, so whichever is more appropriate to the context is what gets used.

Keeping them different seems like it will require you to program two formats, make them compatible with one another and deal with bugs in both of them. Essentially you've not only doubled the number of places where bugs can arise within the formats, you've added the extra step of transpiling which also doubles the number of interactions between the formats, adding even more complexity, even more places where inconsistencies can show up, even more code to sift through to find the problem.

It's the sort of thing that shows up in legacy systems where the programmers don't have the freedom to simply ditch one of the parts.

Personally if I had the freedom of programming the system from scratch I would rather commit completely to a single format and make it work across the entire stack, so then I only have one interpreter/encoder to consider. That one parser would then be the single point of reference for every interaction with the format. Any code that wants to get or place a note for any reason - for playing, editing, recording, whatever - would use the same set of functions, and then you automatically get consistency across all of it.

Edit: another thought about this: if you need some notes to be absolute and others to be relative, it might be worth having an absolute anchor command that other commands can be relative to, and have it indexed, so commands are relative to anchor 1, 2, etc. Maybe anchor 0 is just the start of the song. Also maybe you could set any command as an anchor by referring to its index. That way you can still move around those commands in a relative way while still having the overall format reducible to absolute times during playback. Also a note "duration" could just be an off command set relative to its corresponding on command.

I say that because as another principle I like to make sure that I "name things what they are". If the user is programming things in the editor that are relative, but under the hood they're translated into absolute terms, that will probably lead to unexpected behaviour.