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.
Files changed (267) hide show
  1. pyglet/__init__.py +67 -61
  2. pyglet/__init__.pyi +15 -8
  3. pyglet/app/__init__.py +22 -13
  4. pyglet/app/async_app.py +212 -0
  5. pyglet/app/base.py +2 -1
  6. pyglet/app/{xlib.py → linux.py} +3 -3
  7. pyglet/config/__init__.py +101 -0
  8. pyglet/config/gl/__init__.py +30 -0
  9. pyglet/config/gl/egl.py +120 -0
  10. pyglet/config/gl/macos.py +262 -0
  11. pyglet/config/gl/windows.py +267 -0
  12. pyglet/config/gl/x11.py +142 -0
  13. pyglet/customtypes.py +43 -2
  14. pyglet/display/__init__.py +8 -6
  15. pyglet/display/base.py +3 -63
  16. pyglet/display/cocoa.py +12 -17
  17. pyglet/display/emscripten.py +39 -0
  18. pyglet/display/headless.py +23 -30
  19. pyglet/display/wayland.py +157 -0
  20. pyglet/display/win32.py +5 -21
  21. pyglet/display/xlib.py +19 -27
  22. pyglet/display/xlib_vidmoderestore.py +2 -2
  23. pyglet/enums.py +183 -0
  24. pyglet/event.py +0 -1
  25. pyglet/experimental/geoshader_sprite.py +15 -13
  26. pyglet/experimental/hidraw.py +6 -15
  27. pyglet/experimental/multitexture_sprite.py +31 -19
  28. pyglet/experimental/particles.py +13 -35
  29. pyglet/font/__init__.py +251 -85
  30. pyglet/font/base.py +116 -61
  31. pyglet/font/dwrite/__init__.py +349 -204
  32. pyglet/font/dwrite/dwrite_lib.py +27 -5
  33. pyglet/font/fontconfig.py +14 -6
  34. pyglet/font/freetype.py +138 -87
  35. pyglet/font/freetype_lib.py +19 -0
  36. pyglet/font/group.py +179 -0
  37. pyglet/font/harfbuzz/__init__.py +3 -3
  38. pyglet/font/pyodide_js.py +310 -0
  39. pyglet/font/quartz.py +319 -126
  40. pyglet/font/ttf.py +45 -3
  41. pyglet/font/user.py +14 -19
  42. pyglet/font/win32.py +45 -21
  43. pyglet/graphics/__init__.py +8 -787
  44. pyglet/graphics/allocation.py +115 -1
  45. pyglet/graphics/api/__init__.py +77 -0
  46. pyglet/graphics/api/base.py +299 -0
  47. pyglet/graphics/api/gl/__init__.py +58 -0
  48. pyglet/graphics/api/gl/base.py +24 -0
  49. pyglet/graphics/{vertexbuffer.py → api/gl/buffer.py} +104 -159
  50. pyglet/graphics/api/gl/cocoa/context.py +76 -0
  51. pyglet/graphics/api/gl/context.py +391 -0
  52. pyglet/graphics/api/gl/default_shaders.py +0 -0
  53. pyglet/graphics/api/gl/draw.py +627 -0
  54. pyglet/graphics/api/gl/egl/__init__.py +0 -0
  55. pyglet/graphics/api/gl/egl/context.py +92 -0
  56. pyglet/graphics/api/gl/enums.py +76 -0
  57. pyglet/graphics/api/gl/framebuffer.py +315 -0
  58. pyglet/graphics/api/gl/gl.py +5463 -0
  59. pyglet/graphics/api/gl/gl_info.py +188 -0
  60. pyglet/graphics/api/gl/global_opengl.py +226 -0
  61. pyglet/{gl → graphics/api/gl}/lib.py +34 -18
  62. pyglet/graphics/api/gl/shader.py +1476 -0
  63. pyglet/graphics/api/gl/shapes.py +55 -0
  64. pyglet/graphics/api/gl/sprite.py +102 -0
  65. pyglet/graphics/api/gl/state.py +219 -0
  66. pyglet/graphics/api/gl/text.py +190 -0
  67. pyglet/graphics/api/gl/texture.py +1526 -0
  68. pyglet/graphics/{vertexarray.py → api/gl/vertexarray.py} +11 -13
  69. pyglet/graphics/api/gl/vertexdomain.py +751 -0
  70. pyglet/graphics/api/gl/win32/__init__.py +0 -0
  71. pyglet/graphics/api/gl/win32/context.py +108 -0
  72. pyglet/graphics/api/gl/win32/wgl_info.py +24 -0
  73. pyglet/graphics/api/gl/xlib/__init__.py +0 -0
  74. pyglet/graphics/api/gl/xlib/context.py +174 -0
  75. pyglet/{gl → graphics/api/gl/xlib}/glx_info.py +26 -31
  76. pyglet/graphics/api/gl1/__init__.py +0 -0
  77. pyglet/{gl → graphics/api/gl1}/gl_compat.py +3 -2
  78. pyglet/graphics/api/gl2/__init__.py +0 -0
  79. pyglet/graphics/api/gl2/buffer.py +320 -0
  80. pyglet/graphics/api/gl2/draw.py +600 -0
  81. pyglet/graphics/api/gl2/global_opengl.py +122 -0
  82. pyglet/graphics/api/gl2/shader.py +200 -0
  83. pyglet/graphics/api/gl2/shapes.py +51 -0
  84. pyglet/graphics/api/gl2/sprite.py +79 -0
  85. pyglet/graphics/api/gl2/text.py +175 -0
  86. pyglet/graphics/api/gl2/vertexdomain.py +364 -0
  87. pyglet/graphics/api/webgl/__init__.py +233 -0
  88. pyglet/graphics/api/webgl/buffer.py +302 -0
  89. pyglet/graphics/api/webgl/context.py +234 -0
  90. pyglet/graphics/api/webgl/draw.py +590 -0
  91. pyglet/graphics/api/webgl/enums.py +76 -0
  92. pyglet/graphics/api/webgl/framebuffer.py +360 -0
  93. pyglet/graphics/api/webgl/gl.py +1537 -0
  94. pyglet/graphics/api/webgl/gl_info.py +130 -0
  95. pyglet/graphics/api/webgl/shader.py +1346 -0
  96. pyglet/graphics/api/webgl/shapes.py +92 -0
  97. pyglet/graphics/api/webgl/sprite.py +102 -0
  98. pyglet/graphics/api/webgl/state.py +227 -0
  99. pyglet/graphics/api/webgl/text.py +187 -0
  100. pyglet/graphics/api/webgl/texture.py +1227 -0
  101. pyglet/graphics/api/webgl/vertexarray.py +54 -0
  102. pyglet/graphics/api/webgl/vertexdomain.py +616 -0
  103. pyglet/graphics/api/webgl/webgl_js.pyi +307 -0
  104. pyglet/{image → graphics}/atlas.py +33 -32
  105. pyglet/graphics/base.py +10 -0
  106. pyglet/graphics/buffer.py +245 -0
  107. pyglet/graphics/draw.py +578 -0
  108. pyglet/graphics/framebuffer.py +26 -0
  109. pyglet/graphics/instance.py +178 -69
  110. pyglet/graphics/shader.py +267 -1553
  111. pyglet/graphics/state.py +83 -0
  112. pyglet/graphics/texture.py +703 -0
  113. pyglet/graphics/vertexdomain.py +695 -538
  114. pyglet/gui/ninepatch.py +10 -10
  115. pyglet/gui/widgets.py +120 -10
  116. pyglet/image/__init__.py +20 -1973
  117. pyglet/image/animation.py +12 -12
  118. pyglet/image/base.py +730 -0
  119. pyglet/image/codecs/__init__.py +9 -0
  120. pyglet/image/codecs/bmp.py +53 -30
  121. pyglet/image/codecs/dds.py +53 -31
  122. pyglet/image/codecs/gdiplus.py +38 -14
  123. pyglet/image/codecs/gdkpixbuf2.py +0 -2
  124. pyglet/image/codecs/js_image.py +99 -0
  125. pyglet/image/codecs/ktx2.py +161 -0
  126. pyglet/image/codecs/pil.py +1 -1
  127. pyglet/image/codecs/png.py +1 -1
  128. pyglet/image/codecs/wic.py +11 -2
  129. pyglet/info.py +26 -24
  130. pyglet/input/__init__.py +8 -0
  131. pyglet/input/base.py +163 -105
  132. pyglet/input/controller.py +13 -19
  133. pyglet/input/controller_db.py +39 -24
  134. pyglet/input/emscripten/__init__.py +18 -0
  135. pyglet/input/emscripten/gamepad_js.py +397 -0
  136. pyglet/input/linux/__init__.py +11 -5
  137. pyglet/input/linux/evdev.py +10 -11
  138. pyglet/input/linux/x11_xinput.py +2 -2
  139. pyglet/input/linux/x11_xinput_tablet.py +1 -1
  140. pyglet/input/macos/__init__.py +7 -2
  141. pyglet/input/macos/darwin_gc.py +559 -0
  142. pyglet/input/win32/__init__.py +1 -1
  143. pyglet/input/win32/directinput.py +34 -29
  144. pyglet/input/win32/xinput.py +11 -61
  145. pyglet/lib.py +3 -3
  146. pyglet/libs/__init__.py +1 -1
  147. pyglet/{gl → libs/darwin}/agl.py +1 -1
  148. pyglet/libs/darwin/cocoapy/__init__.py +2 -2
  149. pyglet/libs/darwin/cocoapy/cocoahelpers.py +181 -0
  150. pyglet/libs/darwin/cocoapy/cocoalibs.py +31 -0
  151. pyglet/libs/darwin/cocoapy/cocoatypes.py +27 -0
  152. pyglet/libs/darwin/cocoapy/runtime.py +81 -45
  153. pyglet/libs/darwin/coreaudio.py +4 -4
  154. pyglet/{gl → libs/darwin}/lib_agl.py +9 -8
  155. pyglet/libs/darwin/quartzkey.py +1 -3
  156. pyglet/libs/egl/__init__.py +2 -0
  157. pyglet/libs/egl/egl_lib.py +576 -0
  158. pyglet/libs/egl/eglext.py +51 -5
  159. pyglet/libs/linux/__init__.py +0 -0
  160. pyglet/libs/linux/egl/__init__.py +0 -0
  161. pyglet/libs/linux/egl/eglext.py +22 -0
  162. pyglet/libs/linux/glx/__init__.py +0 -0
  163. pyglet/{gl → libs/linux/glx}/glx.py +13 -14
  164. pyglet/{gl → libs/linux/glx}/glxext_arb.py +408 -192
  165. pyglet/{gl → libs/linux/glx}/glxext_mesa.py +1 -1
  166. pyglet/{gl → libs/linux/glx}/glxext_nv.py +345 -164
  167. pyglet/{gl → libs/linux/glx}/lib_glx.py +3 -2
  168. pyglet/libs/linux/wayland/__init__.py +0 -0
  169. pyglet/libs/linux/wayland/client.py +1068 -0
  170. pyglet/libs/linux/wayland/lib_wayland.py +207 -0
  171. pyglet/libs/linux/wayland/wayland_egl.py +38 -0
  172. pyglet/libs/{wayland → linux/wayland}/xkbcommon.py +26 -0
  173. pyglet/libs/{x11 → linux/x11}/xf86vmode.py +4 -4
  174. pyglet/libs/{x11 → linux/x11}/xinerama.py +2 -2
  175. pyglet/libs/{x11 → linux/x11}/xinput.py +10 -10
  176. pyglet/libs/linux/x11/xrandr.py +0 -0
  177. pyglet/libs/{x11 → linux/x11}/xrender.py +1 -1
  178. pyglet/libs/shared/__init__.py +0 -0
  179. pyglet/libs/shared/spirv/__init__.py +0 -0
  180. pyglet/libs/shared/spirv/lib_shaderc.py +85 -0
  181. pyglet/libs/shared/spirv/lib_spirv_cross.py +126 -0
  182. pyglet/libs/win32/__init__.py +28 -8
  183. pyglet/libs/win32/constants.py +59 -48
  184. pyglet/libs/win32/context_managers.py +20 -3
  185. pyglet/libs/win32/dinput.py +105 -88
  186. pyglet/{gl → libs/win32}/lib_wgl.py +52 -26
  187. pyglet/libs/win32/types.py +58 -23
  188. pyglet/{gl → libs/win32}/wgl.py +32 -25
  189. pyglet/{gl → libs/win32}/wglext_arb.py +364 -2
  190. pyglet/media/__init__.py +9 -10
  191. pyglet/media/codecs/__init__.py +12 -1
  192. pyglet/media/codecs/base.py +99 -96
  193. pyglet/media/codecs/ffmpeg.py +2 -2
  194. pyglet/media/codecs/ffmpeg_lib/libavformat.py +3 -8
  195. pyglet/media/codecs/webaudio_pyodide.py +111 -0
  196. pyglet/media/drivers/__init__.py +9 -4
  197. pyglet/media/drivers/base.py +4 -4
  198. pyglet/media/drivers/openal/__init__.py +1 -1
  199. pyglet/media/drivers/openal/adaptation.py +3 -3
  200. pyglet/media/drivers/pulse/__init__.py +1 -1
  201. pyglet/media/drivers/pulse/adaptation.py +3 -3
  202. pyglet/media/drivers/pyodide_js/__init__.py +8 -0
  203. pyglet/media/drivers/pyodide_js/adaptation.py +288 -0
  204. pyglet/media/drivers/xaudio2/adaptation.py +3 -3
  205. pyglet/media/player.py +276 -193
  206. pyglet/media/player_worker_thread.py +1 -1
  207. pyglet/model/__init__.py +39 -29
  208. pyglet/model/codecs/base.py +4 -4
  209. pyglet/model/codecs/gltf.py +3 -3
  210. pyglet/model/codecs/obj.py +71 -43
  211. pyglet/resource.py +129 -78
  212. pyglet/shapes.py +154 -194
  213. pyglet/sprite.py +47 -164
  214. pyglet/text/__init__.py +44 -54
  215. pyglet/text/caret.py +12 -7
  216. pyglet/text/document.py +19 -17
  217. pyglet/text/formats/html.py +2 -2
  218. pyglet/text/formats/structured.py +10 -40
  219. pyglet/text/layout/__init__.py +20 -13
  220. pyglet/text/layout/base.py +176 -287
  221. pyglet/text/layout/incremental.py +9 -10
  222. pyglet/text/layout/scrolling.py +7 -95
  223. pyglet/window/__init__.py +183 -172
  224. pyglet/window/cocoa/__init__.py +62 -51
  225. pyglet/window/cocoa/pyglet_delegate.py +2 -25
  226. pyglet/window/cocoa/pyglet_view.py +9 -8
  227. pyglet/window/dialog/__init__.py +184 -0
  228. pyglet/window/dialog/base.py +99 -0
  229. pyglet/window/dialog/darwin.py +121 -0
  230. pyglet/window/dialog/linux.py +72 -0
  231. pyglet/window/dialog/windows.py +194 -0
  232. pyglet/window/emscripten/__init__.py +779 -0
  233. pyglet/window/headless/__init__.py +44 -28
  234. pyglet/window/key.py +2 -0
  235. pyglet/window/mouse.py +2 -2
  236. pyglet/window/wayland/__init__.py +377 -0
  237. pyglet/window/win32/__init__.py +101 -46
  238. pyglet/window/xlib/__init__.py +104 -66
  239. {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
  240. pyglet-3.0.dev1.dist-info/RECORD +322 -0
  241. {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/WHEEL +1 -1
  242. pyglet/gl/__init__.py +0 -208
  243. pyglet/gl/base.py +0 -499
  244. pyglet/gl/cocoa.py +0 -309
  245. pyglet/gl/gl.py +0 -4625
  246. pyglet/gl/gl.pyi +0 -2320
  247. pyglet/gl/gl_compat.pyi +0 -3097
  248. pyglet/gl/gl_info.py +0 -190
  249. pyglet/gl/headless.py +0 -166
  250. pyglet/gl/wgl_info.py +0 -36
  251. pyglet/gl/wglext_nv.py +0 -1096
  252. pyglet/gl/win32.py +0 -268
  253. pyglet/gl/xlib.py +0 -295
  254. pyglet/image/buffer.py +0 -274
  255. pyglet/image/codecs/s3tc.py +0 -354
  256. pyglet/libs/x11/xrandr.py +0 -166
  257. pyglet-2.1.13.dist-info/RECORD +0 -234
  258. /pyglet/{libs/wayland → graphics/api/gl/cocoa}/__init__.py +0 -0
  259. /pyglet/libs/{egl → linux/egl}/egl.py +0 -0
  260. /pyglet/libs/{egl → linux/egl}/lib.py +0 -0
  261. /pyglet/libs/{ioctl.py → linux/ioctl.py} +0 -0
  262. /pyglet/libs/{wayland → linux/wayland}/gbm.py +0 -0
  263. /pyglet/libs/{x11 → linux/x11}/__init__.py +0 -0
  264. /pyglet/libs/{x11 → linux/x11}/cursorfont.py +0 -0
  265. /pyglet/libs/{x11 → linux/x11}/xlib.py +0 -0
  266. /pyglet/libs/{x11 → linux/x11}/xsync.py +0 -0
  267. {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 Player
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: 'Player') -> 'PulseAudioPlayer':
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: 'Player', driver: 'PulseAudioDriver') -> None:
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,8 @@
1
+ from . import adaptation
2
+
3
+
4
+ def create_audio_driver():
5
+ return adaptation.JSAudioDriver()
6
+
7
+
8
+ __all__ = ["create_audio_driver"]
@@ -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 Player
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: 'Player') -> 'XAudio2AudioPlayer':
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: 'Player') -> None:
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