Code for writing midi files.

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

I've got working code for generating midi files in my plugin Stepchild. But a problem that I've always encountered is that the way it's written... it can only generate midi notes of a fixed length (steps).. but the stepsequencer now has the ability to create notes of variable length.

The problem is that I don't know how to figure out a way to keep the note length going if notes beneath it are shorter. I need some guidence here... There is something very simple that I must be overlooking. :help:
ModuLR / Radio

Post

When you say 'notes beneath it' do you mean a stacked notes of the same key, or a chord?

AFAIU if your plug generates two concurrent note ons for say C#4, then it is not possible to predict which held key event a corresponding note off will end. I'm not even entirely sure that it would be incorrect for a MIDI device to end both note ons in response to the single note off. :?
Someone shot the food. Remember: don't shoot food!

Post

My bad, I wasn't too clear. I've always had a hard time describing the problem.

Holding mutiple notes. So if I'm holding down C for a bar, but taping D in 16th's. Writing the code for such a midifile is making me crazy because in my head, you would define the length of the note in ticks up front, but that's not how the mid spec works.. basically you just don't turn the note off until you get to that point. I guess something is just kinda screwed in how I've coded it, which doesn't lend itself to keeping track of where I am. Before I knew that every 16th, the note ended, so it was easy to write.. but these variable lengths are just killing me. Maybe I just need some source examples of a good piano roll.. or something to give me some insights.
ModuLR / Radio

Post

I'm doing some work over this weekend on the MP5, I'll try and grab some of my MIDI code and email it to you.

In short though, an easy approach would be to create a timeline array[1] that simply stores every event, with a time stamp, in the order that they occur, IE:

#1 - Time = 0, Event = C5 Note On
#2 - Time = 512, Event = C6 Note On
#3 - Time = 544, Event = C6 Note Off
#4 - Time = 1024, Event = C5 Note Off

and a simply counter would work through the list, waiting until ticks matches the time stamp of the next event in the list, and then processing that event and moving on to the next event.

[1] if the event list is likely to be long, or regularly edited you may wish to use something like alinked list for better performance, otherwise a bruteforce linear array will suffice.
Someone shot the food. Remember: don't shoot food!

Post

hmm, now having reread your post, I'm guessing you are referring specifically to creating MIDI style .mid files, rather than simply handling an eventlist for playback?

If so the same approach would mostly hold true but you'll need to fix your time stamps to variable byte length time encoding. I need to code this myself for doing drag and drop from MKey and MP5, so again, I'll send you the code when I've done it.
Someone shot the food. Remember: don't shoot food!

Post

This is the code I used for Var Length Bytes... I just basically converted it from c++, and it seems to work well. I guess normally, you'd probably make it a function to return a value. This isn't the case here.

Code: Select all

  Procedure WriteVarLen (ValueToConvert:longint);                                // Converts a value in Ticks to a
                                                                                 // Variable Length Byte as needed
    var  VarLenArrayCount : byte;                                                // by Midi spec.  Remember to take
                                                                                 // values in reverse order when
    begin                                                                        // accessing VarLenArray.
      VarLenArrayCount := 0;                                                     //
      VarLenArray[VarLenArrayCount] := (ValueToConvert AND $7f);
      VarLenArrayCount := VarLenArrayCount + 1;
      while (ValueToConvert >= $80) do                                           // VarLenArrayCount = # of bytes needed.
        begin
          ValueToConvert := ValueToConvert shr 7;
          VarLenArray[VarLenArrayCount] := (ValueToConvert AND $7f) or $80;
          VarLenArrayCount := VarLenArrayCount + 1;
        end;
    end;
Hopefully that prints out correctly. :) Let me let this timestamp thing sink in my head a bit more.. and I'll post another reply.
ModuLR / Radio

Post

valley wrote:I'm doing some work over this weekend on the MP5, I'll try and grab some of my MIDI code and email it to you.

In short though, an easy approach would be to create a timeline array[1] that simply stores every event, with a time stamp, in the order that they occur, IE:

#1 - Time = 0, Event = C5 Note On
#2 - Time = 512, Event = C6 Note On
#3 - Time = 544, Event = C6 Note Off
#4 - Time = 1024, Event = C5 Note Off

and a simply counter would work through the list, waiting until ticks matches the time stamp of the next event in the list, and then processing that event and moving on to the next event.

[1] if the event list is likely to be long, or regularly edited you may wish to use something like alinked list for better performance, otherwise a bruteforce linear array will suffice.
I think this goes back to something you had mentioned to me before... but I thought I could work around it, and it turns out I'm kinda stupid for trying.. hahaha.


Basically, since I knew there would be a fixed # of steps, I created an array that contains 32 steps. Then I have a routine which sifts thru the passed block of samples and checks to see if it's triggered a step (meaning 1 thru 32). If it has, then it checks down the bank to determine which banks are active. There really isn't any timestamp information in the array in this case. The timestamp is more or less a routine that just checks to see if it's reached a step. Fatal flaw. Damnit! I'd have to go back a change quite a bit... blah! :roll: :? :cry:

after all this time I finally get what you mean.. I dunno why it took so long to seep in. 8)
ModuLR / Radio

Post

http://www.wilsonc.demon.co.uk/d7powerseq.htm is a full-blown midi sequencer written in delphi and open-source ;)
Includes components for midi file i/o, piano roll etc lots of interesting stuff also the code is pretty clean.

The version on the site is for D7 but you can find sources for previous compilers on torrys.net or similar

Post

Oops - sorry Mod, I missed your last post. :oops:

Jaltoh_, that's quite a cool link. Maybe it wouldn't hurt to add it to the main links thread. Seems like any Delphi programmers would find at least something helful in that code.
Someone shot the food. Remember: don't shoot food!

Post

That might help out quite a bit... I'm gonna dive in and take a peek (hopefully it'll shed some light on how to do things a bit more correctly).

Thanks! :D
ModuLR / Radio

Post

If you're after C code, you could look at TiMidity++ or Jazz++, both open source.

Post Reply

Return to “DSP and Plugin Development”