Music Control Demo#

Screen shot of music control demo
music_control_demo.py#
  1"""
  2If Python and Arcade are installed, this example can be run from the command line with:
  3python -m arcade.examples.music_control_demo
  4"""
  5from __future__ import annotations
  6
  7import arcade
  8import arcade.gui
  9import arcade.gui.widgets.buttons
 10import arcade.gui.widgets.layout
 11
 12
 13class MyView(arcade.View):
 14    def __init__(self, my_window: arcade.Window):
 15        super().__init__(my_window)
 16
 17        self.media_player = None
 18        self.paused = True
 19        self.songs = [":resources:music/funkyrobot.mp3",
 20                      ":resources:music/1918.mp3"]
 21        self.cur_song_index = 0
 22
 23        self.my_music = arcade.load_sound(self.songs[self.cur_song_index])
 24
 25        # This creates a "manager" for all our UI elements
 26        self.ui_manager = arcade.gui.UIManager(self.window)
 27
 28        box = arcade.gui.widgets.layout.UIBoxLayout(vertical=False, space_between=20)
 29
 30        # --- Start button
 31        normal_texture = arcade.load_texture(":resources:onscreen_controls/flat_dark/"
 32                                             "sound_off.png")
 33        hover_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/"
 34                                            "sound_off.png")
 35        press_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/"
 36                                            "sound_off.png")
 37
 38        # Create our button
 39        self.start_button = arcade.gui.widgets.buttons.UITextureButton(
 40            texture=normal_texture,
 41            texture_hovered=hover_texture,
 42            texture_pressed=press_texture,
 43        )
 44
 45        # Map that button's on_click method to this view's on_button_click method.
 46        self.start_button.on_click = self.start_button_clicked  # type: ignore
 47
 48        # Add in our element.
 49        box.add(self.start_button)
 50
 51        # --- Down button
 52        press_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/down.png")
 53        normal_texture = arcade.load_texture(":resources:onscreen_controls/flat_dark/down.png")
 54        hover_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/down.png")
 55
 56        # Create our button
 57        self.down_button = arcade.gui.widgets.buttons.UITextureButton(
 58            texture=normal_texture,
 59            texture_hovered=hover_texture,
 60            texture_pressed=press_texture,
 61        )
 62
 63        # Map that button's on_click method to this view's on_button_click method.
 64        self.down_button.on_click = self.volume_down  # type: ignore
 65        self.down_button.scale(0.5)
 66
 67        # Add in our element.
 68        box.add(self.down_button)
 69
 70        # --- Up button
 71        press_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/up.png")
 72        normal_texture = arcade.load_texture(":resources:onscreen_controls/flat_dark/up.png")
 73        hover_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/up.png")
 74
 75        # Create our button
 76        self.up_button = arcade.gui.widgets.buttons.UITextureButton(
 77            texture=normal_texture,
 78            texture_hovered=hover_texture,
 79            texture_pressed=press_texture,
 80        )
 81
 82        # Map that button's on_click method to this view's on_button_click method.
 83        self.up_button.on_click = self.volume_up  # type: ignore
 84        self.up_button.scale(0.5)
 85
 86        # Add in our element.
 87        box.add(self.up_button)
 88
 89        # --- Right button
 90        press_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/right.png")
 91        normal_texture = arcade.load_texture(":resources:onscreen_controls/flat_dark/right.png")
 92        hover_texture = arcade.load_texture(":resources:onscreen_controls/shaded_dark/right.png")
 93
 94        # Create our button
 95        self.right_button = arcade.gui.widgets.buttons.UITextureButton(
 96            texture=normal_texture,
 97            texture_hovered=hover_texture,
 98            texture_pressed=press_texture,
 99        )
