Source code for SimpleGUICS2Pygame.simpleguics2pygame.sound

# -*- coding: latin-1 -*-

"""
simpleguics2pygame module: simpleguics2pygame/sound.

Class Sound.

Piece of SimpleGUICS2Pygame.
https://bitbucket.org/OPiMedia/simpleguics2pygame

:license: GPLv3 --- Copyright (C) 2015-2016, 2020 Olivier Pirson
:author: Olivier Pirson --- http://www.opimedia.be/
:version: November 29, 2020
"""

from __future__ import print_function

# print('IMPORT', __name__)


__all__ = ('_LocalSound', 'Sound',
           'create_sound', 'load_sound',
           '_load_local_sound')


try:
    from typing import Optional, Sequence, Union
except ImportError:
    pass

import pygame

from SimpleGUICS2Pygame.simpleguics2pygame._arguments import _CONFIG  # pylint: disable=no-name-in-module  # noqa

from SimpleGUICS2Pygame.simpleguics2pygame._media import _load_local_media, _load_media  # pylint: disable=no-name-in-module  # noqa


#
# "Private" function
####################
[docs]def _load_local_sound(filename): # type: (str) -> '_LocalSound' """ Create and return a sound by loading a file from `filename`. Not founded file and errors are ignored. I recommend to use only Internet resources with the `load_sound()` function. Then you can use your program **both** in standard Python and in CodeSkulptor. (See `Tips.html#download-medias`_ .) .. _`Tips.html#download-medias`: ../Tips.html#download-medias But if it is necessary, you can load local sound with this "private" function. Supported formats are the same as the `load_sound()` function. **(Not available in SimpleGUI of CodeSkulptor.)** :param filename: str (**only a valid filename**, not URL) :return: _LocalSound """ assert isinstance(filename, str), type(filename) return _LocalSound(filename)
# # Class #######
[docs]class Sound: """Sound similar to SimpleGUI `Sound` of CodeSkulptor.""" _dir_search_first = '_snd/' """ `load_sound()` try **first** to loading sound from this directory, and next if failed, try to loading from URL. This local directory is relative to the directory of your program. """ _load_disabled = _CONFIG['--no-load-sound'] """ If `True` then load sounds are disabled. """
[docs] def __init__(self, url): # type: (str) -> None """ Set a sound (if not Sound._load_disabled). **Don't use directly**, use `load_sound()`. :param url: str """ assert isinstance(url, str), type(url) self._pygame_channel = None # type: Optional[pygame.mixer.Channel] self._pygame_sound = None # type: Optional[pygame.mixer.Sound] if not Sound._load_disabled and (url != ''): self._pygame_sound = _load_media('Sound', url, # type: ignore Sound._dir_search_first)
[docs] def __repr__(self): # type: () -> str """ Return `'<Sound object>'`. :return: str """ return '<Sound object>'
[docs] def _get_length(self): # type: () -> Union[int, float] """ Return the length of this sound in seconds. (If initialization of this sound was failed then return `0`.) **(Not available in SimpleGUI of CodeSkulptor.)** :return: int or float """ return (self._pygame_sound.get_length() if (self._pygame_sound is not None) else 0)
[docs] def pause(self): # type: () -> None """ Pause this sound. (Use `Sound.play()` to resume.) """ if ((self._pygame_channel is not None) and (self._pygame_channel.get_sound() == self._pygame_sound)): self._pygame_channel.pause()
[docs] def play(self): # type: () -> None """ If this sound is paused then resume the sound, else start the sound. """ if self._pygame_channel is not None: assert self._pygame_sound is not None if self._pygame_channel.get_sound() == self._pygame_sound: self._pygame_channel.unpause() else: self._pygame_channel = self._pygame_sound.play() elif self._pygame_sound is not None: self._pygame_channel = self._pygame_sound.play()
[docs] def rewind(self): # type: () -> None """ If this sound has already been started then stop the sound and rewind to the begining. """ if ((self._pygame_channel is not None) and (self._pygame_channel.get_sound() == self._pygame_sound)): self._pygame_sound.stop()
[docs] def set_volume(self, volume): # type: (Union[int, float]) -> None """ Change the volume of this sound. The default volume is `1` (maximum). :param volume: 0 <= int or float <= 1 """ assert isinstance(volume, (int, float)), type(volume) assert 0 <= volume <= 1, volume if self._pygame_sound is not None: self._pygame_sound.set_volume(volume)
# # "Private" class #################
[docs]class _LocalSound(Sound): """ Child of Sound to load local file sound. **(Not available in SimpleGUI of CodeSkulptor.)** """
[docs] def __init__(self, filename): # pylint: disable=super-init-not-called # type: (str) -> None """ Set a sound (if not Sound._load_disabled). **Don't use directly**, use `_local_load_sound()`. :param filename: str """ assert isinstance(filename, str), type(filename) self._pygame_channel = None self._pygame_sound = None # type: Optional[pygame.mixer.Sound] if not Sound._load_disabled and (filename != ''): self._pygame_sound = _load_local_media('Sound', filename) # type: ignore # noqa
[docs] def __repr__(self): # type: () -> str """ Return `'<_LocalSound object>'`. :return: str """ return '<_LocalSound object>'
# # SimpleGUI functions #####################
[docs]def create_sound(sound_data, sample_rate=8000, num_channels=1): # type: (Sequence[int], int, int) -> Sound """ NOT YET IMPLEMENTED! (Return an empty `Sound`.) (Available in SimpleGUI of CodeSkulptor but *not in CodeSkulptor documentation*!) :param sound_data: (tuple or list) of (0 <= int < 256) :param sample_rate: int >= 0 :param num_channels: int >= 0 :return: Sound """ assert isinstance(sound_data, (tuple, list)), type(sound_data) if __debug__: for data in sound_data: assert isinstance(data, int), type(data) assert 0 <= data < 256, data assert isinstance(sample_rate, int), type(sample_rate) assert sample_rate >= 0, sample_rate assert isinstance(num_channels, int), type(num_channels) assert num_channels >= 0, num_channels return Sound('')
[docs]def load_sound(url): # type: (str) -> Sound """ Create and return a sound by loading a file from `url`. Not founded URL and errors are ignored. SimpleGUICS2Pygame try **first** to loading sound from `Sound._dir_search_first` local directory (`_snd/` by default), and next if failed, try to loading from `url`. This local directory is relative to the directory of your program. For example, ``load_sound('http://commondatastorage.googleapis.com/codeskulptor-assets/jump.ogg')`` try first to loading from ``_snd/commondatastorage.googleapis.com/codeskulptor_assets/jump.ogg``. Supported formats: OGG, WAV and MP3. If MP3 sound failed on your system read `installation of audioread`_. .. _`installation of audioread`: ../index.html#package-audioread-required (Supported formats by CodeSkulptor are browser dependant.) (The sound can be started by `Sound.play()`.) :param url: str (**only a valid URL**, not local filename) :return: Sound """ assert isinstance(url, str), type(url) return Sound(url)