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