-
Notifications
You must be signed in to change notification settings - Fork 210
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
Add different time units to MidiFile #115
base: main
Are you sure you want to change the base?
Conversation
a75bff9
to
bc2988c
Compare
bc2988c
to
a3532bc
Compare
Comments welcome, thus ping @olemb. |
I cast my vote for numpydoc. It hasn't failed me yet! |
Did you run the tox tests? You can do so by getting the latest revision then:
The first one is only necessary to make sure you have all the dev packages installed before you run tox. |
also +1 from me for adding a bunch of unit tests, that's great!! |
Of course I ran the tests, but as said in #114 (and copied into this PR's TODO items) some tests fails due to different rounding in Python 2/3. My question was on what functionality is wanted. Either the rounding could be unified or the tests could be edited to check for the current Python version and test accordingly. Either way it would be extremely helpful for all if there were some sort of continuous integration (e.g. TravisCI). But I also wanted to get a more general feedback on this PR. Is this functionality wanted in mido? If yes, what changes to the PR are needed. If no I add them to the classes inherited from mido in my own projects. Then, still #114 should be merged, since it contains bug fixes. |
a3532bc
to
658eb6b
Compare
|
274d411
to
37e920b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copied the changed files into Mido. units and midifiles. The result was that every Midi file played in extreme slow motion.
Interesting. Can you explain how you checked this in order to repeat (and fix) it. Furthermore it would be interesting which commit adds this slowing down. Is #114 affected as well? |
37e920b
to
3b989cf
Compare
I guess I figured it out: I introduced a However, this reminds me on how difficult it is to change some code without proper tests. I can write a test for this but it requires a MIDI file to be tested. Are there any suggestions on which properties such a file should have or does something like a "standard" MIDI test file exist? |
Many thanks for that I will give it a try. Original problem is difficult to explain but when playing a song that begins with a slow tempo it takes ages for the first note to play. In the case of the attached file about 11 secs but on a daw it starts instantly. I wondered if it was something to do with temp and time sig so tried your changes. I also think that it might be a delta time calc of some sort that is calculating the time to next message incorrectly when the first note is a rest. |
The latest changes fixed the slow motion - Great work. There still remains the problem of a long time to get to the first note when playing the example file as opposed to the short wait when playing in a DAW. I will print out the time delta for each message to try and find out why it takes so long to get to the first note of the above file and similar slow tempo midi files starting with rests. Again many thanks Regards |
The long delay at the beginning is unrelated to the changes in this PR. Caching the merged tracks can indeed solve the problem -- or at least lower its extend. I'll look into it and incorporate this suggestion as well, possibly in a separate PR. The |
Caching the merged tracks only solves the problem of creating loops such as drum loops where they have to be seamless. The problem I am experiencing with long time to first note when a midi file starts that has quite a lot of control changes and a slow tempo and or rests at beginning of song is that the first note on message seems to have a very large time Delta. In the file I uploaded the first one has 12 secs. Most of proceeding channel messages have 0 time Delta but some get 3secs. Saw shows them all as 0. The odd deltas seem to follow where but I only had a brief look. Will try to describe better later. This is not isolated to this midi. |
I missed out seems to follow sysex messages |
Status? |
I am not sure what the status of this PR is. I am still waiting for any kind of response to the questions I raised. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this change looks great. Very nicely done! I hope it could be merged. Particularly the unit
argument to MidiFile would be useful.
Just some minor nitpicks.
docs/midi_files.rst
Outdated
for short) have to be decided upon. | ||
To convert from MIDI time to absolute time in seconds, the tempo (either | ||
in number of beats per minute (BPM) or microseconds per quarter note, see | ||
above) and ticks per per quarter note have to be decided upon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see above
should be a reST hypertext reference to the relevant section instead.
mido/midifiles/midifiles.py
Outdated
class MidiFile(object): | ||
def __init__(self, filename=None, file=None, | ||
type=1, ticks_per_beat=DEFAULT_TICKS_PER_BEAT, | ||
charset='latin1', | ||
unit='seconds', timing='relative', charset='latin1', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this break backwards compatibility or were these defaults implicit before (I think yes, just wanna double check)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, these were implicit before, so this change shouldn't break anything. There was a bug in a previous version which changed the default behaviour, but this is fixed (see comment above). However, I can't guarantee this because there are no tests covering this aspect.
mido/midifiles/midifiles.py
Outdated
delta = tick2beat(msg.time, self.ticks_per_beat, | ||
time_signature) | ||
else: | ||
raise ValueError("`unit` must be either 'ticks', 't', " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The shorthands should be removed ('t', 's', 'b' are not obvious) as they provide very little benefit at a big cost. MidiFile(unit='beats')
is a lot cleaner and easier to search in the docs after.
I.e.
if self.unit.lower() == 'ticks':
is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO the supported units should be defined by an Enum
with sensible names.
This would make the code clearer and simplify types verification.
mido/midifiles/midifiles.py
Outdated
else: | ||
delta = 0 | ||
# Convert relative time to absolute values if needed | ||
if self.timing.lower() in ('a', 'abs', 'absolute'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. Shorthands are harder to search after on StackOverflow etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, an Enum
would solve this.
No need to check for multiple strings variations.
mido/midifiles/units.py
Outdated
""" | ||
# Note: both tempo (microseconds) and ticks are per quarter note |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove comment.
mido/midifiles/units.py
Outdated
""" | ||
# Note: both tempo (microseconds) and ticks are per quarter note |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove comment.
scale = tempo * 1e-6 / ticks_per_beat | ||
return tick * scale | ||
|
||
|
||
def second2tick(second, ticks_per_beat, tempo): | ||
def second2tick(second, ticks_per_beat=DEFAULT_TICKS_PER_BEAT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Convert absolute time in seconds to ticks." > "Round absolute time in seconds to ticks." IMO, or something of that sort to signal that the conversion is lossy.
…idiFile. The unit (MidiFile.unit) holds a string indicating which unit to use to display event timings. Possible values are ticks, seconds and beats. Furthermore the timings can be viewed as absolute values or relative to the preceeding event as indicated by MidiFile.timing. To support timing information in beats, time signature event handling was added to MidiFile.__iter__.
… note to units.py
3b989cf
to
f03c898
Compare
Any advancements?! I can't wait for this improvement |
Unfortunately, I haven't heard back from the developers after I made some changes to the PR. I will update the code and rebase on the current master branch. |
Note: This PR adds the enhancements mentioned in #102 to
MidiFile
. It is based on PR #114, i.e. it includes all commits of #114. Needs to be rebased when this PR is merged.Content
Add different time units and relative/absolute timimg capability to
MidiFile
.MidiFile.unit
can hold a string indicating which unit should be used to display event timings. Possible values areticks
,seconds
,beats
and various shortcuts thereof (t
,s
,sec
, andb
).Furthermore the timings can be viewed as absolute values or relative to the preceeding event as indicated by
MidiFile.timing
. This attribute can also hold a string, possible values areabsolute
(shortcuts:a
,abs
) orrelative
(shortcuts:r
,rel
).To support timing information in beats, time signature event handling was added to
MidiFile.__iter__
and the needed unit conversion functions tomidifiles.units
.Minor modifications
These modifications are split into separate commits which can be skipped if wanted:
midifiles.units
,get_seconds_per_tick
function,Before being able to be merged, these points should be discussed/addressed:
MidiFile
.tick2beat
andbeat2tick
into the main namespace?tick2beat
andbeat2tick
in the API docs.ticks_per_beat
is a bit misleading since it rather should beticks_per_quarter_note
. Renaming the variable, however, may break existing code, so this is a rather bad option. Maybe adding a new variable (and deprecate the old one, but keep it around for backwards compatibility) is a better approach.midi_files.rst
.EDIT: merged the TODO items of #114 into this PR, since they also apply here.