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