diff options
| -rw-r--r-- | solo-tool-project/src/solo_tool/handlers.py | 8 | ||||
| -rw-r--r-- | web-project/src/solo_tool_web.py | 43 | 
2 files changed, 33 insertions, 18 deletions
| diff --git a/solo-tool-project/src/solo_tool/handlers.py b/solo-tool-project/src/solo_tool/handlers.py index ab7309e..0b38968 100644 --- a/solo-tool-project/src/solo_tool/handlers.py +++ b/solo-tool-project/src/solo_tool/handlers.py @@ -18,6 +18,14 @@ def changeSong(st: SoloTool, delta: int) -> Callable[[], None]:              st.song += delta      return f +def restartOrPreviousSong(st: SoloTool, threshold: float) -> Callable[[], None]: +    def f(): +        if st.position < threshold and st.song > 0: +            st.song -= 1 +        else: +            st.position = 0.0 +    return f +  def setSong(st: SoloTool, index: int, followUp: Callable[[], None]=None) -> Callable[[], None]:      def f():          st.song = index diff --git a/web-project/src/solo_tool_web.py b/web-project/src/solo_tool_web.py index 4ddb399..81b0357 100644 --- a/web-project/src/solo_tool_web.py +++ b/web-project/src/solo_tool_web.py @@ -5,9 +5,9 @@ from solo_tool.session_manager import loadSession  from solo_tool import handlers  from solo_tool.midi_controller_launchpad_mini import MidiController -st = loadSession("/home/eddy/music/solos/practice-new.json", "/home/eddy/music") +st = loadSession("/home/eddy/music/sessions/solos.json", "/home/eddy/music")  midiController = MidiController(st) -#midiController.connect() +midiController.connect()  def songName(path: str) -> str:      from os.path import basename, splitext @@ -24,7 +24,7 @@ def keyPointTables() -> None:      for i, song in enumerate(st.songs):          with ui.list().props('separator').bind_visibility_from(st, 'song', value=i):              for kp in st._keyPoints[i]: -                ui.item(f"{kp:0.2}", on_click=handlers.setKeyPoint(st, kp)).props('clickable v-ripple') +                ui.item(f"{kp:0.2}", on_click=handlers.setKeyPoint(st, kp)).props('clickable v-ripple').classes('text-lg')  st.registerKeyPointListCallback(lambda new: keyPointTables.refresh()) @@ -32,6 +32,7 @@ def main():      fullscreen = ui.fullscreen()      ui.dark_mode().enable()      ui.colors(secondary='#ffc107') +    #ui.run_javascript("rateSliderLabels = { 0: '0°C', 3: { label: '3°C' }, 5: '5°C', 6: '6°C' }")      # Header      with ui.header().classes('items-center'): @@ -45,7 +46,7 @@ def main():          ui.button(icon='add', on_click=addKeyPoint).props('flat round dense color=white')      # Song list -    with ui.left_drawer(bottom_corner=True).props('overlay') as song_drawer: +    with ui.left_drawer(bottom_corner=True).props('overlay breakpoint=8000') as song_drawer:          with ui.list().props('separator'):              for i, path in enumerate(st.songs):                  ui.item(songName(path), on_click=handlers.setSong(st, i, lambda: song_drawer.hide())).props('clickable v-ripple') @@ -53,26 +54,32 @@ def main():      # Playback position      ui.slider(min=0, max=1.0, step=0.001) \              .bind_value_from(st, 'position') \ +            .on('change', setPosition) \              .props('thumb-size=0px track-size=16px') \ -            .on('change', setPosition) +            .classes('q-pa-none')      # Key point position -    ui.slider(min=0, max=1.0, step=0.001).bind_value(st, 'keyPoint').props('color=secondary') +    ui.slider(min=0, max=1.0, step=0.001).bind_value(st, 'keyPoint').props('selection-color=transparent color=secondary').classes('q-py-none')      # Play control -    with ui.button_group().classes('w-full').style('height: 90px'): -        ui.button(icon='skip_previous', on_click=handlers.changeSong(st, -1)).style('flex: 1') -        ui.button(icon='start', on_click=handlers.seekAbsolute(st, 0.0), color='negative').style('flex: 1') -        ui.button(color='positive', on_click=handlers.playPause(st)).bind_icon_from(st, "playing", lambda playing: "pause" if playing else "play_arrow").style('flex: 2') -        ui.button(icon='undo', on_click=st.jump, color='secondary').style('flex: 2') -        ui.button(icon='skip_next', on_click=handlers.changeSong(st, 1)).style('flex: 1') - -    # Volume and rate +    with ui.button_group().classes('w-full').style('height: 80px'): +        buttonSize = "20px" +        ui.button(icon='skip_previous', on_click=handlers.restartOrPreviousSong(st, 0.01)).props(f"size={buttonSize}").style('flex: 1') +        ui.button(color='positive', on_click=handlers.playPause(st)).bind_icon_from(st, "playing", lambda playing: "pause" if playing else "play_arrow").props(f"size={buttonSize}").style('flex: 1') +        ui.button(icon='vertical_align_bottom', on_click=handlers.positionToKeyPoint(st), color='amber-5').props(f"size={buttonSize}").style('flex: 2') +        ui.button(icon='undo', on_click=st.jump, color='secondary').props(f"size={buttonSize}").style('flex: 2') +        ui.button(icon='skip_next', on_click=handlers.changeSong(st, 1)).props(f"size={buttonSize}").style('flex: 1') + +    # Playback rate      with ui.row().classes('w-full justify-between no-wrap items-center'): -        ui.button(icon='fast_rewind', on_click=handlers.rateRelative(st, -0.05)) -        ui.label().bind_text_from(st, 'rate', lambda rate: f'{rate:0.3}x').on('click', handlers.rateAbsolute(st, 1.0)).classes('text-lg') -        ui.button(icon='fast_forward', on_click=handlers.rateRelative(st, 0.05)) -        ui.slider(min=0, max=1.2, step=0.01).bind_value(st, 'volume') +        markerLabels = ",".join([f"{v}:'{v}x'" for v in [0.4, 0.6, 0.8, 1.0, 1.2]]) +        ui.slider(min=0.4, max=1.2, step=0.05).bind_value(st, 'rate').props(f'snap markers :marker-labels="{{{markerLabels}}}"').classes('q-px-md') + +    # Volume +    with ui.row().classes('w-full justify-between no-wrap items-center'): +        volumeLabels = ",".join([f"{v}:'{int(v*100)}%'" for v in [0.0, 0.25, 0.5, 0.75, 1.0, 1.25]]) +        ui.slider(min=0, max=1.25, step=0.01).bind_value(st, 'volume').props(f':marker-labels="{{{volumeLabels}}}"').classes('q-px-md') +          ui.button(icon='fullscreen', on_click=fullscreen.toggle).props('outline')      ui.run(binding_refresh_interval=0.5) | 
