MidiMessageSequence double timestamps?


#1

Hi !

I might have missed something, but I don’t understand why MidiMessageSequence timestamps are double ?!
According to the midi file spec, a timestamp is the number of ticks elapsed since the previous event (For example, see : http://www.skytopia.com/project/articles/midi.html)

Therefore, there’s no way this can be non integer, can it ? Why the double then ?


#2

It’s a double to represent time in seconds because - how I see it - it’s more intuitive to work with that way.

You can utilize JUCE’s MidiFile class to convert the message timestamps to seconds from ticks, along with its following method: juce::MidiFile::convertTimestampTicksToSeconds()


#3

On a side note, I’ve not come across a method in the JUCE library to convert the timestamps in seconds to ticks…


#4

Ok, I don’t call that method, so for me, getEventTime always returns ticks, hence integers values. If I’d call it, then getEventTime would return seconds.That makes a lot of sense. Thanks !

However, doesn’t code like that break every single rule of C++ programming ? :slight_smile:

I mean, you don’t know what kind of value you’ve got : should some co-worker starts calling convertTimestampTicksToSeconds() on the original MidiFile object without telling you (or vice-versa), you’re screwed (I guess you’d get a piece of code in a totally unrelated part of the program which stops working because it will assume getEventTime would return ticks while it really returns second, and you have no easy way to check)

Out of curiosity, in which cases do you prefer to have seconds instead of ticks ? I mean, normally software works with either ticks or samples, and in both cases you have to do a conversion (using ppqn + tempo in the first case, and using sample rate in the second) to have use for seconds ?!


#5

I don’t see anything wrong with the code in regards to how C++ is being used… I think you mean design? Which I don’t see anything wrong with that, either.

Regardless, convertTimestampTicksToSeconds() is related to a juce::MidiFile, which means that you should probably use that only in relation to loading MIDI files. Use your judgement!

Simply put; If you start mixing time formats (ie: setting tick timestamps for MIDI messages at one place, and seconds at another, and combining them), you’re asking for trouble. It should be clear how you’re setting such up, shouldn’t it?

I personally rather work with seconds for MIDI because I find it intuitive. 1 tick means nothing to me, especially without a nice zoomable piano roll at hand.


#6

I take your point about C++ design, but if each midi message object contained a pointer to some kind of abstract time object, I don’t think that’d work very well in a real-time situation! And the alternative approach would be to use templated classes to hold the time value, but then every class in the library which uses midi messages would also have to be templated, which would create a total mess!


#7

[quote=“jrlanglois”]I don’t see anything wrong with the code in regards to how C++ is being used… I think you mean design? Which I don’t see anything wrong with that, either.

Regardless, convertTimestampTicksToSeconds() is related to a juce::MidiFile, which means that you should probably use that only in relation to loading MIDI files. Use your judgement!

Simply put; If you start mixing time formats (ie: setting tick timestamps for MIDI messages at one place, and seconds at another, and combining them), you’re asking for trouble. It should be clear how you’re setting such up, shouldn’t it?

I personally rather work with seconds for MIDI because I find it intuitive. 1 tick means nothing to me, especially without a nice zoomable piano roll at hand.[/quote]

Yeah I meant design you’re right, however a function returning doubles which are actually ints could be seen as a code problem, but I’m splitting hair here :slight_smile:

I don’t think our applications do the same thing ! In mine, MidiFiles are mostly used for loading/saving midi sequences (so for example if someone converts the events timstamps to seconds at loading to display the length of the file, it breaks the rest of the code) . I also HAVE to use different time formats, because my “little DAW” uses audio and midi together.

You’re right, it is very clear how to set it up, what I meant is that normally (I don’t remember who I’m quoting), a lib should also be hard to misuse.

My only point is that in a project with several people, one of them can screw up other peoples code. That is of course always possible, but I like to have guards against that.
If you’re alone and you know what you’re doing, it’s not a problem at all :slight_smile:

What about getEventTimeAsTicks and getEventTimeAsSeconds ? :slight_smile:

That’s being said, in my own code, I use the “pointer to some kind of abstract time object” approach, and it works pretty well, and it’s quite powerful (handles tempo changes in real time for example) but, as you said, I have doubts about scalability ! That being said, the tests I’ve done so far, don’t show any overhead, and I tried to keep the Time class small, so it doesn’t use too much memory.

I also use some typedefs (SamplesNumber, TicksNumber, and so on …) which is very usefull to clearup the code and catch mistakes.
(For example SamplesNumber and TicksNumber are both a kind of unsigned int, but I can temporarily typedef SamplesNumber to float and I’ll have a warning everytime I try to assign a SampleNumber to a TickNumber at compile time. )

I personally like strong typing and to make my code fool-proof. Maybe because I make mistakes so often that I need the compiler to stop me ? :smiley:


#8

And how would it know whether the value is stored as ticks, seconds, or something else?


#9

I’d vote against that… The reason being; getEventTimeAsSeconds() would mean the MIDI message needs to pertain to sequence, which such sequence needs to contain all tempos too! Such a method would have to be related to the sequence itself like; MidiMessageSequence::getEventTimeInSecondsAtIndex (int index)


#10

I see that design to be overcomplicated for nothing.

If you stick with one time format, and convert only when necessary - it’s easier to work with. Like in this scenario: a user interacts with MIDI messages, and sets one at a certain time in ticks, in the background - you would actually be setting it as seconds.


#11

And how would it know whether the value is stored as ticks, seconds, or something else?[/quote]

Something else, like a Time class, which deals with all the internal stuff (storage, type conversion, tempo changes and so on).

That’s what I’m doing atm : we wrap MidiSequences into another class. For dealing with Midi only, your approach is perfect, but as soon as you have more complex stuff (audio, automation, tempo changes coming from external devices, and so on…) you need an easy way to get the time in samples, and you can’t use “seconds” to timestamp your events as this changes with the tempo.

That being said, I’m not saying you should change anything. Juce is flexible enough to allow users to build more complex classes wrapping the existing ones, and I’m happy with that. I just wanted to know why the methods return doubles initially, and if it was safe to assume they where integers . I never convert the timestamps to seconds so I don’t have any problem at all :slight_smile:


#12

Not trying to take what you said out of context to distort the question, but you can easily take any time that is seconds based, and convert it to samples easily: Time in samples = Sample-rate * time in seconds


#13

Not trying to take what you said out of context to distort the question, but you can easily take any time that is seconds based, and convert it to samples easily: Time in samples = Sample-rate * time in seconds[/quote]

Of course, it’s true, for samples but not for ticks. The formula would be seconds=60ticks/(ppqnbpm) but you can’t assume bpm is a constant :slight_smile: