diff --git a/python_payload/control.py b/python_payload/control.py
new file mode 100644
index 0000000000000000000000000000000000000000..897f1bc03f9474eef6e5a8c3043b1c86b9394d4f
--- /dev/null
+++ b/python_payload/control.py
@@ -0,0 +1,46 @@
+import ui
+
+class ControlKnob():
+    def __init__(self,name,action=None,default=0.5):
+        #TODO inheritance from Control()
+        self.name=name
+        self.action=action
+        self.value = default
+        self.ui = ui.IconValue(label=self.name,size=60, value=self.value)
+    
+    def draw(self):
+        self.ui.draw()
+
+    def enter(self,data={}):
+        self.value = 0.8
+        self.ui.value = self.value
+        if self.action:
+            self.action(self.value)
+
+    def scroll(self,delta):
+        self.value = max(0,min(1,self.value+delta*0.05))
+        self.ui.value = self.value
+        print (self.value)
+        self.draw()
+        if self.action:
+            self.action(self.value)
+
+class ControlSwitch():
+    def __init__(self,name,action,default):
+        #TODO inheritance from Control()
+        self.name=name
+        self.action=action
+        self.value = default
+        self.ui = ui.IconValue(label=self.name,size=60, value=self.value)
+    
+    def draw(self):
+        self.ui.draw()
+
+    def enter(self):
+        self.value = not self.value
+        self.ui.value = self.value
+        if self.action:
+            self.action(self.value)
+
+    def scroll(self,delta):
+        pass
diff --git a/python_payload/demo_menu.py b/python_payload/demo_menu.py
index e3c5e62590b9199133db1efb23cda1e6156f9ac2..522c758f31ffad47382a7724f33c354f5e113643 100644
--- a/python_payload/demo_menu.py
+++ b/python_payload/demo_menu.py
@@ -1,8 +1,14 @@
 import menu
 import event
 import hardware
+import control
 
-import demo_worms,demo_sparabo
+import demo_worms,demo_sparabo,cap_touch_demo, melodic_demo, harmonic_demo
+import menu_settings,menu_tinysynth
+
+import time
+
+hardware.captouch_autocalib()
 
 def start_worms(action):
     menu.menu_stack.append(menu.active_menu)
@@ -14,6 +20,41 @@ def start_sparabo(action):
     menu.active_menu=None
     demo_sparabo.run()
 
+def start_captouch(action):
+    armed = False
+    while True:
+        cap_touch_demo.run()
+        time.sleep_ms(10)
+        if hardware.get_button(1) == 0:
+            armed = True
+        if armed and hardware.get_button(1) == 2:
+            break
+
+def start_melodic(action):
+    armed = False
+    melodic_demo.init()
+    hardware.set_global_volume_dB(20)
+    hardware.display_fill(0)
+    while True:
+        melodic_demo.run()
+        time.sleep_ms(10)
+        if hardware.get_button(1) == 0:
+            armed = True
+        if armed and hardware.get_button(1) == 2:
+            break
+
+def start_harmonic(action):
+    armed = False
+    harmonic_demo.init()
+    hardware.set_global_volume_dB(20)
+    hardware.display_fill(0)
+    while True:
+        harmonic_demo.run()
+        time.sleep_ms(10)
+        if hardware.get_button(1) == 0:
+            armed = True
+        if armed and hardware.get_button(1) == 2:
+            break
 menu_demo = menu.Menu("demo")
 item_worms = menu.MenuItem("worms")
 item_worms.action = start_worms
@@ -23,6 +64,13 @@ item_abo = menu.MenuItem("abo")
 item_abo.action = start_sparabo
 menu_demo.add(item_abo)
 
+item_cap = menu.MenuItem("captouch")
+item_cap.action = start_captouch
+menu_demo.add(item_cap)
+
+menu_demo.add(menu.MenuItem("melodic", action=start_melodic))
+menu_demo.add(menu.MenuItem("harmonic", action=start_harmonic))
+
 testmenu = menu.Menu("test")
 
 item_add = menu.MenuItem("+")
@@ -39,10 +87,10 @@ testmenu.add(item_add)
 menu_main = menu.Menu("main",has_back=False)
 menu_main.add(menu.MenuItemSubmenu(testmenu))
 menu_main.add(menu.MenuItemSubmenu(menu_demo))
-menu_main.add(menu.MenuItem("nix"))
+menu_main.add(menu.MenuItemSubmenu(menu_settings.get_menu()))
+menu_main.add(menu.MenuItemSubmenu(menu_tinysynth.get_menu()))
 
 menu.set_active_menu(menu_main)
 menu.render()
 
-
 event.the_engine.eventloop()    
diff --git a/python_payload/demo_sparabo.py b/python_payload/demo_sparabo.py
index 50b6d465821a491425b2df0aa793d44951b00107..4bbf4f1e76b93c902e971d677dd27eeba752b492 100644
--- a/python_payload/demo_sparabo.py
+++ b/python_payload/demo_sparabo.py
@@ -38,9 +38,15 @@ def on_step(data):
 	hardware.display_update()
 	
 def handle_input(data={}):
