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