Audio/AudioControl: Lots of fixes
[audiocontrol.git] / config.py
index 3ec155c..9196350 100644 (file)
--- a/config.py
+++ b/config.py
@@ -4,9 +4,9 @@ from Actions import Actions as Action, action
 from Views import EventWidget
 from Events import Event
 import main
-import Joyboard, Keyboard, Process
+import Joyboard, Keyboard, Process, TimeMachine, AlsaPlayer, Metronome
 import Looper, Mixer
-import sys, curses, time, os
+import sys, curses, time, os, os.path, subprocess
 from curses.ascii import alt, ctrl
 
 def shift(letter) : return ord(chr(letter).upper())
@@ -19,46 +19,43 @@ global_map = Bindings.KeyMap()
 #
 # Display size: 88x22
 
-#Logger.init(main.viewmanager, 38, 0, 37, 10, 'audiocontroller.log')
+#Logger.init(main.viewmanager, 0, 17, 88, 5, 'audiocontroller.log')
 Logger.init(main.viewmanager, 0, 17, 88, 5)
 
-jb = None
-ctl = None
-if os.path.exists('/dev/input/js0'):
-    jb = Joyboard.register(
-        viewmanager = main.viewmanager,
-        dispatcher = main.dispatcher,
-        
-        context          = 'jb0',
-        label            = 'Foot Switch',
-        numeric_switches =  10,
-        alpha_switches   =   5,
-        x                =   0,
-        y                =  10,
-        dx               =  88,
-        size             =   7,
-        
-        device           = '/dev/input/js0',
-        bits             = { 1:1, 3:2, 2:4, 0:8 },
-    )
-
-    ctl = Joyboard.registerController(
-        viewmanager = main.viewmanager,
-        dispatcher = main.dispatcher,
-        keylist = main.keylist,
-        source = jb,
-        
-        context          = 'c0',
-        name             = 'Control',
-        x                = 75,
-        y                =  0,
-        dx               = 13,
-        dy               = 10,
-
-        controller       = 0,
-        low              = -27200,
-        high             = -32700,
-    )        
+jb = Joyboard.register(
+    viewmanager = main.viewmanager,
+    dispatcher = main.dispatcher,
+    
+    context          = 'jb0',
+    label            = 'Foot Switch',
+    numeric_switches =  10,
+    alpha_switches   =   5,
+    x                =   0,
+    y                =  10,
+    dx               =  88,
+    size             =   7,
+    
+    device           = os.path.exists('/dev/input/js0') and '/dev/input/js0' or None,
+    bits             = { 1:1, 3:2, 2:4, 0:8 },
+)
+
+ctl = Joyboard.registerController(
+    viewmanager = main.viewmanager,
+    dispatcher = main.dispatcher,
+    keylist = main.keylist,
+    source = jb,
+    
+    context          = 'c0',
+    name             = 'Control',
+    x                = 75,
+    y                =  0,
+    dx               = 13,
+    dy               = 10,
+
+    controller       = 0,
+    low              = -27200,
+    high             = -32700,
+)        
 
 Keyboard.register(
     viewmanager = main.viewmanager,
@@ -68,9 +65,10 @@ Keyboard.register(
     label            = 'Key Bindings',
     x                =  0,
     y                =  0,
-    dx               = 52,
+    dx               = 25,
     dy               = 10,
-    size             =  7
+    size             = 11,
+    ignore_keys      = ( '0','1','2','3','4','5','6','7','8','9','0','a','b','c','d','e' )
 )
 
 ###########################################################################
@@ -91,12 +89,11 @@ for i,k in enumerate(('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b'
     Action.register( Events.EmitEvent('key_%s' % k, main.dispatcher, Event('jb0', i)) )
     global_map.add( Binding( Event('kbd',key(k)), 'Foot %s' % k.upper(), Action['key_%s' % k] ) )
     
-if ctl is not None:
-    Action.register( Joyboard.StepController( 'controller_increment', ctl, +1 ) )
-    Action.register( Joyboard.StepController( 'controller_decrement', ctl, -1 ) )
+Action.register( Joyboard.StepController( 'controller_increment', ctl, +1 ) )
+Action.register( Joyboard.StepController( 'controller_decrement', ctl, -1 ) )
 
-    global_map.add( Binding( Event('kbd', curses.KEY_UP), 'Increment', Action['controller_increment'] ) )
-    global_map.add( Binding( Event('kbd', curses.KEY_DOWN), 'Decrement', Action['controller_decrement'] ) )
+global_map.add( Binding( Event('kbd', curses.KEY_UP), 'Increment', Action['controller_increment'] ) )
+global_map.add( Binding( Event('kbd', curses.KEY_DOWN), 'Decrement', Action['controller_decrement'] ) )
 
 Action.register( Actions.ChangeBindingsRelative( 'unset_this_map', 0, [] ) )
 
@@ -127,6 +124,9 @@ Action.register( Looper.Command('looper_reverse', looper, 'reverse') )
 Action.register( Looper.Command('looper_oneshot', looper, 'oneshot') )
 Action.register( Looper.Command('looper_undo_all', looper, 'undo_all') )
 Action.register( Looper.Command('looper_redo_all', looper, 'redo_all') )
+Action.register( Looper.Command('looper_mute_off', looper, 'mute_off') )
+Action.register( Actions.Macro( 'looper_trigger_unmute',
+                                [ 'looper_trigger', 'looper_mute_off' ] ) )
 
 looper_main_map.add ( Binding( Event('jb0',0),  'Rec',    Action['looper_record'] ) )
 looper_main_map.add ( Binding( Event('jb0',1),  'Over',   Action['looper_overdub'] ) )
@@ -136,46 +136,51 @@ looper_main_map.add ( Binding( Event('jb0',4),  'Redo',   Action['looper_redo']
 looper_main_map.add ( Binding( Event('jb0',5),  'Mute',   Action['looper_mute'] ) )
 looper_main_map.add ( Binding( Event('jb0',6),  'Trig',   Action['looper_trigger'] ) )
 looper_main_map.add ( Binding( Event('jb0',7),  'Once',   Action['looper_oneshot'] ) )
-looper_main_map.add ( Binding( Event('jb0',8),  'Ins',    Action['looper_insert'] ) )
-looper_main_map.add ( Binding( Event('jb0',9),  'Repl',   Action['looper_replace'] ) )
+#looper_main_map.add ( Binding( Event('jb0',8),  'Ins',    Action['looper_insert'] ) )
+#looper_main_map.add ( Binding( Event('jb0',9),  'Repl',   Action['looper_replace'] ) )
+looper_main_map.add( Binding( Event('jb0',8), 'Ctl Up', Action['controller_increment'] ) )
+looper_main_map.add( Binding( Event('jb0',9), 'Ctl Dn', Action['controller_decrement'] ) )
 looper_main_map.add ( Binding( Event('jb0',12), 'Undo A', Action['looper_undo_all'] ) )
 looper_main_map.add ( Binding( Event('jb0',13), 'Redo A', Action['looper_redo_all'] ) )
 looper_main_map.add ( Binding( Event('jb0',14), 'Subst',  Action['looper_substitute'] ) )
 
 
+
 looper_param_map = Bindings.KeyMap( 'Parameters' )
 Action.register( Actions.ChangeBindingsRelative('looper_set_param_map', 1, [looper_param_map] ) )
 looper_main_map.add ( Binding( Event('jb0',11), '[Param]', Action['looper_set_param_map'] ) )
 
-if ctl is not None:
-    Action.register( Looper.AssignController( 'looper_parm_rec_thresh', looper, ctl, 'Rec.Thresh.',
-                                              'rec_thresh', 0.0, 1.0 ) )
-    Action.register( Looper.AssignController( 'looper_parm_feedback', looper, ctl, 'Feedback',
-                                              'feedback', 0.0, 1.0 ) )
-    Action.register( Looper.AssignController( 'looper_parm_dry', looper, ctl, 'Dry Level',
-                                              'global_dry', 0.0, 1.0 ) )
-    Action.register( Looper.AssignController( 'looper_parm_wet', looper, ctl, 'Wet Level',
-                                              'global_wet', 0.0, 1.0 ) )
-    Action.register( Looper.AssignController( 'looper_parm_igain', looper, ctl, 'In. Gain',
-                                              'global_input_gain', 0.0, 1.0 ) )
-
-    steps = [ 1.0 ]
-    for i in range(6):
-        x = pow(2.0,2.0*(i+1)/12.0)
-        steps.append(x)
-        steps[0:0] = [1/x]
-
-    Action.register( Looper.AssignController( 'looper_parm_rate', looper, ctl, 'Rate',
-                                              'rate', 0.5, 2.0, steps ) )
-
-    looper_param_map.add( Binding( Event('jb0',5),  'Feedb', Action['looper_parm_feedback'] ) )
-    looper_param_map.add( Binding( Event('jb0',6),  'Dry',   Action['looper_parm_dry'] ) )
-    looper_param_map.add( Binding( Event('jb0',7),  'Wet',   Action['looper_parm_wet'] ) )
-    looper_param_map.add( Binding( Event('jb0',8),  'Gain',  Action['looper_parm_igain'] ) )
-    looper_param_map.add( Binding( Event('jb0',9),  'Rec T', Action['looper_parm_rec_thresh'] ) )
-    looper_param_map.add( Binding( Event('jb0',12), '',      Actions.Nop() ) )
-    looper_param_map.add( Binding( Event('jb0',13), 'Rev',    Action['looper_reverse'] ) )
-    looper_param_map.add( Binding( Event('jb0',14), 'Rate',  Action['looper_parm_rate'] ) )
+Action.register( Looper.AssignController( 'looper_parm_rec_thresh', looper, ctl, 'Rec.Thresh.',
+                                          'rec_thresh', 0.0, 1.0 ) )
+Action.register( Looper.AssignController( 'looper_parm_feedback', looper, ctl, 'Feedback',
+                                          'feedback', 0.0, 1.0 ) )
+Action.register( Looper.AssignController( 'looper_parm_dry', looper, ctl, 'Dry Level',
+                                          'global_dry', 0.0, 1.0 ) )
+Action.register( Looper.AssignController( 'looper_parm_wet', looper, ctl, 'Wet Level',
+                                          'global_wet', 0.0, 1.0 ) )
+Action.register( Looper.AssignController( 'looper_parm_igain', looper, ctl, 'In. Gain',
+                                          'global_input_gain', 0.0, 1.0 ) )
+
+steps = [ 1.0 ]
+for i in range(6):
+    x = pow(2.0,2.0*(i+1)/12.0)
+    steps.append(x)
+    steps[0:0] = [1/x]
+
+Action.register( Looper.AssignController( 'looper_parm_rate', looper, ctl, 'Rate',
+                                          'rate', 0.5, 2.0, steps ) )
+
+looper_param_map.add( Binding( Event('jb0',5),  '(Feedb)', Action['looper_parm_feedback'] ) )
+looper_param_map.add( Binding( Event('jb0',6),  '(Dry)',   Action['looper_parm_dry'] ) )
+looper_param_map.add( Binding( Event('jb0',7),  '(Wet)',   Action['looper_parm_wet'] ) )
+#looper_param_map.add( Binding( Event('jb0',8),  '(Gain)',  Action['looper_parm_igain'] ) )
+#looper_param_map.add( Binding( Event('jb0',9),  '(Rec T)', Action['looper_parm_rec_thresh'] ) )
+looper_param_map.add( Binding( Event('jb0',12), '',        Actions.Nop() ) )
+#looper_param_map.add( Binding( Event('jb0',13), 'Rev',     Action['looper_reverse'] ) )
+looper_param_map.add( Binding( Event('jb0',14), '(Rate)',  Action['looper_parm_rate'] ) )
+
+looper_param_map.add( Binding( Event('jb0',12),  '(Gain)',  Action['looper_parm_igain'] ) )
+looper_param_map.add( Binding( Event('jb0',13),  '(Rec T)', Action['looper_parm_rec_thresh'] ) )
 
 looper_param_map.add( Binding( Event('jb0',11), '[Main]',    Action['unset_this_map'] ) )
 
@@ -187,20 +192,18 @@ looper.set('sync',1)
 ###########################################################################
 # Mixer and effects
 
-mixer_map = Bindings.KeyMap('Mixer & Effects')
+mixer_map = Bindings.KeyMap('Master')
 Action.register( Actions.ChangeBindingsRelative( 'mode_mixer', 0, [ mixer_map ] ) )
 
-looper_main_map.add( Binding( Event('jb0',10),  '[Mixer]', Action['mode_mixer'] ) )
-
 mixer = Mixer.register(
     viewmanager = main.viewmanager,
     oscserver = main.oscserver,
 
     context  = 'mix',
-    label    = 'Mixer',
-    x        = 52,
-    y        =  0,
-    dx       = 23,
+    label    = 'Master',
+    x        = 25,
+    y        = 0,
+    dx       = 25,
     dy       = 4,
 
     channels = ( 'Guitar', 'Voice' ),
@@ -212,47 +215,215 @@ gain = Mixer.register(
     oscserver = main.oscserver,
 
     context  = 'gain',
-    label    = 'Gain',
-    x        = 52,
-    y        =  7,
-    dx       = 23,
+    label    = 'Lead Gain',
+    x        = 25,
+    y        =  4,
+    dx       = 25,
     dy       = 3,
 
     channels = ( 'Guitar', ),
     remote  = ('127.0.0.1', 9902),
 )
 
-Action.register( Mixer.AssignController( 'mixer_guitar_level', mixer, ctl, 'Guitar', 1 ) )
-Action.register( Mixer.ToggleMuteChannel( 'mixer_mute_guitar', mixer, 1 ) )
-Action.register( Mixer.AssignController( 'mixer_voice_level', mixer, ctl, 'Voice', 2 ) )
-Action.register( Mixer.ToggleMuteChannel( 'mixer_mute_voice', mixer, 2 ) )
-Action.register( Mixer.AssignController( 'mixer_master_level', mixer, ctl, 'Master', 0 ) )
-Action.register( Mixer.ToggleMuteAll( 'mixer_mute_all', mixer ) )
-Action.register( Mixer.CycleVolume( 'mixer_cycle_gain', gain, 1, ( 0.0, 2.0, 4.0 ) ) )
-
-mixer_map.add( Binding( Event('jb0',0),  'Rec',    Action['looper_record'] ) )
-mixer_map.add( Binding( Event('jb0',1),  'Over',   Action['looper_overdub'] ) )
-mixer_map.add( Binding( Event('jb0',2),  'Mult',   Action['looper_multiply'] ) )
-mixer_map.add( Binding( Event('jb0',3),  'Undo',   Action['looper_undo'] ) )
-mixer_map.add( Binding( Event('jb0',4),  'Redo',   Action['looper_redo'] ) )
-mixer_map.add( Binding( Event('jb0',5), 'Un All', Action['looper_undo_all'] ) )
-
-mixer_map.add( Binding( Event('jb0',6), 'Lead', Action['mixer_cycle_gain'] ) )
-mixer_map.add( Binding( Event('jb0',7), 'Mute G', Action['mixer_mute_guitar'] ) )
-mixer_map.add( Binding( Event('jb0',8), 'Mute V', Action['mixer_mute_voice'] ) )
-mixer_map.add( Binding( Event('jb0',9), 'Mute', Action['mixer_mute_all'] ) )
-
-mixer_map.add( Binding( Event('jb0',13), 'Vol G', Action['mixer_guitar_level'] ) )
-mixer_map.add( Binding( Event('jb0',14), 'Vol V', Action['mixer_voice_level'] ) )
-
-mixer.set(1,0.0)
-mixer.set(2,0.0)
-mixer.assignController( ctl, 'Guitar', 1 )
-gain.set(1,0.0)
+monitor = Mixer.register(
+    viewmanager = main.viewmanager,
+    oscserver = main.oscserver,
+
+    context  = 'mix',
+    label    = 'Monitor',
+    x        = 50,
+    y        = 0,
+    dx       = 25,
+    dy       = 4,
+
+    channels = ( 'Guitar', 'Voice' ),
+    remote  = ('127.0.0.1', 9903),
+)
+
+tm = TimeMachine.register(
+    viewmanager = main.viewmanager,
+
+    context = 'tm',
+    name    = 'TimeMachine',
+    x       = 25,
+    y       =  7,
+    dx      = 25,
+    dy      =  3,
+
+    ports   = ('master:out_left', 'master:out_left'),
+    dir     = 'tm',
+    buffer  =  1)
+
+metronome = Metronome.register(
+    viewmanager = main.viewmanager,
+    dispatcher  = main.dispatcher,
+
+    context = 'mt',
+    label   = 'Metronome',
+    x       = 50,
+    y       = 7,
+    dx      = 25,
+    dy      = 3,
+)
+
+# Action.register( Mixer.AssignController  ( 'mixer_master_level', mixer, ctl, 'Master', 0 ) )
+Action.register( Mixer.AssignController  ( 'master_guitar_level', mixer, ctl, 'Mast Guit', 1 ) )
+Action.register( Mixer.AssignController  ( 'master_voice_level',  mixer, ctl, 'Mast Voc', 2 ) )
+Action.register( Mixer.ToggleMuteChannel ( 'mixer_mute_guitar',   mixer, 1 ) )
+Action.register( Mixer.ToggleMuteChannel ( 'mixer_mute_voice',    mixer, 2 ) )
+Action.register( Mixer.ToggleMuteAll     ( 'mixer_mute_all',      mixer ) )
+
+Action.register( Mixer.CycleVolume       ( 'mixer_cycle_gain',   gain, 1, ( 0.0, 2.5, 5.0 ) ) )
+
+Action.register( Mixer.AssignController  ( 'monitor_guitar_level', monitor, ctl, 'Mon Guit.', 1 ) )
+Action.register( Mixer.AssignController  ( 'monitor_voice_level',  monitor, ctl, 'Mon Voc', 2, -6, 12, [ 0, 6 ] ) )
+
+master_level_alt_map = Bindings.KeyMap()
+Action.register( Actions.ChangeBindingsRelative( 'set_master_level_alt_map', 1, [master_level_alt_map] ) )
+Action.register( Actions.Macro( 'master_set_guitar_level',
+                                [ 'master_guitar_level', 'set_master_level_alt_map' ] ) )
+Action.register( Actions.Macro( 'master_set_voice_level',
+                                [ 'master_voice_level', 'unset_this_map' ] ) )
+
+monitor_level_alt_map = Bindings.KeyMap()
+Action.register( Actions.ChangeBindingsRelative( 'set_monitor_level_alt_map', 1, [monitor_level_alt_map] ) )
+Action.register( Actions.Macro( 'monitor_set_voice_level',
+                                [ 'monitor_voice_level', 'set_monitor_level_alt_map' ] ) )
+Action.register( Actions.Macro( 'monitor_set_guitar_level',
+                                [ 'monitor_guitar_level', 'unset_this_map' ] ) )
+
+
+Action.register( TimeMachine.ToggleRecord( 'tm_rec_toggle', tm ) )
+
+mixer_map.add( Binding( Event('jb0',0),  'Rec',     Action['looper_record'] ) )
+mixer_map.add( Binding( Event('jb0',1),  'Over',    Action['looper_overdub'] ) )
+mixer_map.add( Binding( Event('jb0',2),  'Mult',    Action['looper_multiply'] ) )
+mixer_map.add( Binding( Event('jb0',3),  'Undo',    Action['looper_undo'] ) )
+mixer_map.add( Binding( Event('jb0',4),  'Redo',    Action['looper_redo'] ) )
+mixer_map.add( Binding( Event('jb0',5),  'Un All',  Action['looper_undo_all'] ) )
+
+mixer_map.add( Binding( Event('jb0',6), 'Lead',     Action['mixer_cycle_gain'] ) )
+#mixer_map.add( Binding( Event('jb0',7), 'Mute G',   Action['mixer_mute_guitar'] ) )
+#mixer_map.add( Binding( Event('jb0',8), 'Mute V',   Action['mixer_mute_voice'] ) )
+#mixer_map.add( Binding( Event('jb0',9), 'Mute',     Action['mixer_mute_all'] ) )
+mixer_map.add( Binding( Event('jb0',7), 'Mute',     Action['mixer_mute_all'] ) )
+mixer_map.add( Binding( Event('jb0',8), 'Ctl Up', Action['controller_increment'] ) )
+mixer_map.add( Binding( Event('jb0',9), 'Ctl Dn', Action['controller_decrement'] ) )
+
+mixer_map.add( Binding( Event('jb0',13), '(Mas G)', Action['master_set_guitar_level'] ) )
+master_level_alt_map.add( Binding( Event('jb0',13), '(Mas V)', Action['master_set_voice_level'] ) )
+
+mixer_map.add( Binding( Event('jb0',14), '(Mon V)', Action['monitor_set_voice_level'] ) )
+monitor_level_alt_map.add( Binding( Event('jb0',14), '(Mon G)', Action['monitor_set_guitar_level'] ) )
+
+mixer_map.add( Binding( Event('jb0',12), 'TM Rec',  Action['tm_rec_toggle'] ) )
+
+metronome_map = Bindings.KeyMap('Metronome')
+
+Action.register( Actions.ChangeBindingsRelative('set_metronome_map', 1, [metronome_map] ) )
+Action.register( Metronome.Toggle ( 'metronome_toggle', metronome ) )
+Action.register( Metronome.Tap ( 'metronome_tap', metronome ) )
+Action.register( Metronome.StepBPM ('metronome_bpm_inc', metronome, +5 ) )
+Action.register( Metronome.StepBPM ('metronome_bpm_dec', metronome, -5 ) )
+Action.register( Metronome.AssignVolumeController ( 'metronome_volume', metronome, ctl,
+                                                    "Metr Vol", 0.5, 9.9 ) )
+
+metronome_map.add( Binding( Event('jb0', 0), 'Tap', Action['metronome_tap'] ) )
+metronome_map.add( Binding( Event('jb0', 1), 'Toggle', Action['metronome_toggle'] ) )
+metronome_map.add( Binding( Event('jb0', 2), '(Vol)', Action['metronome_volume'] ) )
+metronome_map.add( Binding( Event('jb0', 3), 'bpm Dec', Action['metronome_bpm_dec'] ) )
+metronome_map.add( Binding( Event('jb0', 4), 'bpm Inc', Action['metronome_bpm_inc'] ) )
+
+metronome_map.add( Binding( Event('jb0', 11), '[Main]', Action['unset_this_map'] ) )
+
+mixer_map.add( Binding( Event('jb0', 11), '[Metr]', Action['set_metronome_map'] ) )
+
+mixer.mute(2)
+mixer.assignController( ctl, 'Mas Guit', 1 )
+monitor.set(2, 6)
     
 ###########################################################################
+# Jukebox
+
+player_map = Bindings.KeyMap('JukeBox')
+Action.register( Actions.ChangeBindingsRelative( 'mode_player', 0, [ player_map ] ) )
+
+player = AlsaPlayer.Player()
+
+Action.register( AlsaPlayer.Play  ( 'player_start',  player ) )
+Action.register( AlsaPlayer.Pause ( 'player_pause',  player ) )
+Action.register( AlsaPlayer.Stop  ( 'player_stop',   player ) )
+Action.register( AlsaPlayer.Skip  ( 'player_skip_fwd', player, 5 ) )
+Action.register( AlsaPlayer.Skip  ( 'player_skip_rev', player, -5 ) )
+
+player_stop_map = Bindings.KeyMap()
+
+Action.register( Actions.ChangeBindingsRelative('player_set_stop_map', 1, [player_stop_map] ) )
+Action.register( Actions.Macro( 'player_set_playing',
+                                [ 'player_start', 'player_set_stop_map' ] ) )
+Action.register( Actions.Macro( 'player_set_stop',
+                                [ 'player_stop', 'unset_this_map' ]) )
+
+player_looper_map = Bindings.KeyMap()
+
+Action.register( Actions.ChangeBindingsRelative('player_set_looper_map', 1, [player_looper_map] ) )
+Action.register( Actions.Macro( 'player_start_loop_rec',
+                                [ 'looper_record', 'player_set_looper_map' ] ) )
+Action.register( Actions.Macro( 'player_stop_loop_rec',
+                                [ 'looper_record', 'player_pause', 'unset_this_map' ] ) )
+Action.register( Actions.Macro( 'player_looper_cancel',
+                                [ 'looper_undo', 'unset_this_map' ] ) )
+Action.register( Actions.Macro( 'player_stop_loop',
+                                [ 'looper_undo_all', 'player_pause' ] ) )
+
+for i in range(5):
+    Action.register( AlsaPlayer.Jump  ( 'player_jump_%d' % i, player, i+1 ) )
+    Action.register( Actions.Macro( 'player_set_track_%d' % i,
+                                    [ 'player_jump_%d' % i, 'player_set_stop_map' ] ) )
+    player_map.add( Binding( Event('jb0',i+3), 'Tr %d' % (i+1), Action['player_set_track_%d' % i] ) )
+
+player_map.add( Binding( Event('jb0',8), 'Ctl Up', Action['controller_increment'] ) )
+player_map.add( Binding( Event('jb0',9), 'Ctl Dn', Action['controller_decrement'] ) )
+
+player_map.add( Binding( Event('jb0',  0), 'L Rec', Action['player_start_loop_rec'] ) )
+player_map.add( Binding( Event('jb0',  1), 'L Stp', Action['player_stop_loop'] ) )
+player_map.add( Binding( Event('jb0', 11), 'Back', Action['player_skip_rev'] ) )
+player_map.add( Binding( Event('jb0', 12), 'Fwd', Action['player_skip_fwd'] ) )
+player_map.add( Binding( Event('jb0', 13), 'Play', Action['player_set_playing'] ) )
+player_map.add( Binding( Event('jb0', 14), 'Pause', Action['player_pause'] ) )
+
+player_stop_map.add( Binding( Event('jb0', 13), 'Stop', Action['player_set_stop'] ) )
+
+player_looper_map.add( Binding( Event('jb0',  0), 'L Rec', Action['player_stop_loop_rec'] ) )
+player_looper_map.add( Binding( Event('jb0',  1), 'L Can', Action['player_looper_cancel'] ) )
+
+@action
+def player_queue_tm_recordings(binding):
+    global player
+    player.clear()
+    player.stop()
+    wavs = []
+    for f in os.listdir('tm'):
+        wav = os.path.splitext(f)[0] + '.wav'
+        if f.endswith('.w64'):
+            if not os.path.exists('tm/' + wav):
+                os.waitpid(subprocess.Popen(["sndfile-convert","-pcm16",f,wav],cwd='tm').pid,0)
+                wavs.append(wav)
+        elif f.endswith('.wav'):
+            wavs.append(f)
+    wavs.sort()
+    wavs.reverse()
+    for wav in wavs[:5]:
+        player.add('tm/' + wav)
+        player.stop()
+
+player_map.add( Binding( Event('jb0',  2), 'Add TM', Action['player_queue_tm_recordings'] ) )
+
+###########################################################################
 
-mixer_map.add( Binding( Event('jb0',10), '[Loop]', Action['mode_looper'] ) )
+mixer_map.add       ( Binding( Event('jb0',10), '[Loop]',  Action['mode_looper'] ) )
+looper_main_map.add ( Binding( Event('jb0',10), '[JBox]',  Action['mode_player'] ) )
+player_map.add      ( Binding( Event('jb0',10), '[Mastr]', Action['mode_mixer']  ) )
 
 main.keylist.append(global_map)
 main.keylist.append(mixer_map)