Timing of exported MIDI

Hi Team,

First some background info: In one of my bands, we’re using an M-Live B.Beat machine to play some backing tracks and have click and cues in our In-Ears. I produce the stems in Ardour.

The B.Beat can also use MIDI files to pilot pedalboards, digital mixer, lights, etc …
We’re not using that today but my experimenting this capibility is the reason for this message :slight_smile:

The song has tempo defined with a tempo marker (93 bpm) and is perfectly in sync with the metronome.
I’ve created a MIDI track and a MIDI region that’s the duration of the song.
On that MIDI track, I’ve created a few MIDI CC events using the automation lanes and a couple of PCs too.
For the sake of testing, these are cleanly aligned on beat 1 of the measures.

Making the begining of the son the Time Origin, I can observe that the beat 1 of the measures (where my MIDI events occur) are:
Measure 1 : 0s
Measure 2 : 2.58s
Measure 3 : 5.161s
etc
image
image
image

So, next, I do a Stem Export of that channel for the Time Span of my song, which gives me a MIDI file that should be in sync with the exported audio stems.

Trying the MIDI file in the B.Beat machine, I was surprised that the MIDI events are not aligned properly with the beats …

So I opened the MIDI file in a decoder, which shows me (filtering only on the CC13 for simplicity):

0.000s | tick 0 | track 1 | ch 1 | Control Change CC 13 value 0
2.000s | tick 7680 | track 1 | ch 1 | Control Change CC 13 value 64
4.000s | tick 15360 | track 1 | ch 1 | Control Change CC 13 value 100
4.000s | tick 15360 | track 1 | Sequencer Specific (3 bytes)
4.000s | tick 15360 | track 1 | Sequencer Specific (3 bytes)
4.000s | tick 15360 | track 1 | Sequencer Specific (3 bytes)
6.000s | tick 23040 | track 1 | ch 1 | Control Change CC 13 value 127
8.000s | tick 30720 | track 1 | ch 1 | Control Change CC 13 value 30
18.000s | tick 69120 | track 1 | ch 1 | Control Change CC 13 value 70
18.000s | tick 69120 | track 1 | Sequencer Specific (3 bytes)
18.000s | tick 69120 | track 1 | Sequencer Specific (3 bytes)
18.000s | tick 69120 | track 1 | Sequencer Specific (3 bytes)
18.000s | tick 69120 | track 1 | End of Track

Timing is not what it should :face_with_diagonal_mouth:
It would be right if the tempo was 120 bpm.

Any thoughts ?
Is it linked to Ardour not exporting tempo maps ?

Out of curiosity, I imported my MIDI file in Qtractor, added my 93bpm tempo and re-exported.

Now the timing looks OK:

0.000s | tick 0 | track 1 | Track Name: “Africa_Automation”
0.000s | tick 0 | track 1 | Tempo 93.00 BPM (645161 us/qn)
0.000s | tick 0 | track 1 | Time Signature 4/4 (clocks 32, 32nds 4)
0.000s | tick 0 | track 1 | ch 1 | Control Change CC 13 value 0
2.581s | tick 3840 | track 1 | ch 1 | Control Change CC 13 value 64
5.161s | tick 7680 | track 1 | ch 1 | Control Change CC 13 value 100
7.742s | tick 11520 | track 1 | ch 1 | Control Change CC 13 value 127
10.323s | tick 15360 | track 1 | ch 1 | Control Change CC 13 value 30
18.065s | tick 26880 | track 1 | End of Track

So I guess I have my answer … Ardour not exporting the tempo in the MIDI file is the issue.
But at least I have a workaround.

I wonder if fixing up the exported MIDI file with that information is something that could be done with a lua script. I haven’t checked to see if there is a hook to automatically run a particular script on export, but maybe that would be a way to get the tempo line added to the file.

I don’t see that being easily done :thinking:
Not only finding the tempo marker that would apply to the exported time span … the midi file is binary not the nice text I posted so needing to call an external program/lib to do hack it …

Nah, I’ll do it manually until Ardour does it properly :sweat_smile:

On Linux you could easily use midicomp which “decompiles” SMF to text and vice versa.

   midicomp foo.mid > foo.txt
   edit foo.txt
   midicomp -c foo.txt > foo.mid
3 Likes

What a great little app, if only it would compile. Looks like the code has not been touched in 9 years and fails miserably to compile.

Worked fine for me on debian, though it might have been packaged (can’t check right now due to travel)

Looks promising indeed !
But like @Lexridge , it won’t compile on my Fedora. Whooooole buch of errors. Seems it needs a serious update.

Looks like in Debian there are midicsv and csvmidi, that do something similar (albeit the format could be a bit more difficult to edit):

Description: translate MIDI file to CSV
Midicsv reads a standard MIDI file and decodes it into a CSV (Comma-Separated
Value) file which preserves all the information in the MIDI file. The ASCII
CSV file may be loaded into a spreadsheet or database application, or processed
by a program to transform the MIDI data (for example, to key transpose a
composition or extract a track from a multi-track sequence). A CSV file in the
format created by midicsv may be converted back into a standard MIDI file with
the csvmidi program.

I have not tried it.

Couldn’t find it in Fedora or 3rd party repos but I did find a python port which was easily installed and works like a charm :slight_smile:
Thanks for the lead !

Well, once I figured out MIDI Tempo is expressed as microseconds for a quarter note I was all set :sweat_smile:

1 Like

Just for sharing, I did find a surprising side effect in my attempt to pilot my Behringer mixer via MIDI.

As visible in the table below, calling back a saved config snapshot is done by sending a Program Change. All good.

But what happens when Ardour (or I guess other DAWs too) sends a PC ? They also send the Bank Select command …
MSB, LSB Control Change = CC 0 and CC 32

It turns out Behringer is actually using these CCs to pilot faders !

It took me a while to figure out why, when sending a PC to recall a config snapshot, the first fader of the mixer dropped to infinity :face_with_raised_eyebrow: :thinking: :exploding_head:

So using the midicsv utilities, I also removed these CC0 and CC32 … And now everything is working as intended :slight_smile:

Looks like it is old style (K&R) C syntax, doesn’t use C89 or C90 style C.
I’ll take a look when I have some off time, the program isn’t very large so might just be a few function prototypes to fix up and then it will compile with current compiler defaults. There is probably a way to force gcc to accept K&R syntax, but it would be worthwhile getting the source closer to modern standards.

While poking around at midicomp (which doesn’t have proper function prototypes :frowning: ) I found in the comments that it was based on mf2t, which was originally written for Atari ST but has been updated to C23 by the original author here:

It also builds the companion program t2mf which is of course needed to go back to MIDI file after converting to text (or to generate a new MIDI file if you generate a text file originally).

2 Likes