+    print("removed")
+    
+    
     sequencer.remove()
     ev.remove()
 
+    #TODO this is a bad hack!
+    event.the_engine.events_timed=[]
+    
 
 def init():
     ctx.text_align = ctx.CENTER
diff --git a/python_payload/menu.py b/python_payload/menu.py
index 4e44a2b7d7088a23808918ef0e97a6d5363fd0cf..e4ec935f5610b0fa0ba480b15e379e4e11e5966c 100644
--- a/python_payload/menu.py
+++ b/python_payload/menu.py
@@ -87,9 +87,9 @@ class Menu():
     
 
 class MenuItem():
-    def __init__(self,name="item"):
+    def __init__(self,name="item",action=None):
         self.name= name
-        self.action= None
+        self.action= action
         self.ui = ui.Icon(label=name)
 
     def __repr__(self):
@@ -118,16 +118,45 @@ class MenuItemBack(MenuItem):
     def enter(self,data={}):
         menu_back()
 
+class MenuItemControl(MenuItem):
+    def __init__(self,name,control):
+        super().__init__(name=name)
+        self.control=control
+        self.ui=control.ui
+
+    def enter(self):
+        print("menu enter")
+        self.control.enter()
+
+    def scroll(self,delta):
+        self.control.scroll(delta)
+
 def on_scroll(d):
     if active_menu is None:
         return
 
-    if active_menu.angle_step<0.5:
-        active_menu.angle_step+=0.025
-    if d["value"] == -1:
-        active_menu.rotate_steps(-1)
-    elif d["value"] == 1:
-        active_menu.rotate_steps(1)
+    if d["index"]==0:#right button
+        hovered=active_menu.get_hovered_item()
+        if hasattr(hovered, "scroll"):
+            hovered.scroll(d["value"])
+
+    else: #index=1, #left button
+        if active_menu.angle_step<0.5:
+            active_menu.angle_step+=0.025
+        if d["value"] == -1:
+            active_menu.rotate_steps(-1)
+        elif d["value"] == 1:
+            active_menu.rotate_steps(1)
+
+    render()
+
+def on_scroll_captouch(d):
+    if active_menu is None:
+        return
+    if abs(d["radius"]) < 10000:
+        return
+    print(d["angle"])
+    active_menu.rotate_to(d["angle"]+math.pi)
     render()
 
 def on_release(d):
@@ -145,17 +174,22 @@ def on_enter(d):
     else:
         active_menu.get_hovered_item().enter()
     
