pyglet 2.1.13__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 +5 -21
- 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 +28 -8
- 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 +154 -194
- 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.13.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
- pyglet-3.0.dev1.dist-info/RECORD +322 -0
- {pyglet-2.1.13.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.13.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.13.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
|
@@ -14,7 +14,7 @@ from .interface import PulseAudioMainloop
|
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from pyglet.media.codecs import AudioData, AudioFormat, Source
|
|
17
|
-
from pyglet.media.player import
|
|
17
|
+
from pyglet.media.player import AudioPlayer
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
_debug = debug_print('debug_media')
|
|
@@ -31,7 +31,7 @@ class PulseAudioDriver(AbstractAudioDriver):
|
|
|
31
31
|
self._players = weakref.WeakSet()
|
|
32
32
|
self._listener = PulseAudioListener(self)
|
|
33
33
|
|
|
34
|
-
def create_audio_player(self, source: 'Source', player: '
|
|
34
|
+
def create_audio_player(self, source: 'Source', player: 'AudioPlayer') -> 'PulseAudioPlayer':
|
|
35
35
|
assert self.context is not None
|
|
36
36
|
player = PulseAudioPlayer(source, player, self)
|
|
37
37
|
self._players.add(player)
|
|
@@ -148,7 +148,7 @@ class _AudioDataBuffer:
|
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
class PulseAudioPlayer(AbstractAudioPlayer):
|
|
151
|
-
def __init__(self, source: 'Source', player: '
|
|
151
|
+
def __init__(self, source: 'Source', player: 'AudioPlayer', driver: 'PulseAudioDriver') -> None:
|
|
152
152
|
super().__init__(source, player)
|
|
153
153
|
self.driver = driver
|
|
154
154
|
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from typing import TYPE_CHECKING, NoReturn
|
|
5
|
+
|
|
6
|
+
import pyglet
|
|
7
|
+
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
|
8
|
+
from pyglet.media.drivers.listener import AbstractListener
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import js
|
|
12
|
+
from pyodide.ffi import create_proxy
|
|
13
|
+
except ImportError:
|
|
14
|
+
raise ImportError('Pyodide not available.')
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from pyglet.media import Player
|
|
18
|
+
from pyglet.media.codecs.webaudio_pyodide import JavascriptWebAudioSource
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class JSAudioDriver(AbstractAudioDriver):
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
super().__init__()
|
|
24
|
+
self._start_button = None
|
|
25
|
+
self._start_button_proxy = None
|
|
26
|
+
self.ctx = js.window.AudioContext.new()
|
|
27
|
+
self._audio_state_proxy = create_proxy(self._update_button_state)
|
|
28
|
+
self.ctx.onstatechange = self._audio_state_proxy
|
|
29
|
+
|
|
30
|
+
def _update_button_state(self, event=None):
|
|
31
|
+
state = self.ctx.state
|
|
32
|
+
if state == "suspended":
|
|
33
|
+
if not self._start_button:
|
|
34
|
+
self._create_approval()
|
|
35
|
+
self._start_button.style.display = "block"
|
|
36
|
+
else:
|
|
37
|
+
if self._start_button:
|
|
38
|
+
self._start_button.style.display = "none"
|
|
39
|
+
|
|
40
|
+
def resume_audio_context(self, event):
|
|
41
|
+
if self.ctx.state == "suspended":
|
|
42
|
+
# Resume the AudioContext, and then hide the button
|
|
43
|
+
self.ctx.resume().then(lambda _: js.console.log("AudioContext resumed!"))
|
|
44
|
+
# Optionally, remove or hide the button after the first click
|
|
45
|
+
self._start_button.style.display = "none"
|
|
46
|
+
|
|
47
|
+
def _remove_approval(self):
|
|
48
|
+
self._start_button.removeEventListener("click", self._start_button_proxy)
|
|
49
|
+
self._start_button_proxy.destroy()
|
|
50
|
+
self._start_button_proxy = None
|
|
51
|
+
self._start_button.remove()
|
|
52
|
+
self._start_button = None
|
|
53
|
+
|
|
54
|
+
def _create_approval(self):
|
|
55
|
+
# Create a button element to resume audio, as browsers may block it due to abuse of page sounds.
|
|
56
|
+
assert self._start_button is None
|
|
57
|
+
self._start_button = js.document.createElement("button")
|
|
58
|
+
self._start_button.innerHTML = "Click to Enable Audio"
|
|
59
|
+
self._start_button.style.top = "50%"
|
|
60
|
+
self._start_button.style.left = "50%"
|
|
61
|
+
self._start_button.style.padding = "10px 20px"
|
|
62
|
+
self._start_button.style.fontSize = "16px"
|
|
63
|
+
self._start_button_proxy = create_proxy(self.resume_audio_context)
|
|
64
|
+
self._start_button.addEventListener("click", self._start_button_proxy)
|
|
65
|
+
js.document.body.appendChild(self._start_button)
|
|
66
|
+
|
|
67
|
+
def decode_audio(self, array_buffer):
|
|
68
|
+
return self.ctx.decodeAudioData(array_buffer)
|
|
69
|
+
|
|
70
|
+
def create_audio_player(self, source, player):
|
|
71
|
+
return PyodideJSAudioPlayer(self, source, player)
|
|
72
|
+
|
|
73
|
+
def get_listener(self):
|
|
74
|
+
return PyodideJSListener(self)
|
|
75
|
+
|
|
76
|
+
def delete(self):
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
def _convert_coordinates(coordinates: tuple[float, float, float]) -> tuple[float, float, float]:
|
|
80
|
+
x, y, z = coordinates
|
|
81
|
+
return x, y, -z
|
|
82
|
+
|
|
83
|
+
class PyodideJSListener(AbstractListener):
|
|
84
|
+
"""Not currently supported."""
|
|
85
|
+
|
|
86
|
+
def __init__(self, driver: JSAudioDriver):
|
|
87
|
+
super().__init__()
|
|
88
|
+
self._driver = driver
|
|
89
|
+
self._listener = driver.ctx.listener
|
|
90
|
+
|
|
91
|
+
def _set_volume(self, volume):
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
def _set_position(self, position: tuple[float, float, float]):
|
|
95
|
+
self._position = position
|
|
96
|
+
self._listener.positionX = position[0]
|
|
97
|
+
self._listener.positionY = position[0]
|
|
98
|
+
self._listener.positionZ = position[0]
|
|
99
|
+
|
|
100
|
+
def _set_forward_orientation(self, orientation):
|
|
101
|
+
self._forward_orientation = orientation
|
|
102
|
+
|
|
103
|
+
x, y, z = _convert_coordinates(orientation)
|
|
104
|
+
self._listener.forwardX = x
|
|
105
|
+
self._listener.forwardY = y
|
|
106
|
+
self._listener.forwardZ = z
|
|
107
|
+
|
|
108
|
+
def _set_up_orientation(self, orientation):
|
|
109
|
+
self._up_orientation = orientation
|
|
110
|
+
x, y, z = _convert_coordinates(orientation)
|
|
111
|
+
self._listener.upX = x
|
|
112
|
+
self._listener.upY = y
|
|
113
|
+
self._listener.upZ = z
|
|
114
|
+
|
|
115
|
+
def _set_orientation(self):
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class PyodideJSAudioPlayer(AbstractAudioPlayer):
|
|
120
|
+
def __init__(self, driver: JSAudioDriver, source: JavascriptWebAudioSource, player: Player) -> None:
|
|
121
|
+
super().__init__(source, player)
|
|
122
|
+
self.driver = driver
|
|
123
|
+
self._buffer_loaded = False
|
|
124
|
+
|
|
125
|
+
self._source_player = driver.ctx.createBufferSource()
|
|
126
|
+
# Audio buffer has not been loaded yet.
|
|
127
|
+
if not source.audio_buffer:
|
|
128
|
+
self._buffer_loaded = False
|
|
129
|
+
source.add_player(self)
|
|
130
|
+
else:
|
|
131
|
+
self._buffer_loaded = True
|
|
132
|
+
self._source_player.buffer = source.audio_buffer
|
|
133
|
+
|
|
134
|
+
# Only create a gain node if the volume is actually adjusted.
|
|
135
|
+
|
|
136
|
+
self._gain_node = self.driver.ctx.createGain()
|
|
137
|
+
self._panner_node = self.driver.ctx.createPanner()
|
|
138
|
+
# Connect Source to Gain Node
|
|
139
|
+
self._source_player.connect(self._gain_node)
|
|
140
|
+
# Connect Gain to Panner
|
|
141
|
+
self._gain_node.connect(self._panner_node)
|
|
142
|
+
|
|
143
|
+
# Connect Panner to Destination
|
|
144
|
+
self._panner_node.connect(self.driver.ctx.destination)
|
|
145
|
+
|
|
146
|
+
self._pseudo_play_cursor = 0
|
|
147
|
+
self._pseudo_write_cursor = 0
|
|
148
|
+
self._playing = False
|
|
149
|
+
self._start_position = 0
|
|
150
|
+
|
|
151
|
+
self._exhausted = False
|
|
152
|
+
self._dispatched_on_eos = False
|
|
153
|
+
|
|
154
|
+
# Optionally, you can set up an "onended" event:
|
|
155
|
+
def on_ended(_) -> None: # noqa: ANN001
|
|
156
|
+
self._playing = False
|
|
157
|
+
# Dispatch EOS event if needed.
|
|
158
|
+
asyncio.create_task(MediaEvent('on_eos').sync_dispatch_to_player(self.player))
|
|
159
|
+
|
|
160
|
+
self._source_player.onended = on_ended
|
|
161
|
+
|
|
162
|
+
def on_source_finished_loading(self, source: JavascriptWebAudioSource) -> None:
|
|
163
|
+
self._source_player.buffer = source.audio_buffer
|
|
164
|
+
self._buffer_loaded = True
|
|
165
|
+
|
|
166
|
+
def __del__(self) -> None:
|
|
167
|
+
self.delete()
|
|
168
|
+
|
|
169
|
+
def delete(self) -> None:
|
|
170
|
+
if self._gain_node:
|
|
171
|
+
self._gain_node.disconnect()
|
|
172
|
+
self._gain_node = None
|
|
173
|
+
|
|
174
|
+
if self._panner_node:
|
|
175
|
+
self._panner_node.disconnect()
|
|
176
|
+
self._panner_node = None
|
|
177
|
+
|
|
178
|
+
if self._source_player:
|
|
179
|
+
self._source_player.disconnect()
|
|
180
|
+
self._source_player.onended = None
|
|
181
|
+
self._source_player = None
|
|
182
|
+
|
|
183
|
+
def play(self) -> None:
|
|
184
|
+
self._playing = True
|
|
185
|
+
self._source_player.start(self._start_position)
|
|
186
|
+
|
|
187
|
+
def stop(self) -> None:
|
|
188
|
+
self._source_player.stop()
|
|
189
|
+
self._playing = False
|
|
190
|
+
|
|
191
|
+
def work(self) -> NoReturn:
|
|
192
|
+
raise NotImplementedError("This should not be called for this player.")
|
|
193
|
+
|
|
194
|
+
def prefill_audio(self) -> None:
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
def _update_play_cursor(self) -> None:
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
def clear(self) -> None:
|
|
201
|
+
super().clear()
|
|
202
|
+
self._pseudo_play_cursor = 0
|
|
203
|
+
self._pseudo_write_cursor = 0
|
|
204
|
+
self._exhausted = False
|
|
205
|
+
self._dispatched_on_eos = False
|
|
206
|
+
|
|
207
|
+
def seek(self, position: float) -> None:
|
|
208
|
+
self._start_position = position
|
|
209
|
+
if self._playing:
|
|
210
|
+
self._source_player.start(position)
|
|
211
|
+
|
|
212
|
+
def get_play_cursor(self) -> float:
|
|
213
|
+
return self._pseudo_play_cursor
|
|
214
|
+
|
|
215
|
+
def set_volume(self, volume: float) -> None:
|
|
216
|
+
if self._gain_node:
|
|
217
|
+
self._gain_node.gain.value = volume
|
|
218
|
+
|
|
219
|
+
def set_position(self, position: tuple[float, float, float]) -> None:
|
|
220
|
+
if self._panner_node:
|
|
221
|
+
x, y, z = position
|
|
222
|
+
self._panner_node.positionX.value = x
|
|
223
|
+
self._panner_node.positionY.value = y
|
|
224
|
+
self._panner_node.positionZ.value = z
|
|
225
|
+
|
|
226
|
+
def set_min_distance(self, min_distance: float) -> None:
|
|
227
|
+
if self._panner_node:
|
|
228
|
+
self._panner_node.refDistance = min_distance
|
|
229
|
+
|
|
230
|
+
def set_max_distance(self, max_distance: float) -> None:
|
|
231
|
+
if self._panner_node:
|
|
232
|
+
self._panner_node.maxDistance = max_distance
|
|
233
|
+
|
|
234
|
+
def set_pitch(self, pitch: float) -> None:
|
|
235
|
+
if self._source_player:
|
|
236
|
+
self._source_player.playbackRate.value = pitch
|
|
237
|
+
|
|
238
|
+
def set_cone_orientation(self, cone_orientation: tuple[float, float, float]) -> None:
|
|
239
|
+
if self._panner_node:
|
|
240
|
+
x, y, z = cone_orientation
|
|
241
|
+
self._panner_node.orientationX.value = x
|
|
242
|
+
self._panner_node.orientationY.value = y
|
|
243
|
+
self._panner_node.orientationZ.value = z
|
|
244
|
+
|
|
245
|
+
def set_cone_inner_angle(self, cone_inner_angle: float) -> None:
|
|
246
|
+
if self._panner_node:
|
|
247
|
+
self._panner_node.coneInnerAngle = cone_inner_angle
|
|
248
|
+
|
|
249
|
+
def set_cone_outer_angle(self, cone_outer_angle: float) -> None:
|
|
250
|
+
if self._panner_node:
|
|
251
|
+
self._panner_node.coneOuterAngle = cone_outer_angle
|
|
252
|
+
|
|
253
|
+
def set_cone_outer_gain(self, cone_outer_gain: float) -> None:
|
|
254
|
+
if self._panner_node:
|
|
255
|
+
self._panner_node.coneOuterGain = cone_outer_gain
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class MediaEvent:
|
|
259
|
+
"""Representation of a media event.
|
|
260
|
+
|
|
261
|
+
These events are used internally by some audio driver implementation to
|
|
262
|
+
communicate events to the :class:`~pyglet.media.player.Player`.
|
|
263
|
+
One example is the ``on_eos`` event.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
event (str): Event description.
|
|
267
|
+
timestamp (float): The time when this event happens.
|
|
268
|
+
*args: Any required positional argument to go along with this event.
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
__slots__ = 'event', 'timestamp', 'args'
|
|
272
|
+
|
|
273
|
+
def __init__(self, event, timestamp=0.0, *args):
|
|
274
|
+
# Meaning of timestamp is dependent on context; and not seen by application.
|
|
275
|
+
self.event = event
|
|
276
|
+
self.timestamp = timestamp
|
|
277
|
+
self.args = args
|
|
278
|
+
|
|
279
|
+
async def sync_dispatch_to_player(self, player):
|
|
280
|
+
await pyglet.app.platform_event_loop.post_event(player, self.event, *self.args)
|
|
281
|
+
|
|
282
|
+
def __repr__(self):
|
|
283
|
+
return f"MediaEvent({self.event}, {self.timestamp}, {self.args})"
|
|
284
|
+
|
|
285
|
+
def __lt__(self, other):
|
|
286
|
+
if not isinstance(other, MediaEvent):
|
|
287
|
+
return NotImplemented
|
|
288
|
+
return self.timestamp < other.timestamp
|
|
@@ -11,7 +11,7 @@ from . import interface
|
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
13
|
from pyglet.media.codecs import AudioData, AudioFormat, Source
|
|
14
|
-
from pyglet.media.player import
|
|
14
|
+
from pyglet.media.player import AudioPlayer
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
_debug = debug_print('debug_media')
|
|
@@ -35,7 +35,7 @@ class XAudio2Driver(AbstractAudioDriver):
|
|
|
35
35
|
assert self._xa2_driver is not None
|
|
36
36
|
return self._xa2_driver.get_performance()
|
|
37
37
|
|
|
38
|
-
def create_audio_player(self, source: 'Source', player: '
|
|
38
|
+
def create_audio_player(self, source: 'Source', player: 'AudioPlayer') -> 'XAudio2AudioPlayer':
|
|
39
39
|
assert self._xa2_driver is not None
|
|
40
40
|
return XAudio2AudioPlayer(self, source, player)
|
|
41
41
|
|
|
@@ -79,7 +79,7 @@ class XAudio2Listener(AbstractListener):
|
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
class XAudio2AudioPlayer(AbstractAudioPlayer):
|
|
82
|
-
def __init__(self, driver: 'XAudio2Driver', source: 'Source', player: '
|
|
82
|
+
def __init__(self, driver: 'XAudio2Driver', source: 'Source', player: 'AudioPlayer') -> None:
|
|
83
83
|
super().__init__(source, player)
|
|
84
84
|
# We keep here a strong reference because the AudioDriver is anyway
|
|
85
85
|
# a singleton object which will only be deleted when the application
|