aboutsummaryrefslogtreecommitdiffstats
path: root/web-project/src/solo_tool_web.py
blob: 1c039abacf23f19fbd4c7c12767560ddc028c7fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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: str) -> str:
    from os.path import basename, splitext
    return basename(splitext(path)[0])

@ui.refreshable
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')

st.registerKeyPointListCallback(lambda new: keyPointTables.refresh())

def addKeyPoint() -> None:
    st.keyPoints += [st.keyPoint]

def main():
    fullscreen = ui.fullscreen()
    ui.dark_mode().enable()
    ui.colors(secondary='#ffc107')

    # Header
    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')

    # Key points list
    with ui.right_drawer(top_corner=True, bottom_corner=True).props('width=120 behavior=desktop'):
        ui.label("Key Points").classes('text-lg')
        keyPointTables()
        ui.button(icon='add', on_click=addKeyPoint).props('flat round dense color=secondary')

    # Song list
    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='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.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()