1
1
class TempoMap (list ):
2
- def __init__ (self , stream ):
3
- self .stream = stream
2
+ def __init__ (self , resolution ):
3
+ self .resolution = resolution
4
4
5
5
def add_and_update (self , event ):
6
6
self .add (event )
@@ -12,7 +12,7 @@ def add(self, event):
12
12
# convert into milliseconds per beat
13
13
tempo = tempo / 1000.0
14
14
# generate ms per tick
15
- event .mpt = tempo / self .stream . resolution
15
+ event .mpt = tempo / self .resolution
16
16
self .append (event )
17
17
18
18
def update (self ):
@@ -26,12 +26,62 @@ def update(self):
26
26
last = event
27
27
28
28
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
35
85
36
86
class EventStreamIterator (object ):
37
87
def __init__ (self , stream , window ):
0 commit comments