-event.Event(name="menu rotation",
+event.Event(name="menu rotation button",group_id="menu",
     condition=lambda e: e["type"] =="button" and not e["change"] and abs(e["value"])==1 ,
     action=on_scroll
 )
 
-event.Event(name="menu rotation release",
+event.Event(name="menu rotation captouch",group_id="menu",
+    condition=lambda e: e["type"] =="captouch" and not e["change"] and abs(e["value"])==1 and e["index"]==2,
+    action=on_scroll_captouch
+)
+
+event.Event(name="menu rotation button release",group_id="menu",
     condition=lambda e: e["type"] =="button" and e["change"] and e["value"] ==0,
     action=on_release
 )
 
-event.Event(name="menu enter",
+event.Event(name="menu button enter",group_id="menu",
     condition=lambda e: e["type"] =="button" and e["change"] and e["value"] == 2,
     action=on_enter
 )
@@ -166,7 +200,7 @@ def render():
         return
     hardware.get_ctx().rectangle(-120,-120,240,240).rgb(0,0,0).fill()
     active_menu.draw()
-    hardware.display_update()
+    #hardware.display_update()
 
 def set_active_menu(menu):
     global active_menu
diff --git a/python_payload/menu_settings.py b/python_payload/menu_settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..860c7e1a75b91a74ab3739ec3d285e47565e7614
--- /dev/null
+++ b/python_payload/menu_settings.py
@@ -0,0 +1,51 @@
+import menu
+import event
+import control
+import ui
+import hardware
+
+
+ui_input = ui.Icon("")
+
+def render_input_data(data):
+    ui_input.label = str(data["angle"])
+    print("xxx")
+    ui_input.draw()
+
+def set_controls_overlay(value):
+    print ("set_controls_overlay")
+    if value:
+        event_input_overlay = event.Event(
+            name="show input overlay", group_id="input-overlay",
+            #condition=lambda d: d['type'] in ["captouch","button"],
+            condition=lambda d: d['type'] in ["captouch"] and d['value']==1,
+            action=render_input_data
+        )
+    else:
+        print("REMOVE")
+        event.the_engine.remove("input-overlay")
+
+def set_volume(value):
+    db = int(value*60-40)
+    print("DB",db)
+    hardware.set_global_volume_dB(db)
+    
+
+def get_menu():
+    m = menu.Menu("settings")
+
+    control_debug_input=control.ControlSwitch(
+        name="show inputs",
+        action=set_controls_overlay,
+        default=False
+    )
+
+    item_input_overlay = menu.MenuItemControl("input overlay", control_debug_input)
+    m.add(item_input_overlay)
+
+    c = control.ControlKnob(name="Volume",default=0.5,action=set_volume)
+    m.add(menu.MenuItemControl("volume",c))
+
+    return m
+
+m = get_menu()
\ No newline at end of file
diff --git a/python_payload/menu_tinysynth.py b/python_payload/menu_tinysynth.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d012b44429cdb59b5235dd916f09114b7aab4b8
--- /dev/null
+++ b/python_payload/menu_tinysynth.py
@@ -0,0 +1,45 @@
+from synth import tinysynth
+
+import menu
+import event
+import control
+import ui
+import hardware
+
+
+ui_input = ui.Icon("")
+
+
+def set_play(value):
+    print ("set_controls_overlay")
+    if value:
+        synth.start()
+    else:
+        synth.stop()
+
+def set_volume(value):
+    db = int(value*60-40)
+    print("DB",db)
+    hardware.set_global_volume_dB(db)
+
+def set_frequency(value):
+    f = 440+value*440
+    synth.freq(f)
+    
+
+def get_menu():
+    m = menu.Menu("tinysynth")
+
+    freq=control.ControlKnob(name="freq",action=set_frequency,default=0.0)
+    m.add(menu.MenuItemControl("freq",freq))
+
+    vol = control.ControlKnob(name="vol",action=set_volume,default=0.0)
+    m.add(menu.MenuItemControl("volume",vol))
+
+    play = control.ControlSwitch(name="play",action=set_play,default=False)
+    m.add(menu.MenuItemControl("play",play))
+    return m
+
+synth = tinysynth(440,0)
+
+m = get_menu()
\ No newline at end of file
diff --git a/python_payload/ui.py b/python_payload/ui.py
index 48fb0eed34f2e8cc036e8be73a9ffef82c0ee226..c47d5baae43856a24e5c38b6498bc78d3e2567cc 100644
--- a/python_payload/ui.py
+++ b/python_payload/ui.py
@@ -2,6 +2,12 @@ import hardware
 import random
 import math
 import time
+from math import sin,cos,pi
+
+
+GO_GREEN = (63/255,255/255,33/53)
+PUSH_RED = (251/255,72/255,196/255)
+
 
 class UIElement():
     def __init__(self,origin=(0,0)):
@@ -17,7 +23,6 @@ class UIElement():
             child.draw(pos)
 
     def _draw(self,pos):
-        #print(pos)
         pass
 
     def add(self, child):
@@ -40,15 +45,14 @@ class Icon(UIElement):
         self.bg_b = random.random()
         self.fg = 0
         self.label=label
-        self.size = size
+        self.size=size
         self.has_highlight = False
         super().__init__()
 
     def _draw(self,pos):
         x = int(pos[0])
         y = int(pos[1])
-        width = 55
-        height = 40
+
         self.ctx.text_align = self.ctx.CENTER
         self.ctx.text_baseline = self.ctx.MIDDLE
 
@@ -59,12 +63,32 @@ class Icon(UIElement):
                 y-hs/2,
                 hs,hs,hs//2
             ).fill()
-        self.ctx.move_to(x,y-self.size/2).rgb(self.bg_r,self.bg_g,self.bg_b).round_rectangle(
-            x-self.size/2,
-            y-self.size/2,
-            self.size,self.size,self.size//2
-        ).fill()
+        self.ctx.move_to(x,y).rgb(self.bg_r,self.bg_g,self.bg_b).arc(x,y,self.size/2,-math.pi,math.pi,True).fill()
+        #self.ctx.move_to(x,y-self.size/2).rgb(self.bg_r,self.bg_g,self.bg_b).
+        #.round_rectangle(
+        #    x-self.size/2,
+        #    y-self.size/2,
+        #    self.size,self.size,self.size//2
+        #).fill()
         self.ctx.rgb(1,1,1).move_to(x,y).text(self.label)
+
+class IconValue(Icon):
+    def __init__(self, value=0, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.value = value
+    
+    def _draw(self,pos):
+        (x,y) = pos
+
+        if self.has_highlight:
+            self.ctx.move_to(x,y).rgb(*GO_GREEN).arc(x,y,self.size/2+5,-pi,pi,True).fill()
+
+        self.ctx.move_to(x,y).rgb(*PUSH_RED).arc(x,y,self.size/2,-pi,pi,True).fill()
+        self.ctx.move_to(x,y).rgb(*GO_GREEN).arc(x,y,self.size/2-5,2*pi*self.value,0,1).fill()
+        self.ctx.rgb(0,0,0).move_to(x,y).text(self.label)
+
+
+
 class GroupStackedVertical(UIElement):
     pass