Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Determine the total length of a midi file #373

Open
tqwewe opened this issue Jul 1, 2021 · 12 comments
Open

Determine the total length of a midi file #373

tqwewe opened this issue Jul 1, 2021 · 12 comments

Comments

@tqwewe
Copy link

tqwewe commented Jul 1, 2021

I've created a function to convert the delta to miliseconds:

const microsecondsPerQuarter = (
  midi.tracks[0].find(({ setTempo }) => setTempo).setTempo
).microsecondsPerQuarter;

const deltaToMs = (delta, bpm = 110) =>
  (60_000_000 / (bpm * microsecondsPerQuarter)) * delta;

I'm not sure if this is even correct, but it seems to work for now.
#305 Says something about divisions but I'm not sure how to use that.

From here, how can I determine the total miliseconds of the midi track in order for a perfect loop?

@chrisguttandin
Copy link
Owner

Assuming you only have one setTempo event for the entire track you could do it like this.

seconds = delta * microsecondsPerQuarter / division / 1000000

@tqwewe
Copy link
Author

tqwewe commented Jul 1, 2021

Hi thanks for your reply!

Where does delta come from exactly?

My data looks like this:

{
  "division": 384,
  "format": 1,
  "tracks": [
    [
      {
        "timeSignature": {
          "denominator": 4,
          "metronome": 24,
          "numerator": 4,
          "thirtyseconds": 8
        },
        "delta": 0
      },
      {
        "setTempo": {
          "microsecondsPerQuarter": 545454
        },
        "delta": 0
      },
      {
        "endOfTrack": true,
        "delta": 0
      }
    ],
    [
      {
        "trackName": "Electric Piano",
        "delta": 0
      },
      {
        "programChange": {
          "programNumber": 0
        },
        "channel": 0,
        "delta": 0
      },
      {
        "noteOn": {
          "noteNumber": 59,
          "velocity": 50
        },
        "channel": 0,
        "delta": 0
      },
      {
        "noteOff": {
          "noteNumber": 59,
          "velocity": 0
        },
        "channel": 0,
        "delta": 96
      },
      ...
      {
        "endOfTrack": true,
        "delta": 0
      }
    ]
  ]
}

@chrisguttandin
Copy link
Owner

It's the delta of the event. Let's say you want to figure out the time of the noteOff event in your example. Then it would be:

seconds = 96 * 545454 / 384 / 1000000

In other words the first node stops after about 0.136 seconds.

@tqwewe
Copy link
Author

tqwewe commented Jul 1, 2021

Ah yep I managed to calculate that. But I'm curious to get the entire duration for a perfect loop. For example, if the last note is not at the end of the bar, then there would be some space after of silence

@chrisguttandin
Copy link
Owner

I guess there is no way to derive that information from the file. If you know that your file contains the events for 16 beats you could just use microsecondsPerQuarter * 16 as the length of the loop. But if the last note ends at beat 15 then this will be the end of the MIDI file.

@tqwewe
Copy link
Author

tqwewe commented Jul 2, 2021

If I can know how many beats my file contains, then that'd be perfect. But I cannot find how to get that information.

Importing the file into Ableton live, it detects the full length correctly.
I used this website to write the midi: https://onlinesequencer.net/
And Ableton was able to get the correct lenght of my midi track.

I think the information must be in the file somewhere.

@chrisguttandin
Copy link
Owner

What's the time difference between your last event in the MIDI file and the expected duration that Ableton detects?

@tqwewe
Copy link
Author

tqwewe commented Jul 3, 2021

I created a midi using onlinesequencer.net.

I marked with a red line where I'd expect the loop to occur, and this is also where Ableton puts the loop (at the end of bar 2):

Midi Example

@chrisguttandin
Copy link
Owner

Maybe Ableton just rounds to the next full bar. You can use the denominator of the timeSignature event to determine how many beats a bar has.

@tqwewe
Copy link
Author

tqwewe commented Jul 7, 2021

Hmm I'm still trying to figure out how to use the denominator to calculate this.

@chrisguttandin
Copy link
Owner

chrisguttandin commented Jul 7, 2021

I'm not pretending that I understood the ins and outs of the timeSignature event. I guess it takes years to understand it completely. :-)

Anyway, as far as I understand a denominator of 4 says a bar has 4 beats. And the microsecondsPerQuarter says a beat is 545454 ticks. When we convert this to seconds using the formula from above we end up with about 136ms.

Given that a bar has 4 beats a bar is about 544ms long. So if we want to end up with a full bar we need to make sure the length is a multiple of 544ms or 2181816 ticks (= 545454 * 4 ticks).

By looking at the image from above I guess the accumulated delta of your last noteOff event is about 3409088 ticks (something close to 545454 * 6.25 ticks).

If you now pick the next multiple of 4 you end up with 8.

Does that make sense?

@tqwewe
Copy link
Author

tqwewe commented Jul 7, 2021

Thanks so much for this reply! I'm trying it out now. I'm just a little confused why you chose to include the noteOff 96 ticks in the equasion, I guess because it's the last note off in the track?

I'll let you know how I go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants