11class TempoMap (list ):
2- def __init__ (self , stream ):
3- self .stream = stream
2+ def __init__ (self , resolution ):
3+ self .resolution = resolution
44
55 def add_and_update (self , event ):
66 self .add (event )
@@ -12,7 +12,7 @@ def add(self, event):
1212 # convert into milliseconds per beat
1313 tempo = tempo / 1000.0
1414 # generate ms per tick
15- event .mpt = tempo / self .stream . resolution
15+ event .mpt = tempo / self .resolution
1616 self .append (event )
1717
1818 def update (self ):
@@ -26,12 +26,62 @@ def update(self):
2626 last = event
2727
2828 def get_tempo (self , offset = 0 ):
29- last = self [0 ]
30- for tm in self [1 :]:
31- if tm .tick > offset :
32- return last
33- last = tm
34- return last
29+ try :
30+ last = self [0 ]
31+ for tm in self [1 :]:
32+ if tm .tick > offset :
33+ return last
34+ last = tm
35+ return last
36+ except IndexError :
37+ # no tempo changes specified in midi track
38+ last = SetTempoEvent ()
39+ last .bpm = 120
40+ last .mpqn = 500
41+ last .mpt = last .mpqn / self .resolution
42+ self .append (last )
43+ return last
44+
45+ class TimeResolver (object ):
46+ """
47+ iterates over a pattern and analyzes timing information
48+ the result of the analysis can be used to convert from absolute midi tick to wall clock time (in milliseconds).
49+ """
50+ def __init__ (self , pattern ):
51+ self .pattern = pattern
52+ self .tempomap = TempoMap (self .pattern .resolution )
53+ self .__resolve_timing ()
54+
55+ def __resolve_timing (self ):
56+ """
57+ go over all events and initialize a tempo map
58+ """
59+ # backup original mode and turn to absolute
60+ original_ticks_relative = self .pattern .tick_relative
61+ self .pattern .make_ticks_abs ()
62+ # create a tempo map
63+ self .__init_tempomap ()
64+ # restore original mode
65+ if (original_ticks_relative ):
66+ self .pattern .make_ticks_rel ()
67+
68+ def __init_tempomap (self ):
69+ """
70+ initialize the tempo map which tracks tempo changes through time
71+ """
72+ for track in self .pattern :
73+ for event in track :
74+ if event .name == "Set Tempo" :
75+ self .tempomap .add (event )
76+ self .tempomap .update ()
77+
78+ def tick2ms (self , absolute_tick ):
79+ """
80+ convert absolute midi tick to wall clock time (milliseconds)
81+ """
82+ ev = self .tempomap .get_tempo (absolute_tick )
83+ ms = ev .msdelay + ((absolute_tick - ev .tick )* ev .mpt )
84+ return ms
3585
3686class EventStreamIterator (object ):
3787 def __init__ (self , stream , window ):
0 commit comments