pyglet 2.1.12__py3-none-any.whl → 3.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyglet/__init__.py +67 -61
- pyglet/__init__.pyi +15 -8
- pyglet/app/__init__.py +22 -13
- pyglet/app/async_app.py +212 -0
- pyglet/app/base.py +2 -1
- pyglet/app/{xlib.py → linux.py} +3 -3
- pyglet/config/__init__.py +101 -0
- pyglet/config/gl/__init__.py +30 -0
- pyglet/config/gl/egl.py +120 -0
- pyglet/config/gl/macos.py +262 -0
- pyglet/config/gl/windows.py +267 -0
- pyglet/config/gl/x11.py +142 -0
- pyglet/customtypes.py +43 -2
- pyglet/display/__init__.py +8 -6
- pyglet/display/base.py +3 -63
- pyglet/display/cocoa.py +12 -17
- pyglet/display/emscripten.py +39 -0
- pyglet/display/headless.py +23 -30
- pyglet/display/wayland.py +157 -0
- pyglet/display/win32.py +4 -17
- pyglet/display/xlib.py +19 -27
- pyglet/display/xlib_vidmoderestore.py +2 -2
- pyglet/enums.py +183 -0
- pyglet/event.py +0 -1
- pyglet/experimental/geoshader_sprite.py +15 -13
- pyglet/experimental/hidraw.py +6 -15
- pyglet/experimental/multitexture_sprite.py +31 -19
- pyglet/experimental/particles.py +13 -35
- pyglet/font/__init__.py +251 -85
- pyglet/font/base.py +116 -61
- pyglet/font/dwrite/__init__.py +349 -204
- pyglet/font/dwrite/dwrite_lib.py +27 -5
- pyglet/font/fontconfig.py +14 -6
- pyglet/font/freetype.py +138 -87
- pyglet/font/freetype_lib.py +19 -0
- pyglet/font/group.py +179 -0
- pyglet/font/harfbuzz/__init__.py +3 -3
- pyglet/font/pyodide_js.py +310 -0
- pyglet/font/quartz.py +319 -126
- pyglet/font/ttf.py +45 -3
- pyglet/font/user.py +14 -19
- pyglet/font/win32.py +45 -21
- pyglet/graphics/__init__.py +8 -787
- pyglet/graphics/allocation.py +115 -1
- pyglet/graphics/api/__init__.py +77 -0
- pyglet/graphics/api/base.py +299 -0
- pyglet/graphics/api/gl/__init__.py +58 -0
- pyglet/graphics/api/gl/base.py +24 -0
- pyglet/graphics/{vertexbuffer.py → api/gl/buffer.py} +104 -159
- pyglet/graphics/api/gl/cocoa/context.py +76 -0
- pyglet/graphics/api/gl/context.py +391 -0
- pyglet/graphics/api/gl/default_shaders.py +0 -0
- pyglet/graphics/api/gl/draw.py +627 -0
- pyglet/graphics/api/gl/egl/__init__.py +0 -0
- pyglet/graphics/api/gl/egl/context.py +92 -0
- pyglet/graphics/api/gl/enums.py +76 -0
- pyglet/graphics/api/gl/framebuffer.py +315 -0
- pyglet/graphics/api/gl/gl.py +5463 -0
- pyglet/graphics/api/gl/gl_info.py +188 -0
- pyglet/graphics/api/gl/global_opengl.py +226 -0
- pyglet/{gl → graphics/api/gl}/lib.py +34 -18
- pyglet/graphics/api/gl/shader.py +1476 -0
- pyglet/graphics/api/gl/shapes.py +55 -0
- pyglet/graphics/api/gl/sprite.py +102 -0
- pyglet/graphics/api/gl/state.py +219 -0
- pyglet/graphics/api/gl/text.py +190 -0
- pyglet/graphics/api/gl/texture.py +1526 -0
- pyglet/graphics/{vertexarray.py → api/gl/vertexarray.py} +11 -13
- pyglet/graphics/api/gl/vertexdomain.py +751 -0
- pyglet/graphics/api/gl/win32/__init__.py +0 -0
- pyglet/graphics/api/gl/win32/context.py +108 -0
- pyglet/graphics/api/gl/win32/wgl_info.py +24 -0
- pyglet/graphics/api/gl/xlib/__init__.py +0 -0
- pyglet/graphics/api/gl/xlib/context.py +174 -0
- pyglet/{gl → graphics/api/gl/xlib}/glx_info.py +26 -31
- pyglet/graphics/api/gl1/__init__.py +0 -0
- pyglet/{gl → graphics/api/gl1}/gl_compat.py +3 -2
- pyglet/graphics/api/gl2/__init__.py +0 -0
- pyglet/graphics/api/gl2/buffer.py +320 -0
- pyglet/graphics/api/gl2/draw.py +600 -0
- pyglet/graphics/api/gl2/global_opengl.py +122 -0
- pyglet/graphics/api/gl2/shader.py +200 -0
- pyglet/graphics/api/gl2/shapes.py +51 -0
- pyglet/graphics/api/gl2/sprite.py +79 -0
- pyglet/graphics/api/gl2/text.py +175 -0
- pyglet/graphics/api/gl2/vertexdomain.py +364 -0
- pyglet/graphics/api/webgl/__init__.py +233 -0
- pyglet/graphics/api/webgl/buffer.py +302 -0
- pyglet/graphics/api/webgl/context.py +234 -0
- pyglet/graphics/api/webgl/draw.py +590 -0
- pyglet/graphics/api/webgl/enums.py +76 -0
- pyglet/graphics/api/webgl/framebuffer.py +360 -0
- pyglet/graphics/api/webgl/gl.py +1537 -0
- pyglet/graphics/api/webgl/gl_info.py +130 -0
- pyglet/graphics/api/webgl/shader.py +1346 -0
- pyglet/graphics/api/webgl/shapes.py +92 -0
- pyglet/graphics/api/webgl/sprite.py +102 -0
- pyglet/graphics/api/webgl/state.py +227 -0
- pyglet/graphics/api/webgl/text.py +187 -0
- pyglet/graphics/api/webgl/texture.py +1227 -0
- pyglet/graphics/api/webgl/vertexarray.py +54 -0
- pyglet/graphics/api/webgl/vertexdomain.py +616 -0
- pyglet/graphics/api/webgl/webgl_js.pyi +307 -0
- pyglet/{image → graphics}/atlas.py +33 -32
- pyglet/graphics/base.py +10 -0
- pyglet/graphics/buffer.py +245 -0
- pyglet/graphics/draw.py +578 -0
- pyglet/graphics/framebuffer.py +26 -0
- pyglet/graphics/instance.py +178 -69
- pyglet/graphics/shader.py +267 -1553
- pyglet/graphics/state.py +83 -0
- pyglet/graphics/texture.py +703 -0
- pyglet/graphics/vertexdomain.py +695 -538
- pyglet/gui/ninepatch.py +10 -10
- pyglet/gui/widgets.py +120 -10
- pyglet/image/__init__.py +20 -1973
- pyglet/image/animation.py +12 -12
- pyglet/image/base.py +730 -0
- pyglet/image/codecs/__init__.py +9 -0
- pyglet/image/codecs/bmp.py +53 -30
- pyglet/image/codecs/dds.py +53 -31
- pyglet/image/codecs/gdiplus.py +38 -14
- pyglet/image/codecs/gdkpixbuf2.py +0 -2
- pyglet/image/codecs/js_image.py +99 -0
- pyglet/image/codecs/ktx2.py +161 -0
- pyglet/image/codecs/pil.py +1 -1
- pyglet/image/codecs/png.py +1 -1
- pyglet/image/codecs/wic.py +11 -2
- pyglet/info.py +26 -24
- pyglet/input/__init__.py +8 -0
- pyglet/input/base.py +163 -105
- pyglet/input/controller.py +13 -19
- pyglet/input/controller_db.py +39 -24
- pyglet/input/emscripten/__init__.py +18 -0
- pyglet/input/emscripten/gamepad_js.py +397 -0
- pyglet/input/linux/__init__.py +11 -5
- pyglet/input/linux/evdev.py +10 -11
- pyglet/input/linux/x11_xinput.py +2 -2
- pyglet/input/linux/x11_xinput_tablet.py +1 -1
- pyglet/input/macos/__init__.py +7 -2
- pyglet/input/macos/darwin_gc.py +559 -0
- pyglet/input/win32/__init__.py +1 -1
- pyglet/input/win32/directinput.py +34 -29
- pyglet/input/win32/xinput.py +11 -61
- pyglet/lib.py +3 -3
- pyglet/libs/__init__.py +1 -1
- pyglet/{gl → libs/darwin}/agl.py +1 -1
- pyglet/libs/darwin/cocoapy/__init__.py +2 -2
- pyglet/libs/darwin/cocoapy/cocoahelpers.py +181 -0
- pyglet/libs/darwin/cocoapy/cocoalibs.py +31 -0
- pyglet/libs/darwin/cocoapy/cocoatypes.py +27 -0
- pyglet/libs/darwin/cocoapy/runtime.py +81 -45
- pyglet/libs/darwin/coreaudio.py +4 -4
- pyglet/{gl → libs/darwin}/lib_agl.py +9 -8
- pyglet/libs/darwin/quartzkey.py +1 -3
- pyglet/libs/egl/__init__.py +2 -0
- pyglet/libs/egl/egl_lib.py +576 -0
- pyglet/libs/egl/eglext.py +51 -5
- pyglet/libs/linux/__init__.py +0 -0
- pyglet/libs/linux/egl/__init__.py +0 -0
- pyglet/libs/linux/egl/eglext.py +22 -0
- pyglet/libs/linux/glx/__init__.py +0 -0
- pyglet/{gl → libs/linux/glx}/glx.py +13 -14
- pyglet/{gl → libs/linux/glx}/glxext_arb.py +408 -192
- pyglet/{gl → libs/linux/glx}/glxext_mesa.py +1 -1
- pyglet/{gl → libs/linux/glx}/glxext_nv.py +345 -164
- pyglet/{gl → libs/linux/glx}/lib_glx.py +3 -2
- pyglet/libs/linux/wayland/__init__.py +0 -0
- pyglet/libs/linux/wayland/client.py +1068 -0
- pyglet/libs/linux/wayland/lib_wayland.py +207 -0
- pyglet/libs/linux/wayland/wayland_egl.py +38 -0
- pyglet/libs/{wayland → linux/wayland}/xkbcommon.py +26 -0
- pyglet/libs/{x11 → linux/x11}/xf86vmode.py +4 -4
- pyglet/libs/{x11 → linux/x11}/xinerama.py +2 -2
- pyglet/libs/{x11 → linux/x11}/xinput.py +10 -10
- pyglet/libs/linux/x11/xrandr.py +0 -0
- pyglet/libs/{x11 → linux/x11}/xrender.py +1 -1
- pyglet/libs/shared/__init__.py +0 -0
- pyglet/libs/shared/spirv/__init__.py +0 -0
- pyglet/libs/shared/spirv/lib_shaderc.py +85 -0
- pyglet/libs/shared/spirv/lib_spirv_cross.py +126 -0
- pyglet/libs/win32/__init__.py +27 -5
- pyglet/libs/win32/constants.py +59 -48
- pyglet/libs/win32/context_managers.py +20 -3
- pyglet/libs/win32/dinput.py +105 -88
- pyglet/{gl → libs/win32}/lib_wgl.py +52 -26
- pyglet/libs/win32/types.py +58 -23
- pyglet/{gl → libs/win32}/wgl.py +32 -25
- pyglet/{gl → libs/win32}/wglext_arb.py +364 -2
- pyglet/media/__init__.py +9 -10
- pyglet/media/codecs/__init__.py +12 -1
- pyglet/media/codecs/base.py +99 -96
- pyglet/media/codecs/ffmpeg.py +2 -2
- pyglet/media/codecs/ffmpeg_lib/libavformat.py +3 -8
- pyglet/media/codecs/webaudio_pyodide.py +111 -0
- pyglet/media/drivers/__init__.py +9 -4
- pyglet/media/drivers/base.py +4 -4
- pyglet/media/drivers/openal/__init__.py +1 -1
- pyglet/media/drivers/openal/adaptation.py +3 -3
- pyglet/media/drivers/pulse/__init__.py +1 -1
- pyglet/media/drivers/pulse/adaptation.py +3 -3
- pyglet/media/drivers/pyodide_js/__init__.py +8 -0
- pyglet/media/drivers/pyodide_js/adaptation.py +288 -0
- pyglet/media/drivers/xaudio2/adaptation.py +3 -3
- pyglet/media/player.py +276 -193
- pyglet/media/player_worker_thread.py +1 -1
- pyglet/model/__init__.py +39 -29
- pyglet/model/codecs/base.py +4 -4
- pyglet/model/codecs/gltf.py +3 -3
- pyglet/model/codecs/obj.py +71 -43
- pyglet/resource.py +129 -78
- pyglet/shapes.py +147 -177
- pyglet/sprite.py +47 -164
- pyglet/text/__init__.py +44 -54
- pyglet/text/caret.py +12 -7
- pyglet/text/document.py +19 -17
- pyglet/text/formats/html.py +2 -2
- pyglet/text/formats/structured.py +10 -40
- pyglet/text/layout/__init__.py +20 -13
- pyglet/text/layout/base.py +176 -287
- pyglet/text/layout/incremental.py +9 -10
- pyglet/text/layout/scrolling.py +7 -95
- pyglet/window/__init__.py +183 -172
- pyglet/window/cocoa/__init__.py +62 -51
- pyglet/window/cocoa/pyglet_delegate.py +2 -25
- pyglet/window/cocoa/pyglet_view.py +9 -8
- pyglet/window/dialog/__init__.py +184 -0
- pyglet/window/dialog/base.py +99 -0
- pyglet/window/dialog/darwin.py +121 -0
- pyglet/window/dialog/linux.py +72 -0
- pyglet/window/dialog/windows.py +194 -0
- pyglet/window/emscripten/__init__.py +779 -0
- pyglet/window/headless/__init__.py +44 -28
- pyglet/window/key.py +2 -0
- pyglet/window/mouse.py +2 -2
- pyglet/window/wayland/__init__.py +377 -0
- pyglet/window/win32/__init__.py +101 -46
- pyglet/window/xlib/__init__.py +104 -66
- {pyglet-2.1.12.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
- pyglet-3.0.dev1.dist-info/RECORD +322 -0
- {pyglet-2.1.12.dist-info → pyglet-3.0.dev1.dist-info}/WHEEL +1 -1
- pyglet/gl/__init__.py +0 -208
- pyglet/gl/base.py +0 -499
- pyglet/gl/cocoa.py +0 -309
- pyglet/gl/gl.py +0 -4625
- pyglet/gl/gl.pyi +0 -2320
- pyglet/gl/gl_compat.pyi +0 -3097
- pyglet/gl/gl_info.py +0 -190
- pyglet/gl/headless.py +0 -166
- pyglet/gl/wgl_info.py +0 -36
- pyglet/gl/wglext_nv.py +0 -1096
- pyglet/gl/win32.py +0 -268
- pyglet/gl/xlib.py +0 -295
- pyglet/image/buffer.py +0 -274
- pyglet/image/codecs/s3tc.py +0 -354
- pyglet/libs/x11/xrandr.py +0 -166
- pyglet-2.1.12.dist-info/RECORD +0 -234
- /pyglet/{libs/wayland → graphics/api/gl/cocoa}/__init__.py +0 -0
- /pyglet/libs/{egl → linux/egl}/egl.py +0 -0
- /pyglet/libs/{egl → linux/egl}/lib.py +0 -0
- /pyglet/libs/{ioctl.py → linux/ioctl.py} +0 -0
- /pyglet/libs/{wayland → linux/wayland}/gbm.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/__init__.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/cursorfont.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/xlib.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/xsync.py +0 -0
- {pyglet-2.1.12.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
pyglet/media/codecs/base.py
CHANGED
|
@@ -3,16 +3,16 @@ from __future__ import annotations
|
|
|
3
3
|
import ctypes
|
|
4
4
|
import io
|
|
5
5
|
from dataclasses import dataclass
|
|
6
|
-
from typing import TYPE_CHECKING, BinaryIO,
|
|
6
|
+
from typing import TYPE_CHECKING, BinaryIO, Optional, Union
|
|
7
7
|
|
|
8
|
-
from pyglet.media.exceptions import
|
|
8
|
+
from pyglet.media.exceptions import MediaException, CannotSeekException
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
-
from pyglet.
|
|
11
|
+
from pyglet.graphics import Texture
|
|
12
12
|
from pyglet.image.animation import Animation
|
|
13
13
|
from pyglet.media.codecs import MediaEncoder
|
|
14
14
|
from pyglet.media.drivers.base import MediaEvent
|
|
15
|
-
from pyglet.media.player import
|
|
15
|
+
from pyglet.media.player import AudioPlayer
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class AudioFormat:
|
|
@@ -21,15 +21,20 @@ class AudioFormat:
|
|
|
21
21
|
An instance of this class is provided by sources with audio tracks. You
|
|
22
22
|
should not modify the fields, as they are used internally to describe the
|
|
23
23
|
format of data provided by the source.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
channels (int): The number of channels: 1 for mono or 2 for stereo
|
|
27
|
-
(pyglet does not yet support surround-sound sources).
|
|
28
|
-
sample_size (int): Bits per sample; only 8 or 16 are supported.
|
|
29
|
-
sample_rate (int): Samples per second (in Hertz).
|
|
30
24
|
"""
|
|
31
25
|
|
|
32
26
|
def __init__(self, channels: int, sample_size: int, sample_rate: int) -> None:
|
|
27
|
+
"""Specify the audio format properties.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
channels:
|
|
31
|
+
The number of channels: 1 for mono or 2 for stereo
|
|
32
|
+
(pyglet does not yet support surround-sound sources).
|
|
33
|
+
sample_size:
|
|
34
|
+
Bits per sample; only 8 or 16 are supported.
|
|
35
|
+
sample_rate:
|
|
36
|
+
Samples per second (in Hertz).
|
|
37
|
+
"""
|
|
33
38
|
self.channels = channels
|
|
34
39
|
self.sample_size = sample_size
|
|
35
40
|
self.sample_rate = sample_rate
|
|
@@ -91,12 +96,15 @@ class VideoFormat:
|
|
|
91
96
|
should be displayed at 1280x480. It is the responsibility of the
|
|
92
97
|
application to perform this scaling.
|
|
93
98
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
Args:
|
|
100
|
+
width:
|
|
101
|
+
Width of video image, in pixels.
|
|
102
|
+
height:
|
|
103
|
+
Height of video image, in pixels.
|
|
104
|
+
sample_aspect:
|
|
105
|
+
Aspect ratio (width over height) of a single video pixel.
|
|
106
|
+
frame_rate:
|
|
107
|
+
Frame rate (frames per second) of the video or ``None`` if not known.
|
|
100
108
|
|
|
101
109
|
.. versionadded:: 1.2
|
|
102
110
|
"""
|
|
@@ -110,29 +118,35 @@ class AudioData:
|
|
|
110
118
|
"""A single packet of audio data.
|
|
111
119
|
|
|
112
120
|
This class is used internally by pyglet.
|
|
113
|
-
|
|
114
|
-
Args:
|
|
115
|
-
data (bytes, ctypes array, or supporting buffer protocol): Sample data.
|
|
116
|
-
length (int): Size of sample data, in bytes.
|
|
117
|
-
timestamp (float): Time of the first sample, in seconds.
|
|
118
|
-
duration (float): Total data duration, in seconds.
|
|
119
|
-
events (List[:class:`pyglet.media.drivers.base.MediaEvent`]): List of events
|
|
120
|
-
contained within this packet. Events are timestamped relative to
|
|
121
|
-
this audio packet.
|
|
122
|
-
|
|
123
|
-
.. deprecated:: 2.0.10
|
|
124
|
-
`timestamp` and `duration` are unused and will be removed eventually.
|
|
125
121
|
"""
|
|
126
122
|
|
|
127
123
|
__slots__ = 'data', 'duration', 'events', 'length', 'pointer', 'timestamp'
|
|
128
124
|
|
|
129
|
-
def __init__(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
125
|
+
def __init__(
|
|
126
|
+
self,
|
|
127
|
+
data: bytes | ctypes.Array,
|
|
128
|
+
length: int,
|
|
129
|
+
timestamp: float = 0.0,
|
|
130
|
+
duration: float = 0.0,
|
|
131
|
+
events: list[MediaEvent] | None = None,
|
|
132
|
+
) -> None:
|
|
133
|
+
"""Events (List[:class:`pyglet.media.drivers.base.MediaEvent`]):
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
data:
|
|
137
|
+
(bytes, ctypes array, or supporting buffer protocol): Sample data.
|
|
138
|
+
length:
|
|
139
|
+
Size of sample data, in bytes.
|
|
140
|
+
timestamp:
|
|
141
|
+
Time of the first sample, in seconds.
|
|
142
|
+
duration:
|
|
143
|
+
Total data duration, in seconds.
|
|
144
|
+
events:
|
|
145
|
+
List of events contained within this packet. Events are timestamped relative to this audio packet.
|
|
135
146
|
|
|
147
|
+
.. deprecated:: 2.0.10
|
|
148
|
+
`timestamp` and `duration` are unused and will be removed eventually.
|
|
149
|
+
"""
|
|
136
150
|
if isinstance(data, bytes):
|
|
137
151
|
# bytes are treated specially by ctypes and can be cast to a void pointer, get
|
|
138
152
|
# their content's address like this
|
|
@@ -200,21 +214,21 @@ class Source:
|
|
|
200
214
|
is_player_source (bool): Determine if this source is a player
|
|
201
215
|
current source.
|
|
202
216
|
|
|
203
|
-
Check on a :py:class:`~pyglet.media.player.
|
|
217
|
+
Check on a :py:class:`~pyglet.media.player.AudioPlayer` if this source
|
|
204
218
|
is the current source.
|
|
205
219
|
"""
|
|
206
220
|
|
|
207
221
|
_duration = None
|
|
208
|
-
_players:
|
|
222
|
+
_players: list[AudioPlayer] = [] # Players created through Source.play
|
|
209
223
|
|
|
210
|
-
audio_format = None
|
|
211
|
-
video_format = None
|
|
212
|
-
info = None
|
|
213
|
-
is_player_source = False
|
|
224
|
+
audio_format: AudioFormat | None = None
|
|
225
|
+
video_format: VideoFormat | None = None
|
|
226
|
+
info: SourceInfo | None = None
|
|
227
|
+
is_player_source: bool = False
|
|
214
228
|
|
|
215
229
|
@property
|
|
216
230
|
def duration(self) -> float:
|
|
217
|
-
"""
|
|
231
|
+
"""The length of the source, in seconds.
|
|
218
232
|
|
|
219
233
|
Not all source durations can be determined; in this case the value
|
|
220
234
|
is ``None``.
|
|
@@ -223,7 +237,7 @@ class Source:
|
|
|
223
237
|
"""
|
|
224
238
|
return self._duration
|
|
225
239
|
|
|
226
|
-
def play(self) ->
|
|
240
|
+
def play(self) -> AudioPlayer:
|
|
227
241
|
"""Play the source.
|
|
228
242
|
|
|
229
243
|
This is a convenience method which creates a Player for
|
|
@@ -232,8 +246,9 @@ class Source:
|
|
|
232
246
|
Returns:
|
|
233
247
|
:class:`.Player`
|
|
234
248
|
"""
|
|
235
|
-
from pyglet.media.player import
|
|
236
|
-
|
|
249
|
+
from pyglet.media.player import AudioPlayer # XXX Nasty circular dependency
|
|
250
|
+
|
|
251
|
+
player = AudioPlayer()
|
|
237
252
|
player.queue(self)
|
|
238
253
|
player.play()
|
|
239
254
|
Source._players.append(player)
|
|
@@ -259,28 +274,25 @@ class Source:
|
|
|
259
274
|
few seconds.
|
|
260
275
|
|
|
261
276
|
.. versionadded:: 1.1
|
|
262
|
-
|
|
263
|
-
Returns:
|
|
264
|
-
:class:`pyglet.image.Animation`
|
|
265
277
|
"""
|
|
266
278
|
from pyglet.image import Animation, AnimationFrame
|
|
279
|
+
|
|
267
280
|
if not self.video_format:
|
|
268
281
|
# XXX: This causes an assertion in the constructor of Animation
|
|
269
282
|
return Animation([])
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
283
|
+
frames = []
|
|
284
|
+
last_ts = 0
|
|
285
|
+
next_ts = self.get_next_video_timestamp()
|
|
286
|
+
while next_ts is not None:
|
|
287
|
+
image = self.get_next_video_frame()
|
|
288
|
+
if image is not None:
|
|
289
|
+
delay = next_ts - last_ts
|
|
290
|
+
frames.append(AnimationFrame(image, delay))
|
|
291
|
+
last_ts = next_ts
|
|
273
292
|
next_ts = self.get_next_video_timestamp()
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
delay = next_ts - last_ts
|
|
278
|
-
frames.append(AnimationFrame(image, delay))
|
|
279
|
-
last_ts = next_ts
|
|
280
|
-
next_ts = self.get_next_video_timestamp()
|
|
281
|
-
return Animation(frames)
|
|
282
|
-
|
|
283
|
-
def get_next_video_timestamp(self) -> Optional[float]:
|
|
293
|
+
return Animation(frames)
|
|
294
|
+
|
|
295
|
+
def get_next_video_timestamp(self) -> float | None:
|
|
284
296
|
"""Get the timestamp of the next video frame.
|
|
285
297
|
|
|
286
298
|
.. versionadded:: 1.1
|
|
@@ -289,33 +301,27 @@ class Source:
|
|
|
289
301
|
float: The next timestamp, or ``None`` if there are no more video
|
|
290
302
|
frames.
|
|
291
303
|
"""
|
|
292
|
-
pass
|
|
293
304
|
|
|
294
|
-
def get_next_video_frame(self) ->
|
|
305
|
+
def get_next_video_frame(self) -> Texture | None:
|
|
295
306
|
"""Get the next video frame.
|
|
296
307
|
|
|
297
|
-
.. versionadded:: 1.1
|
|
298
|
-
|
|
299
308
|
Returns:
|
|
300
|
-
|
|
301
|
-
or ``None`` if the video frame could not be decoded or there are
|
|
309
|
+
The next video frame image, or ``None`` if the video frame could not be decoded or there are
|
|
302
310
|
no more video frames.
|
|
311
|
+
|
|
312
|
+
.. versionadded:: 1.1
|
|
303
313
|
"""
|
|
304
|
-
pass
|
|
305
314
|
|
|
306
|
-
def save(self,
|
|
307
|
-
filename: str,
|
|
308
|
-
file: Optional[BinaryIO] = None,
|
|
309
|
-
encoder: Optional['MediaEncoder'] = None) -> None:
|
|
315
|
+
def save(self, filename: str, file: BinaryIO | None = None, encoder: MediaEncoder | None = None) -> None:
|
|
310
316
|
"""Save this Source to a file.
|
|
311
317
|
|
|
312
|
-
:
|
|
313
|
-
|
|
318
|
+
Args:
|
|
319
|
+
filename
|
|
314
320
|
Used to set the file format, and to open the output file
|
|
315
321
|
if `file` is unspecified.
|
|
316
|
-
|
|
322
|
+
file:
|
|
317
323
|
File to write audio data to.
|
|
318
|
-
|
|
324
|
+
encoder:
|
|
319
325
|
If unspecified, all encoders matching the filename extension
|
|
320
326
|
are tried. If all fail, the exception from the first one
|
|
321
327
|
attempted is raised.
|
|
@@ -323,14 +329,14 @@ class Source:
|
|
|
323
329
|
"""
|
|
324
330
|
if encoder:
|
|
325
331
|
return encoder.encode(self, filename, file)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
332
|
+
import pyglet.media.codecs
|
|
333
|
+
|
|
334
|
+
return pyglet.media.codecs.registry.encode(self, filename, file)
|
|
329
335
|
|
|
330
336
|
# Internal methods that Player calls on the source:
|
|
331
337
|
|
|
332
338
|
def is_precise(self) -> bool:
|
|
333
|
-
"""
|
|
339
|
+
"""Whether this source is considered precise.
|
|
334
340
|
|
|
335
341
|
``x`` bytes on source ``s`` are considered aligned if
|
|
336
342
|
``x % s.audio_format.bytes_per_frame == 0``, so there'd be no partial
|
|
@@ -362,8 +368,8 @@ class Source:
|
|
|
362
368
|
negatively impacted at best and memory access violations occur at
|
|
363
369
|
worst.
|
|
364
370
|
|
|
365
|
-
|
|
366
|
-
|
|
371
|
+
Returns:
|
|
372
|
+
Whether the source is precise.
|
|
367
373
|
"""
|
|
368
374
|
return False
|
|
369
375
|
|
|
@@ -376,7 +382,7 @@ class Source:
|
|
|
376
382
|
"""
|
|
377
383
|
raise CannotSeekException()
|
|
378
384
|
|
|
379
|
-
def get_queue_source(self) ->
|
|
385
|
+
def get_queue_source(self) -> Source:
|
|
380
386
|
"""Return the ``Source`` to be used as the queue source for a player.
|
|
381
387
|
|
|
382
388
|
Default implementation returns ``self``.
|
|
@@ -386,7 +392,7 @@ class Source:
|
|
|
386
392
|
"""
|
|
387
393
|
return self
|
|
388
394
|
|
|
389
|
-
def get_audio_data(self, num_bytes: int, compensation_time=0.0) ->
|
|
395
|
+
def get_audio_data(self, num_bytes: int, compensation_time=0.0) -> AudioData | None:
|
|
390
396
|
"""Get next packet of audio data.
|
|
391
397
|
|
|
392
398
|
Args:
|
|
@@ -409,10 +415,10 @@ class StreamingSource(Source):
|
|
|
409
415
|
"""A source that is decoded as it is being played.
|
|
410
416
|
|
|
411
417
|
The source can only be played once at a time on any
|
|
412
|
-
:class:`~pyglet.media.player.
|
|
418
|
+
:class:`~pyglet.media.player.AudioPlayer`.
|
|
413
419
|
"""
|
|
414
420
|
|
|
415
|
-
def get_queue_source(self) ->
|
|
421
|
+
def get_queue_source(self) -> StreamingSource:
|
|
416
422
|
"""Return the ``Source`` to be used as the source for a player.
|
|
417
423
|
|
|
418
424
|
Default implementation returns self.
|
|
@@ -427,7 +433,6 @@ class StreamingSource(Source):
|
|
|
427
433
|
|
|
428
434
|
def delete(self) -> None:
|
|
429
435
|
"""Release the resources held by this StreamingSource."""
|
|
430
|
-
pass
|
|
431
436
|
|
|
432
437
|
|
|
433
438
|
class StaticSource(Source):
|
|
@@ -469,7 +474,7 @@ class StaticSource(Source):
|
|
|
469
474
|
|
|
470
475
|
self._duration = len(self._data) / self.audio_format.bytes_per_second
|
|
471
476
|
|
|
472
|
-
def get_queue_source(self) -> Optional[
|
|
477
|
+
def get_queue_source(self) -> Optional[StaticMemorySource]:
|
|
473
478
|
if self._data is not None:
|
|
474
479
|
return StaticMemorySource(self._data, self.audio_format)
|
|
475
480
|
return None
|
|
@@ -478,7 +483,7 @@ class StaticSource(Source):
|
|
|
478
483
|
"""The StaticSource does not provide audio data.
|
|
479
484
|
|
|
480
485
|
When the StaticSource is queued on a
|
|
481
|
-
:class:`~pyglet.media.player.
|
|
486
|
+
:class:`~pyglet.media.player.AudioPlayer`, it creates a
|
|
482
487
|
:class:`.StaticMemorySource` containing its internal audio data and
|
|
483
488
|
audio format.
|
|
484
489
|
|
|
@@ -489,8 +494,7 @@ class StaticSource(Source):
|
|
|
489
494
|
|
|
490
495
|
|
|
491
496
|
class StaticMemorySource(StaticSource):
|
|
492
|
-
"""
|
|
493
|
-
Helper class for default implementation of :class:`.StaticSource`.
|
|
497
|
+
"""Helper class for default implementation of :class:`.StaticSource`.
|
|
494
498
|
|
|
495
499
|
Do not use directly. This class is used internally by pyglet.
|
|
496
500
|
|
|
@@ -569,14 +573,14 @@ class SourceGroup:
|
|
|
569
573
|
self.audio_format = self.audio_format or source.audio_format
|
|
570
574
|
self.info = self.info or source.info
|
|
571
575
|
source = source.get_queue_source()
|
|
572
|
-
assert
|
|
576
|
+
assert source.audio_format == self.audio_format, "Sources must share the same audio format."
|
|
573
577
|
self._sources.append(source)
|
|
574
578
|
self.duration += source.duration
|
|
575
579
|
|
|
576
580
|
def has_next(self) -> bool:
|
|
577
581
|
return len(self._sources) > 1
|
|
578
582
|
|
|
579
|
-
def get_queue_source(self) ->
|
|
583
|
+
def get_queue_source(self) -> SourceGroup:
|
|
580
584
|
return self
|
|
581
585
|
|
|
582
586
|
def _advance(self) -> None:
|
|
@@ -592,14 +596,13 @@ class SourceGroup:
|
|
|
592
596
|
def get_audio_data(self, num_bytes: float, compensation_time=0.0) -> Optional[AudioData]:
|
|
593
597
|
"""Get next audio packet.
|
|
594
598
|
|
|
595
|
-
:
|
|
599
|
+
Args:
|
|
596
600
|
`num_bytes` : int
|
|
597
601
|
Hint for preferred size of audio packet; may be ignored.
|
|
598
602
|
|
|
599
|
-
:
|
|
600
|
-
|
|
603
|
+
Returns:
|
|
604
|
+
Audio data, or ``None`` if there is no more data.
|
|
601
605
|
"""
|
|
602
|
-
|
|
603
606
|
if not self._sources:
|
|
604
607
|
return None
|
|
605
608
|
|
pyglet/media/codecs/ffmpeg.py
CHANGED
|
@@ -1037,7 +1037,7 @@ class FFmpegSource(StreamingSource):
|
|
|
1037
1037
|
width = self.video_format.width
|
|
1038
1038
|
height = self.video_format.height
|
|
1039
1039
|
pitch = width * 4
|
|
1040
|
-
buf_size = avutil.av_image_get_buffer_size(AV_PIX_FMT_RGBA, width, height, 1)
|
|
1040
|
+
buf_size = avutil.av_image_get_buffer_size(AV_PIX_FMT_RGBA, width, height, 1)
|
|
1041
1041
|
buffer = (c_uint8 * buf_size)()
|
|
1042
1042
|
try:
|
|
1043
1043
|
result = self._ffmpeg_decode_video(video_packet.packet, buffer)
|
|
@@ -1195,7 +1195,7 @@ class FFmpegSource(StreamingSource):
|
|
|
1195
1195
|
|
|
1196
1196
|
|
|
1197
1197
|
ffmpeg_init()
|
|
1198
|
-
if pyglet.options
|
|
1198
|
+
if pyglet.options.debug_media:
|
|
1199
1199
|
_debug = True
|
|
1200
1200
|
else:
|
|
1201
1201
|
_debug = False
|
|
@@ -132,8 +132,8 @@ AVStream_Fields = [
|
|
|
132
132
|
('metadata', POINTER(AVDictionary)),
|
|
133
133
|
('avg_frame_rate', AVRational),
|
|
134
134
|
('attached_pic', AVPacket),
|
|
135
|
-
('side_data', POINTER(AVPacketSideData)),
|
|
136
|
-
('nb_side_data', c_int),
|
|
135
|
+
('side_data', POINTER(AVPacketSideData)),
|
|
136
|
+
('nb_side_data', c_int),
|
|
137
137
|
('event_flags', c_int),
|
|
138
138
|
('r_frame_rate', AVRational),
|
|
139
139
|
('recommended_encoder_configuration', c_char_p), # Deprecated. Removed in 59.
|
|
@@ -147,16 +147,11 @@ compat.add_version_changes('avformat', 58, AVStream, AVStream_Fields, removals=(
|
|
|
147
147
|
compat.add_version_changes('avformat', 59, AVStream, AVStream_Fields,
|
|
148
148
|
removals=('av_class', 'codec', 'recommended_encoder_configuration', 'info'))
|
|
149
149
|
|
|
150
|
-
for compat_ver in (60, 61):
|
|
150
|
+
for compat_ver in (60, 61, 62):
|
|
151
151
|
compat.add_version_changes('avformat', compat_ver, AVStream, AVStream_Fields,
|
|
152
152
|
removals=('codec', 'recommended_encoder_configuration', 'info'),
|
|
153
153
|
repositions=(compat.Reposition("codecpar", "id"),))
|
|
154
154
|
|
|
155
|
-
compat.add_version_changes('avformat', 62, AVStream, AVStream_Fields,
|
|
156
|
-
removals=('codec', 'recommended_encoder_configuration', 'info', 'side_data',
|
|
157
|
-
'nb_side_data'),
|
|
158
|
-
repositions=(compat.Reposition("codecpar", "id"),))
|
|
159
|
-
|
|
160
155
|
|
|
161
156
|
class AVProgram(Structure):
|
|
162
157
|
pass
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import weakref
|
|
4
|
+
from typing import BinaryIO, NoReturn, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
import pyglet
|
|
7
|
+
|
|
8
|
+
from . import MediaDecoder
|
|
9
|
+
from .base import AudioFormat, Source, StaticSource
|
|
10
|
+
|
|
11
|
+
_debug = pyglet.options.debug_media
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
import js
|
|
15
|
+
import pyodide.ffi
|
|
16
|
+
except ImportError:
|
|
17
|
+
raise ImportError("Pyodide not found.")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
from pyglet.media import get_audio_driver
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from pyglet.media.drivers.pyodide_js.adaptation import PyodideJSAudioPlayer
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class JavascriptWebAudioSource(Source):
|
|
27
|
+
def __init__(self, filename: str, file: BinaryIO | None = None) -> None: # noqa: D107
|
|
28
|
+
if file is None:
|
|
29
|
+
with open(filename, 'rb') as f:
|
|
30
|
+
data = f.read()
|
|
31
|
+
self._file = data
|
|
32
|
+
else:
|
|
33
|
+
self._file = file.read()
|
|
34
|
+
|
|
35
|
+
self.filename = filename
|
|
36
|
+
self.js_array = js.Uint8Array.new(self._file)
|
|
37
|
+
self.audio_buffer = None
|
|
38
|
+
self._duration = 0
|
|
39
|
+
self._current_offset = 0
|
|
40
|
+
|
|
41
|
+
# Default dummy audio format so AudioPlayer can create an internal PyodideJSAudioPlayer.
|
|
42
|
+
# The JavaScript internal player doesn't use this object.
|
|
43
|
+
self.audio_format = AudioFormat(channels=2, sample_size=16, sample_rate=44100)
|
|
44
|
+
|
|
45
|
+
# If this audio is not finished loading, a player may be waiting to play it.
|
|
46
|
+
self._waiting_players = weakref.WeakSet()
|
|
47
|
+
|
|
48
|
+
get_audio_driver().decode_audio(self.js_array.buffer).then(self.on_decode).catch(self.on_error)
|
|
49
|
+
|
|
50
|
+
def add_player(self, player: PyodideJSAudioPlayer) -> None:
|
|
51
|
+
self._waiting_players.add(player)
|
|
52
|
+
|
|
53
|
+
# Decode the audio data
|
|
54
|
+
def on_decode(self, audio_buffer) -> None:
|
|
55
|
+
if _debug:
|
|
56
|
+
print(f"Decoded {self.filename} successfully.")
|
|
57
|
+
self.audio_buffer = audio_buffer
|
|
58
|
+
|
|
59
|
+
self.audio_format = AudioFormat(
|
|
60
|
+
channels=self.audio_buffer.numberOfChannels,
|
|
61
|
+
sample_size=16,
|
|
62
|
+
sample_rate=self.audio_buffer.sampleRate,
|
|
63
|
+
)
|
|
64
|
+
self._duration = self.audio_buffer.duration
|
|
65
|
+
|
|
66
|
+
for player in self._waiting_players:
|
|
67
|
+
player.on_source_finished_loading(self)
|
|
68
|
+
|
|
69
|
+
self._waiting_players.clear()
|
|
70
|
+
|
|
71
|
+
def on_error(self, error) -> NoReturn:
|
|
72
|
+
js.console.log(f"Failed decoding {self.filename}: {error}")
|
|
73
|
+
|
|
74
|
+
self._waiting_players.clear()
|
|
75
|
+
|
|
76
|
+
def __del__(self) -> None:
|
|
77
|
+
if hasattr(self, '_file'):
|
|
78
|
+
self._file = None
|
|
79
|
+
|
|
80
|
+
self.js_array = None
|
|
81
|
+
self.audio_buffer = None
|
|
82
|
+
|
|
83
|
+
def get_audio_data(self, num_bytes: int, compensation_time: float = 0.0) -> NoReturn:
|
|
84
|
+
raise NotImplementedError("This is not supported and should not be called.")
|
|
85
|
+
|
|
86
|
+
def seek(self, timestamp: float) -> NoReturn:
|
|
87
|
+
"""This is not supported by Javascript."""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
#########################################
|
|
91
|
+
# Decoder class:
|
|
92
|
+
#########################################
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class PyodideDecoder(MediaDecoder): # noqa: D101
|
|
96
|
+
def get_file_extensions(self) -> tuple[str, ...]:
|
|
97
|
+
return '.mp3', '.aac', '.wav', '.ogg', '.webm'
|
|
98
|
+
# possibly use audio.canPlayType?
|
|
99
|
+
|
|
100
|
+
def decode(self, filename: str, file: BinaryIO, streaming: bool = True) -> JavascriptWebAudioSource | StaticSource:
|
|
101
|
+
if streaming:
|
|
102
|
+
return JavascriptWebAudioSource(filename, file)
|
|
103
|
+
return StaticSource(JavascriptWebAudioSource(filename, file))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_decoders() -> list[PyodideDecoder]: # noqa: D103
|
|
107
|
+
return [PyodideDecoder()]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_encoders() -> list: # noqa: D103
|
|
111
|
+
return []
|
pyglet/media/drivers/__init__.py
CHANGED
|
@@ -5,7 +5,7 @@ import atexit
|
|
|
5
5
|
|
|
6
6
|
import pyglet
|
|
7
7
|
|
|
8
|
-
_debug = pyglet.options
|
|
8
|
+
_debug = pyglet.options.debug_media
|
|
9
9
|
_is_pyglet_doc_run = hasattr(sys, "is_pyglet_doc_run") and sys.is_pyglet_doc_run
|
|
10
10
|
|
|
11
11
|
|
|
@@ -15,7 +15,7 @@ if _is_pyglet_doc_run:
|
|
|
15
15
|
|
|
16
16
|
else:
|
|
17
17
|
|
|
18
|
-
for driver_name in pyglet.options
|
|
18
|
+
for driver_name in pyglet.options.audio:
|
|
19
19
|
try:
|
|
20
20
|
if driver_name == 'pulse':
|
|
21
21
|
from . import pulse
|
|
@@ -55,8 +55,13 @@ else:
|
|
|
55
55
|
traceback.print_exc()
|
|
56
56
|
|
|
57
57
|
else:
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
if pyglet.compat_platform == "emscripten":
|
|
59
|
+
from . import pyodide_js
|
|
60
|
+
|
|
61
|
+
_audio_driver = pyodide_js.create_audio_driver()
|
|
62
|
+
else:
|
|
63
|
+
from . import silent
|
|
64
|
+
_audio_driver = silent.create_audio_driver()
|
|
60
65
|
|
|
61
66
|
|
|
62
67
|
def get_audio_driver():
|
pyglet/media/drivers/base.py
CHANGED
|
@@ -409,7 +409,7 @@ class AbstractAudioPlayer(metaclass=ABCMeta):
|
|
|
409
409
|
pass
|
|
410
410
|
|
|
411
411
|
def set_position(self, position):
|
|
412
|
-
"""See :py:attr:`~pyglet.media.
|
|
412
|
+
"""See :py:attr:`~pyglet.media.AudioPlayer.position`."""
|
|
413
413
|
pass
|
|
414
414
|
|
|
415
415
|
def set_min_distance(self, min_distance):
|
|
@@ -421,7 +421,7 @@ class AbstractAudioPlayer(metaclass=ABCMeta):
|
|
|
421
421
|
pass
|
|
422
422
|
|
|
423
423
|
def set_pitch(self, pitch):
|
|
424
|
-
"""See :py:attr:`~pyglet.media.
|
|
424
|
+
"""See :py:attr:`~pyglet.media.AudioPlayer.pitch`."""
|
|
425
425
|
pass
|
|
426
426
|
|
|
427
427
|
def set_cone_orientation(self, cone_orientation):
|
|
@@ -459,7 +459,7 @@ class MediaEvent:
|
|
|
459
459
|
"""Representation of a media event.
|
|
460
460
|
|
|
461
461
|
These events are used internally by some audio driver implementation to
|
|
462
|
-
communicate events to the :class:`~pyglet.media.player.
|
|
462
|
+
communicate events to the :class:`~pyglet.media.player.AudioPlayer`.
|
|
463
463
|
One example is the ``on_eos`` event.
|
|
464
464
|
|
|
465
465
|
Args:
|
|
@@ -468,7 +468,7 @@ class MediaEvent:
|
|
|
468
468
|
*args: Any required positional argument to go along with this event.
|
|
469
469
|
"""
|
|
470
470
|
|
|
471
|
-
__slots__ = '
|
|
471
|
+
__slots__ = 'args', 'event', 'timestamp'
|
|
472
472
|
|
|
473
473
|
def __init__(self, event, timestamp=0.0, *args):
|
|
474
474
|
# Meaning of timestamp is dependent on context; and not seen by application.
|
|
@@ -9,7 +9,7 @@ from pyglet.media.player_worker_thread import PlayerWorkerThread
|
|
|
9
9
|
from pyglet.util import debug_print
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
-
from pyglet.media import Source,
|
|
12
|
+
from pyglet.media import Source, AudioPlayer
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
_debug = debug_print('debug_media')
|
|
@@ -28,7 +28,7 @@ class OpenALDriver(AbstractAudioDriver):
|
|
|
28
28
|
self.worker = PlayerWorkerThread()
|
|
29
29
|
self.worker.start()
|
|
30
30
|
|
|
31
|
-
def create_audio_player(self, source: 'Source', player: '
|
|
31
|
+
def create_audio_player(self, source: 'Source', player: 'AudioPlayer') -> 'OpenALAudioPlayer':
|
|
32
32
|
assert self.device is not None, 'Device was closed'
|
|
33
33
|
return OpenALAudioPlayer(self, source, player)
|
|
34
34
|
|
|
@@ -91,7 +91,7 @@ class OpenALListener(AbstractListener):
|
|
|
91
91
|
|
|
92
92
|
|
|
93
93
|
class OpenALAudioPlayer(AbstractAudioPlayer):
|
|
94
|
-
def __init__(self, driver: 'OpenALDriver', source: 'Source', player: '
|
|
94
|
+
def __init__(self, driver: 'OpenALDriver', source: 'Source', player: 'AudioPlayer') -> None:
|
|
95
95
|
super().__init__(source, player)
|
|
96
96
|
self.driver = driver
|
|
97
97
|
self.alsource = driver.context.create_source()
|