11#!/usr/bin/env python3
22"""A simple JACK timebase master."""
3-
43import argparse
5- import sys
64from threading import Event
75
86import jack
@@ -12,31 +10,31 @@ class TimebaseMasterClient(jack.Client):
1210 def __init__ (self , name , * , bpm = 120.0 , beats_per_bar = 4 , beat_type = 4 ,
1311 ticks_per_beat = 1920 , conditional = False , debug = False , ** kw ):
1412 super ().__init__ (name , ** kw )
15- self .beats_per_bar = int ( beats_per_bar )
16- self .beat_type = int ( beat_type )
13+ self .beats_per_bar = beats_per_bar
14+ self .beat_type = beat_type
1715 self .bpm = bpm
1816 self .conditional = conditional
1917 self .debug = debug
20- self .ticks_per_beat = int ( ticks_per_beat )
18+ self .ticks_per_beat = ticks_per_beat
2119 self .stop_event = Event ()
22- self .set_shutdown_callback (self .shutdown )
20+ self .set_shutdown_callback (self .shutdown_callback )
2321
24- def shutdown (self , status , reason ):
22+ def shutdown_callback (self , status , reason ):
2523 print ('JACK shutdown:' , reason , status )
2624 self .stop_event .set ()
2725
28- def _tb_callback (self , state , nframes , pos , new_pos ):
26+ def timebase_callback (self , state , nframes , pos , new_pos ):
2927 if self .debug and new_pos :
30- print (" New pos:" , jack .position2dict (pos ))
28+ print (' New pos:' , jack .position2dict (pos ))
3129
3230 # Adapted from:
3331 # https://github.com/jackaudio/jack2/blob/develop/example-clients/transport.c#L66
3432 if new_pos :
35- pos .beats_per_bar = float ( self .beats_per_bar )
33+ pos .beats_per_bar = self .beats_per_bar
3634 pos .beats_per_minute = self .bpm
37- pos .beat_type = float ( self .beat_type )
38- pos .ticks_per_beat = float ( self .ticks_per_beat )
39- pos .valid = jack ._lib . JackPositionBBT
35+ pos .beat_type = self .beat_type
36+ pos .ticks_per_beat = self .ticks_per_beat
37+ pos .valid = jack .POSITION_BBT
4038
4139 minutes = pos .frame / (pos .frame_rate * 60.0 )
4240 abs_tick = minutes * self .bpm * self .ticks_per_beat
@@ -45,9 +43,11 @@ def _tb_callback(self, state, nframes, pos, new_pos):
4543 pos .bar = int (abs_beat / self .beats_per_bar )
4644 pos .beat = int (abs_beat - (pos .bar * self .beats_per_bar ) + 1 )
4745 pos .tick = int (abs_tick - (abs_beat * self .ticks_per_beat ))
48- pos .bar_start_tick = pos .bar * self .beats_per_bar * self .ticks_per_beat
46+ pos .bar_start_tick = (
47+ pos .bar * self .beats_per_bar * self .ticks_per_beat )
4948 pos .bar += 1 # adjust start to bar 1
5049 else :
50+ assert pos .valid & jack .POSITION_BBT
5151 # Compute BBT info based on previous period.
5252 pos .tick += int (nframes * pos .ticks_per_beat *
5353 pos .beats_per_minute / (pos .frame_rate * 60 ))
@@ -62,70 +62,68 @@ def _tb_callback(self, state, nframes, pos, new_pos):
6262 pos .bar_start_tick += pos .beats_per_bar * pos .ticks_per_beat
6363
6464 if self .debug :
65- print (" Pos:" , jack .position2dict (pos ))
65+ print (' Pos:' , jack .position2dict (pos ))
6666
6767 def become_timebase_master (self , conditional = None ):
68- return self . set_timebase_callback ( self . _tb_callback , conditional
69- if conditional is not None
70- else self .conditional )
68+ if conditional is None :
69+ conditiona = self . conditional
70+ return self .set_timebase_callback ( self . timebase_callback , conditional )
7171
7272
7373def main (args = None ):
7474 ap = argparse .ArgumentParser (description = __doc__ )
7575 ap .add_argument (
7676 '-d' , '--debug' ,
7777 action = 'store_true' ,
78- help = "Enable debug messages" )
78+ help = 'enable debug messages' )
7979 ap .add_argument (
8080 '-c' , '--conditional' ,
8181 action = 'store_true' ,
82- help = "Exit if another timebase master is already active" )
82+ help = 'exit if another timebase master is already active' )
8383 ap .add_argument (
8484 '-n' , '--client-name' ,
8585 metavar = 'NAME' ,
8686 default = 'timebase' ,
87- help = " JACK client name (default: %(default)s)" )
87+ help = ' JACK client name (default: %(default)s)' )
8888 ap .add_argument (
8989 '-m' , '--meter' ,
9090 default = '4/4' ,
91- help = "Meter as <beats-per-bar>/<beat-type> (default: %(default)s)" )
91+ help = 'meter as <beats-per-bar>/<beat-type> (default: %(default)s)' )
9292 ap .add_argument (
9393 '-t' , '--ticks-per-beat' ,
9494 type = int ,
9595 metavar = 'NUM' ,
9696 default = 1920 ,
97- help = "Ticks per beat (default: %(default)s)" )
97+ help = 'ticks per beat (default: %(default)s)' )
9898 ap .add_argument (
9999 'tempo' ,
100100 nargs = '?' ,
101101 type = float ,
102102 default = 120.0 ,
103- help = "Tempo in beats per minute (0.1-300.0, default: %(default)s)" )
103+ help = 'tempo in beats per minute (default: %(default)s)' )
104104
105105 args = ap .parse_args (args )
106106
107107 try :
108- beats_per_bar , beat_type = (int (x ) for x in args .meter .split ('/' , 1 ))
109- except (TypeError , ValueError ):
110- print ("Error: invalid meter: {}\n " .format (args .meter ))
111- ap .print_help ()
112- return 2
108+ beats_per_bar , beat_type = map (float , args .meter .split ('/' ))
109+ except ValueError :
110+ ap .error ('Invalid meter: ' + args .meter )
113111
114112 try :
115113 tbmaster = TimebaseMasterClient (
116114 args .client_name ,
117- bpm = max ( 0.1 , min ( 300.0 , args .tempo )) ,
115+ bpm = args .tempo ,
118116 beats_per_bar = beats_per_bar ,
119117 beat_type = beat_type ,
120118 ticks_per_beat = args .ticks_per_beat ,
121119 debug = args .debug )
122120 except jack .JackError as exc :
123- return " Could not create timebase master JACK client: {}" .format (exc )
121+ ap . exit ( ' Could not create timebase master JACK client: {}' .format (exc ) )
124122
125123 with tbmaster :
126124 if tbmaster .become_timebase_master (args .conditional ):
127125 try :
128- print (" Press Ctrl-C to quit..." )
126+ print (' Press Ctrl-C to quit...' )
129127 tbmaster .stop_event .wait ()
130128 except KeyboardInterrupt :
131129 print ('' )
@@ -136,8 +134,8 @@ def main(args=None):
136134 # another JACK client might have grabbed timebase master
137135 pass
138136 else :
139- return " Timebase master already present. Exiting..."
137+ ap . exit ( ' Timebase master already present. Exiting...' )
140138
141139
142140if __name__ == '__main__' :
143- sys . exit ( main () or 0 )
141+ main ()
0 commit comments