plusdeck.jupyter

This library also includes some simple Jupyter widgets, under the plusdeck.jupyter namespace. These are ConfigEditor, for editing the CLI configuration file, and player, for spawning a simple player UI. To see these in action, check out the Player.ipynb file in the root of this project.

ConfigEditor

Bases: VBox

A widget for editing a Plus Deck 2C PC Cassette Deck config.

Source code in plusdeck/jupyter.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class ConfigEditor(widgets.VBox):
    """A widget for editing a Plus Deck 2C PC Cassette Deck config."""

    _config: Config
    _port_widget: widgets.SelectMultiple

    def __init__(self, config: Config):
        ports = [port.device for port in comports(include_links=True)]
        self._config = config
        self._port_widget = widgets.SelectMultiple(
            options=ports,
            value=(config.port,) if config.port in ports else ports[0:1],
            description="Serial Port",
            disabled=False,
        )
        super(ConfigEditor, self).__init__([self._port_widget])

    @property
    def value(self) -> Config:
        """The value of the current config."""

        self._config = replace(self._config, port=self._port_widget.value[0])
        return self._config

value property

The value of the current config.

player(client) async

Create a player widget for the Plus Deck 2C PC Cassette Deck.

Source code in plusdeck/jupyter.py
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
async def player(client: Client) -> widgets.HBox:
    """Create a player widget for the Plus Deck 2C PC Cassette Deck."""

    rcv = await client.subscribe()

    status = widgets.Label(
        value="Off",
        layout={"height": "60%"},
        style={"font_family": "monospace", "font_size": "24pt"},
    )

    async def display_state():
        async for state in rcv:
            status.value = STATES[state]

    asyncio.get_running_loop().create_task(display_state())

    pause = widgets.Button(
        value=False, description="⏸️", tooltip="Pause", layout={"width": "95%"}
    )

    @pause.on_click
    def on_pause(button):
        client.send(Command.PAUSE)

    play_a = widgets.Button(
        value=False, description="▶️", tooltip="Play Side A", layout={"width": "45%"}
    )

    @play_a.on_click
    def on_play_a(button):
        client.send(Command.PLAY_A)

    play_b = widgets.Button(
        value=False, description="◀️", tooltip="Play Side B", layout={"width": "45%"}
    )

    def on_play_b(button):
        client.send(Command.PLAY_B)

    play_b.on_click(on_play_b)

    stop = widgets.Button(
        value=False, description="⏹️", tooltip="Stop", layout={"width": "95%"}
    )

    @stop.on_click
    def on_stop(button):
        client.send(Command.STOP)

    eject = widgets.Button(value=False, description="⏏️", tooltip="Eject")

    @eject.on_click
    def on_eject(button):
        client.send(Command.EJECT)

    fast_forward = widgets.Button(value=False, description="⏩", tooltip="Fast-Forward")

    @fast_forward.on_click
    def on_fast_forward(button):
        client.send(Command.FAST_FORWARD_B)

    rewind = widgets.Button(value=False, description="⏪", tooltip="Rewind")

    @rewind.on_click
    def on_rewind(button):
        client.send(Command.FAST_FORWARD_A)

    power = widgets.Button(value=False, description="⏻", tooltip="Turn On/Off")

    @power.on_click
    def on_power(button):
        client.send(Command.UNSUBSCRIBE)

    return widgets.HBox(
        [
            widgets.VBox([pause, widgets.HBox([play_b, play_a]), stop]),
            widgets.VBox([status, widgets.HBox([eject, rewind, fast_forward, power])]),
        ]
    )