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