Sound Demo#

Screen shot of using sound demo
sound_demo.py#
  1"""
  2Sound Panning Demo
  3
  4If Python and Arcade are installed, this example can be run from the
  5command line with:
  6python -m arcade.examples.sound_demo
  7
  8Each button plays a sound when clicked.
  9
 10The top left button plays a streaming music track when pressed. If you
 11click it while it's already playing, it will intentionally crash the
 12demo to demonstrate how you shouldn't try to play a streaming sound
 13that's already playing.
 14
 15The lower 3 rows of buttons play a non-streaming (static) sound with
 16different panning and volume. Going from left to right changes the
 17panning, which is how much the sound plays in the left speaker vs the
 18right speaker. Lower rows play the sound louder than the higher ones.
 19"""
 20
 21from __future__ import annotations
 22
 23import typing
 24
 25import arcade
 26
 27SCREEN_WIDTH = 800
 28SCREEN_HEIGHT = 600
 29SCREEN_TITLE = "Sound Panning Demo"
 30BUTTON_SIZE = 30
 31
 32
 33SOUND_PANNING = [-1.0, -0.5, 0.0, 0.5, 1.0]
 34BUTTON_X_POSITIONS = [
 35    BUTTON_SIZE,
 36    SCREEN_WIDTH / 4,
 37    SCREEN_WIDTH / 2,
 38    SCREEN_WIDTH / 4 * 3,
 39    SCREEN_WIDTH - BUTTON_SIZE,
 40]
 41
 42
 43VOLUME_VARIATION = [0.1, 0.5, 1]
 44Y_OFFSETS = [50, 0, -50]
 45
 46
 47class SoundButton(arcade.SpriteSolidColor):
 48    """
 49    A sprite that stores settings about how to play a sound.
 50
 51    This class can load a sound as either a static sound or a streaming
 52    sound. Streaming should be used for long files that will only have
 53    one instance playing, such as music or ambiance tracks.
 54
 55    If you try to play a sound created with streaming=True while it is
 56    already playing, it will raise an exception! Non-streaming (static)
 57    sounds are fine with it, and can have play() called on them as many
 58    times as you want.
 59    """
 60
 61    def __init__(
 62        self,
 63        sound_file,
 64        pan=0.5,
 65        volume=0.5,
 66        center_x=0,
 67        center_y=0,
 68        streaming=False
 69    ):
 70        super().__init__(BUTTON_SIZE, BUTTON_SIZE, color=arcade.color.WHITE)
 71        self.sound = arcade.Sound(sound_file, streaming=streaming)
 72        self.pan = pan
 73        self.volume = volume
 74        self.center_x = center_x
 75        self.center_y = center_y
 76
 77    def play(self):
 78        self.sound.play(pan=self.pan, volume=self.volume)
 79
 80
 81class MyGame(arcade.Window):
 82    def __init__(self, width, height, title):
 83        super().__init__(width, height, title)
 84        self.background_color = arcade.color.AMAZON
 85        self.button_sprites = None
 86
 87    def setup(self):
 88        self.button_sprites = arcade.SpriteList()
 89
 90        # create the streaming button at the top left
 91        self.button_sprites.append(
 92            SoundButton(
 93                ":resources:music/funkyrobot.mp3",
 94                pan=-1.0,
 95                volume=0.1,
 96                center_x=BUTTON_SIZE,
 97                center_y=SCREEN_HEIGHT / 2 + 150,
 98                streaming=True
 99            )
100        )
101
102        # Position the grid of buttons
103        # The zip function takes pieces from iterables and returns them
104        # as tuples. For more information, see the python doc:
105        # https://docs.python.org/3/library/functions.html#zip
106        for vol, y_offset in zip(VOLUME_VARIATION, Y_OFFSETS):
107            for pan_setting, x_pos in zip(SOUND_PANNING, BUTTON_X_POSITIONS):
108                self.button_sprites.append(
109                    SoundButton(
110                        ":resources:sounds/upgrade4.wav",
111                        pan_setting,
112                        vol,
113                        x_pos,
114                        SCREEN_HEIGHT / 2 + y_offset,
115                    )
116                )
117
118    def on_draw(self):
119        self.clear()
120        self.button_sprites.draw()
121
122    def on_update(self, delta_time):
123        self.button_sprites.update()
124
125    def on_mouse_press(self, x, y, button, key_modifiers):
126        hit_sprites = arcade.get_sprites_at_point((x, y), self.button_sprites)
127        for sprite in hit_sprites:
128            button_sprite = typing.cast(SoundButton, sprite)
129            if button == arcade.MOUSE_BUTTON_LEFT:
130                button_sprite.play()
131
132
133def main():
134    game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
135    game.setup()
136    arcade.run()
137
138
139if __name__ == "__main__":
140    main()