100
101        # Map that button's on_click method to this view's on_button_click method.
102        self.right_button.on_click = self.forward  # type: ignore
103        self.right_button.scale(0.5)
104
105        # Add in our element.
106        box.add(self.right_button)
107
108        # Place buttons in the center of the screen using an UIAnchorWidget with default values
109        self.ui_manager.add(arcade.gui.widgets.layout.UIAnchorLayout(children=[box]))
110
111    def music_over(self):
112        self.media_player.pop_handlers()
113        self.media_player = None
114        self.sound_button_off()
115        self.cur_song_index += 1
116        if self.cur_song_index >= len(self.songs):
117            self.cur_song_index = 0
118        self.my_music = arcade.load_sound(self.songs[self.cur_song_index])
119        self.media_player = self.my_music.play()
120        self.media_player.push_handlers(on_eos=self.music_over)
121
122    def volume_down(self, *_):
123        if self.media_player and self.media_player.volume > 0.2:
124            self.media_player.volume -= 0.2
125
126    def volume_up(self, *_):
127        if self.media_player and self.media_player.volume < 1.0:
128            self.media_player.volume += 0.2
129
130    def forward(self, *_):
131        skip_time = 10
132
133        if self.media_player and self.media_player.time < self.my_music.get_length() - skip_time:
134            self.media_player.seek(self.media_player.time + 10)
135
136    def sound_button_on(self):
137        self.start_button.texture_pressed = \
138            arcade.load_texture(":resources:onscreen_controls/shaded_dark/sound_on.png")
139        self.start_button.texture = \
140            arcade.load_texture(":resources:onscreen_controls/flat_dark/sound_on.png")
141        self.start_button.texture_hovered = \
142            arcade.load_texture(":resources:onscreen_controls/shaded_dark/sound_on.png")
143
144    def sound_button_off(self):
145        self.start_button.texture_pressed = \
146            arcade.load_texture(":resources:onscreen_controls/shaded_dark/sound_off.png")
147        self.start_button.texture = \
148            arcade.load_texture(":resources:onscreen_controls/flat_dark/sound_off.png")
149        self.start_button.texture_hovered = \
150            arcade.load_texture(":resources:onscreen_controls/shaded_dark/sound_off.png")
151
152    def start_button_clicked(self, *_):
153        self.paused = False
154        if not self.media_player:
155            # Play button has been hit, and we need to start playing from the beginning.
156            self.media_player = self.my_music.play()
157            self.media_player.push_handlers(on_eos=self.music_over)
158            self.sound_button_on()
159        elif not self.media_player.playing:
160            # Play button hit, and we need to un-pause our playing.
161            self.media_player.play()
162            self.sound_button_on()
163        elif self.media_player.playing:
164            # We are playing music, so pause.
165            self.media_player.pause()
166            self.sound_button_off()
167
168    def on_draw(self):
169        self.clear()
170
171        # This draws our UI elements
172        self.ui_manager.draw()
173        arcade.draw_text("Music Demo",
174                         start_x=0, start_y=self.window.height - 55,
175                         width=self.window.width,
176                         font_size=40,
177                         align="center",
178                         color=arcade.color.BLACK)
179
180        if self.media_player:
181            seconds = self.media_player.time
182            minutes = int(seconds // 60)
183            seconds = int(seconds % 60)
184            arcade.draw_text(f"Time: {minutes}:{seconds:02}",
185                             start_x=10, start_y=10, color=arcade.color.BLACK, font_size=24)
186            volume = self.media_player.volume
187            arcade.draw_text(f"Volume: {volume:3.1f}",
188                             start_x=10, start_y=50, color=arcade.color.BLACK, font_size=24)
189
190    def on_show_view(self):
191        self.window.background_color = arcade.color.ALMOND
192
193        # Registers handlers for GUI button clicks, etc.
194        # We don't really use them in this example.
195        self.ui_manager.enable()
196
197    def on_hide_view(self):
198        # This unregisters the manager's UI handlers,
199        # Handlers respond to GUI button clicks, etc.
200        self.ui_manager.disable()
201
202
203if __name__ == "__main__":
204    window = arcade.Window(title="Arcade Music Control Demo")
205    window.show_view(MyView(window))
206    arcade.run()