1
- """
2
- Sound Library.
3
- """
1
+ """Sound Library."""
4
2
5
3
from __future__ import annotations
6
4
29
27
30
28
31
29
class Sound :
32
- """This class represents a sound you can play."""
30
+ """Holds :ref:`playable <sound-basics-playing>` loaded audio data.
31
+
32
+ .. important:: :ref:`Streaming <sound-loading-modes>` disables features!
33
+
34
+ When ``streaming=True``, :py:meth:`.play` and :py:func:`play_sound`:
35
+
36
+ * raise a :py:class:`RuntimeError` if there is already another
37
+ active playback
38
+ * do not support looping
39
+
40
+ To learn about the restrictions on :ref:`streaming <sound-loading-modes>`,
41
+ please see:
42
+
43
+ * :ref:`sound-loading-modes-streaming`
44
+ * The py:class:`pyglet.media.codes.base.StreamingSource` class used
45
+ internally
46
+
47
+ To learn about cross-platform loading and file format concerns,
48
+ please see:
49
+
50
+ * Arcade's sound documentation:
51
+
52
+ * :ref:`sound-loading-modes`
53
+ * :ref:`sound-compat-easy`
54
+ * :ref:`sound-compat-loading`
55
+
56
+ * The pyglet guide to :external+pyglet:ref:`guide-media`
57
+
58
+ Args:
59
+ file_name:
60
+ The path of a file to load, optionally prefixed with a
61
+ :ref:`resource handle <resource_handles>`.
62
+ streaming:
63
+ If ``True``, attempt to load data from ``file_path`` via
64
+ via :ref:`streaming <sound-loading-modes>`.
65
+ """
33
66
34
67
def __init__ (self , file_name : str | Path , streaming : bool = False ):
35
68
self .file_name : str = ""
@@ -57,13 +90,26 @@ def play(
57
90
loop : bool = False ,
58
91
speed : float = 1.0 ,
59
92
) -> media .Player :
60
- """
61
- Play the sound.
93
+ """Try to play this :py:class:`Sound` and return a :py:class:`~pyglet.media.player.Player`.
62
94
63
- :param volume: Volume, from 0=quiet to 1=loud
64
- :param pan: Pan, from -1=left to 0=centered to 1=right
65
- :param loop: Loop, false to play once, true to loop continuously
66
- :param speed: Change the speed of the sound which also changes pitch, default 1.0
95
+ .. important:: Any :py:class:`Sound` with ``streaming=True`` loses features!
96
+
97
+ ``loop`` will not work and simultaneous playbacks raise
98
+ a :py:class:`RuntimeError`.
99
+
100
+ See the following to learn more about the keywords and restrictions:
101
+
102
+ * :py:class:`Sound`
103
+ * :ref:`sound-advanced-playback-change-aspects-ongoing`
104
+ * :ref:`sound-advanced-playback-change-aspects-new`
105
+
106
+ Args:
107
+ volume: Volume (``0.0`` is silent, ``1.0`` is loudest).
108
+ pan: Left / right channel balance (``-1`` is left, ``0.0`` is
109
+ center, and ``1.0`` is right).
110
+ loop: ``True`` attempts to restart playback after finishing.
111
+ speed: Change the speed (and pitch) of the sound. Default speed is
112
+ ``1.0``.
67
113
"""
68
114
if isinstance (self .source , media .StreamingSource ) and self .source .is_player_source :
69
115
raise RuntimeError (
@@ -105,72 +151,93 @@ def _on_player_eos():
105
151
return player
106
152
107
153
def stop (self , player : media .Player ) -> None :
108
- """
109
- Stop a currently playing sound.
154
+ """Permanently stop and :py:meth:`~pyglet.media.player.Player.delete` ``player``.
155
+
156
+ All references in the :py:class:`pyglet.media.Source` player table
157
+ will be deleted.
158
+
159
+ Args:
160
+ player: A pyglet :py:class:`~pyglet.media.player.Player`
161
+ returned from :func:`play_sound` or :py:meth:`Sound.play`.
110
162
"""
111
163
player .pause ()
112
164
player .delete ()
113
165
if player in media .Source ._players :
114
166
media .Source ._players .remove (player )
115
167
116
168
def get_length (self ) -> float :
117
- """Get length of audio in seconds"""
169
+ """Get length of the loaded audio in seconds"""
118
170
# We validate that duration is known when loading the source
119
171
return self .source .duration # type: ignore
120
172
121
173
def is_complete (self , player : media .Player ) -> bool :
122
- """Return true if the sound is done playing."""
174
+ """``True`` if the sound is done playing."""
123
175
# We validate that duration is known when loading the source
124
176
return player .time >= self .source .duration # type: ignore
125
177
126
178
def is_playing (self , player : media .Player ) -> bool :
127
- """
128
- Return if the sound is currently playing or not
179
+ """``True`` if ``player`` is currently playing, otherwise ``False``.
129
180
130
- :param player: Player returned from :func:`play_sound`.
131
- :returns: A boolean, ``True`` if the sound is playing.
181
+ Args:
182
+ player: A pyglet :py:class:`~pyglet.media.player.Player`
183
+ returned from :py:meth:`Sound.play <.Sound.play>` or
184
+ :func:`play_sound`.
132
185
186
+ Returns:
187
+ ``True`` if the passed pyglet player is playing.
133
188
"""
134
189
return player .playing
135
190
136
191
def get_volume (self , player : media .Player ) -> float :
137
- """
138
- Get the current volume.
139
-
140
- :param player: Player returned from :func:`play_sound`.
141
- :returns: A float, 0 for volume off, 1 for full volume.
192
+ """Get the current volume.
193
+
194
+ Args:
195
+ player: A pyglet :py:class:`~pyglet.media.player.Player`
196
+ returned from :py:meth:`Sound.play <.Sound.play>` or
197
+ :func:`play_sound`.
198
+ Returns:
199
+ A volume between ``0.0`` (silent) and ``1.0`` (full volume).
142
200
"""
143
201
return player .volume # type: ignore # pending https://github.com/pyglet/pyglet/issues/847
144
202
145
- def set_volume (self , volume , player : media .Player ) -> None :
146
- """
147
- Set the volume of a sound as it is playing.
203
+ def set_volume (self , volume : float , player : media .Player ) -> None :
204
+ """Set the volume of a sound as it is playing.
148
205
149
- :param volume: Floating point volume. 0 is silent, 1 is full.
150
- :param player: Player returned from :func:`play_sound`.
206
+ Args:
207
+ volume: Floating point volume. 0 is silent, 1 is full.
208
+ player: A pyglet :py:class:`~pyglet.media.player.Player`
209
+ returned from :func:`play_sound` or :py:meth:`Sound.play`.
151
210
"""
152
211
player .volume = volume
153
212
154
213
def get_stream_position (self , player : media .Player ) -> float :
155
- """
156
- Return where we are in the stream. This will reset back to
214
+ """Return where we are in the stream. This will reset back to
157
215
zero when it is done playing.
158
216
159
- :param player: Player returned from :func:`play_sound`.
160
-
217
+ Args:
218
+ player: Player returned from :func:`play_sound`.
161
219
"""
162
220
return player .time
163
221
164
222
165
223
def load_sound (path : str | Path , streaming : bool = False ) -> Sound :
166
- """
167
- Load a sound.
224
+ """Load a file as a :py:class:`Sound` data object.
225
+
226
+ .. important:: Using ``streaming=True`` disables certain features!
168
227
169
- :param path: Name of the sound file to load.
170
- :param streaming: Boolean for determining if we stream the sound
171
- or load it all into memory. Set to ``True`` for long sounds to save
172
- memory, ``False`` for short sounds to speed playback.
173
- :returns: Sound object which can be used by the :func:`play_sound` function.
228
+ These include looping and multiple playbacks. Please
229
+ see :py:class:`Sound` to learn more.
230
+
231
+ Args:
232
+ path: a path which may be prefixed with a
233
+ :ref:`resource_handle <resource_handles>`.
234
+ streaming: Boolean for determining if we stream the sound or
235
+ load it all into memory. Set to ``True`` for long sounds to
236
+ save memory, ``False`` for short sounds to speed playback.
237
+
238
+ Returns:
239
+ A :ref:playable <sound-basics-playing>` instance of a
240
+ :py:class:`Sound` object.
174
241
"""
175
242
# Initialize the audio driver if it hasn't been already.
176
243
# This call is to avoid audio driver initialization
@@ -188,20 +255,69 @@ def load_sound(path: str | Path, streaming: bool = False) -> Sound:
188
255
189
256
190
257
def play_sound (
191
- sound : Sound ,
258
+ sound : Sound | None ,
192
259
volume : float = 1.0 ,
193
260
pan : float = 0.0 ,
194
261
loop : bool = False ,
195
262
speed : float = 1.0 ,
196
263
) -> media .Player | None :
197
- """
198
- Play a sound.
264
+ """Try to play the ``sound`` and return a :py:class:`~pyglet.media.player.Player`.
265
+
266
+ .. note:: The ``sound`` **must** be a :py:class:`Sound` object!
267
+
268
+ See the following to load audio from file paths:
269
+
270
+ * :ref:`sound-basics-loading`
271
+ * :ref:`sound-loading-modes`
272
+ * :py:func:`load_sound`
273
+ * :py:class:`Sound`
274
+
275
+ The output and return value depend on whether playback succeeded:
276
+
277
+ .. list-table::
278
+ :header-rows: 1
279
+
280
+ * - Success?
281
+ - Console output
282
+ - Return value
283
+
284
+ * - No / ``sound`` is ``None``
285
+ - Log a warning
286
+ - ``None``
287
+
288
+ * - Yes
289
+ - N/A
290
+ - A pyglet :py:class:`~pyglet.media.player.Player`
291
+
292
+ See the following to learn more:
293
+
294
+ * :ref:`sound-basics-sound_vs_player`
295
+ * :ref:`sound-advanced-playback`
296
+
297
+ .. important:: Any :py:class:`Sound` with ``streaming=True`` loses features!
298
+
299
+ ``loop`` will not work and simultaneous playbacks raise
300
+ a :py:class:`RuntimeError`.
301
+
302
+ To learn more about the ``streaming`` keyword and restrictions, please see:
303
+
304
+ * :py:class:`Sound`
305
+ * :ref:`sound-advanced-playback-change-aspects-ongoing`
306
+ * :ref:`sound-advanced-playback-change-aspects-new`
307
+
308
+ Args:
309
+ sound: A :py:class:`Sound` instance or ``None``.
310
+ volume: From ``0.0`` (silent) to ``1.0`` (max volume).
311
+ pan: The left / right ear balance (``-1`` is left, ``0`` is center,
312
+ and ``1`` is right)
313
+ loop: ``True`` makes playback restart each time it reaches the end.
314
+ speed: How fast to play. Slower than ``1.0`` deepens sound while
315
+ values higher than ``1.0`` raise the pitch.
316
+
317
+ Returns:
318
+ A :py:class:`pyglet.media.Player` instance for the playback or
319
+ ``None`` if playback failed.
199
320
200
- :param sound: Sound loaded by :func:`load_sound`. Do NOT use a string here for the filename.
201
- :param volume: Volume, from 0=quiet to 1=loud
202
- :param pan: Pan, from -1=left to 0=centered to 1=right
203
- :param loop: Should we loop the sound over and over?
204
- :param speed: Change the speed of the sound which also changes pitch, default 1.0
205
321
"""
206
322
if sound is None :
207
323
logger .warning ("Unable to play sound, no data passed in." )
@@ -221,11 +337,13 @@ def play_sound(
221
337
return None
222
338
223
339
224
- def stop_sound (player : media .Player ):
225
- """
226
- Stop a sound that is currently playing.
340
+ def stop_sound (player : media .Player ) -> None :
341
+ """Stop a pyglet player for a which is currently playing.
227
342
228
- :param player: Player returned from :func:`play_sound`.
343
+ Args:
344
+ player: A pyglet :py:class:`~pyglet.media.player.Player`
345
+ returned from :py:meth:`Sound.play <.Sound.play>` or
346
+ :func:`play_sound`.
229
347
"""
230
348
231
349
if not isinstance (player , media .Player ):
0 commit comments