from nicegui import ui from solo_tool import SoloTool 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/funk-band/practice.json") midiController = MidiController(st) #midiController.connect() def songName(path): from os.path import basename, splitext return basename(splitext(path)[0]) def main(): fullscreen = ui.fullscreen() ui.dark_mode().enable() ui.colors(secondary='#ffc107') with ui.header().classes('items-center'): ui.button(icon='menu', on_click=lambda: song_drawer.toggle()).props('flat round dense color=white') ui.label().bind_text_from(st, 'song', lambda index: songName(st.songs[index]) if index is not None else "Select a song").classes('text-lg') with ui.right_drawer(top_corner=True, bottom_corner=True).props('width=120 behavior=desktop'): ui.label("Key Points").classes('text-lg') 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') with ui.left_drawer(bottom_corner=True).props('overlay') 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') # Playback position ui.slider(min=0, max=1.0, step=0.01).bind_value(st, 'position').props('thumb-size=0px track-size=16px') # Key point position ui.slider(min=0, max=1.0, step=0.01).bind_value(st, 'keyPoint').props('color=secondary') # 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='stop', on_click=st.stop, 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.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') ui.button(icon='fullscreen', on_click=fullscreen.toggle).props('outline') ui.run() if __name__ in {'__main__', '__mp_main__'}: main()