pyglet 2.1.5__py3-none-any.whl → 2.1.8__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 +27 -42
- pyglet/app/base.py +2 -2
- pyglet/clock.py +1 -1
- pyglet/display/base.py +31 -21
- pyglet/display/cocoa.py +25 -1
- pyglet/display/headless.py +1 -1
- pyglet/display/win32.py +134 -18
- pyglet/display/xlib.py +285 -70
- pyglet/event.py +17 -1
- pyglet/experimental/README.md +1 -1
- pyglet/experimental/jobs.py +1 -1
- pyglet/experimental/multitexture_sprite.py +2 -2
- pyglet/font/__init__.py +1 -1
- pyglet/font/base.py +8 -5
- pyglet/font/dwrite/__init__.py +13 -8
- pyglet/font/dwrite/dwrite_lib.py +1 -1
- pyglet/font/user.py +1 -1
- pyglet/gl/base.py +8 -4
- pyglet/gl/cocoa.py +4 -0
- pyglet/gl/gl.py +4 -3
- pyglet/gl/gl.pyi +2320 -0
- pyglet/gl/gl_compat.py +7 -18
- pyglet/gl/gl_compat.pyi +3097 -0
- pyglet/gl/xlib.py +24 -0
- pyglet/graphics/shader.py +34 -20
- pyglet/graphics/vertexbuffer.py +1 -1
- pyglet/gui/frame.py +2 -2
- pyglet/gui/widgets.py +1 -1
- pyglet/image/__init__.py +3 -3
- pyglet/image/buffer.py +3 -3
- pyglet/input/base.py +8 -8
- pyglet/input/linux/evdev.py +1 -1
- pyglet/libs/darwin/cocoapy/cocoalibs.py +3 -1
- pyglet/libs/win32/__init__.py +12 -0
- pyglet/libs/win32/constants.py +4 -0
- pyglet/libs/win32/types.py +97 -0
- pyglet/libs/x11/xrandr.py +166 -0
- pyglet/libs/x11/xrender.py +43 -0
- pyglet/libs/x11/xsync.py +43 -0
- pyglet/math.py +40 -49
- pyglet/media/buffered_logger.py +1 -1
- pyglet/media/codecs/ffmpeg.py +18 -34
- pyglet/media/codecs/gstreamer.py +3 -3
- pyglet/media/codecs/pyogg.py +1 -1
- pyglet/media/codecs/wave.py +6 -0
- pyglet/media/codecs/wmf.py +33 -7
- pyglet/media/devices/win32.py +1 -1
- pyglet/media/drivers/base.py +1 -1
- pyglet/media/drivers/directsound/interface.py +4 -0
- pyglet/media/drivers/listener.py +2 -2
- pyglet/media/drivers/xaudio2/interface.py +6 -2
- pyglet/media/drivers/xaudio2/lib_xaudio2.py +1 -1
- pyglet/media/instrumentation.py +2 -2
- pyglet/media/player.py +2 -2
- pyglet/media/player_worker_thread.py +1 -1
- pyglet/media/synthesis.py +1 -1
- pyglet/model/codecs/gltf.py +1 -1
- pyglet/shapes.py +25 -24
- pyglet/sprite.py +1 -1
- pyglet/text/caret.py +44 -5
- pyglet/text/layout/base.py +3 -3
- pyglet/util.py +1 -1
- pyglet/window/__init__.py +54 -14
- pyglet/window/cocoa/__init__.py +27 -0
- pyglet/window/mouse.py +11 -1
- pyglet/window/win32/__init__.py +40 -14
- pyglet/window/xlib/__init__.py +21 -7
- {pyglet-2.1.5.dist-info → pyglet-2.1.8.dist-info}/METADATA +1 -1
- {pyglet-2.1.5.dist-info → pyglet-2.1.8.dist-info}/RECORD +71 -67
- {pyglet-2.1.5.dist-info → pyglet-2.1.8.dist-info}/LICENSE +0 -0
- {pyglet-2.1.5.dist-info → pyglet-2.1.8.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from ctypes import c_ulong, c_int, POINTER, Structure, c_char_p, c_uint, c_ushort
|
|
3
|
+
|
|
4
|
+
import pyglet
|
|
5
|
+
from pyglet.libs.x11.xlib import (
|
|
6
|
+
Time,
|
|
7
|
+
Window,
|
|
8
|
+
Display,
|
|
9
|
+
XCloseDisplay,
|
|
10
|
+
XDefaultRootWindow,
|
|
11
|
+
XOpenDisplay,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
lib = None
|
|
15
|
+
try:
|
|
16
|
+
lib = pyglet.lib.load_library("Xrandr")
|
|
17
|
+
except ImportError:
|
|
18
|
+
if pyglet.options.debug_lib:
|
|
19
|
+
warnings.warn("Xrandr could not be loaded.")
|
|
20
|
+
raise ImportError
|
|
21
|
+
|
|
22
|
+
RRCrtc = c_ulong # typedef XID
|
|
23
|
+
RROutput = c_ulong # typedef XID
|
|
24
|
+
RRMode = c_ulong # typedef XID
|
|
25
|
+
Connection = c_ushort # Connection in Xrandr.h
|
|
26
|
+
SubpixelOrder = c_ushort # SubpixelOrder in Xrandr.h
|
|
27
|
+
XRRModeFlags = c_ulong
|
|
28
|
+
|
|
29
|
+
class XRRModeInfo(Structure):
|
|
30
|
+
_fields_ = [
|
|
31
|
+
("id", RRMode), # mode ID
|
|
32
|
+
("width", c_uint), # horizontal resolution
|
|
33
|
+
("height", c_uint), # vertical resolution
|
|
34
|
+
("dotClock", c_ulong), # pixel clock (in Hz)
|
|
35
|
+
("hSyncStart", c_uint),
|
|
36
|
+
("hSyncEnd", c_uint),
|
|
37
|
+
("hTotal", c_uint),
|
|
38
|
+
("hSkew", c_uint),
|
|
39
|
+
("vSyncStart", c_uint),
|
|
40
|
+
("vSyncEnd", c_uint),
|
|
41
|
+
("vTotal", c_uint),
|
|
42
|
+
("name", c_char_p),
|
|
43
|
+
("nameLength", c_uint),
|
|
44
|
+
("modeFlags", XRRModeFlags),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class XRRScreenResources(Structure):
|
|
49
|
+
_fields_ = [
|
|
50
|
+
("timestamp", Time),
|
|
51
|
+
("configTimestamp", Time),
|
|
52
|
+
("ncrtc", c_int),
|
|
53
|
+
("crtcs", POINTER(RRCrtc)),
|
|
54
|
+
("noutput", c_int),
|
|
55
|
+
("outputs", POINTER(RROutput)),
|
|
56
|
+
("nmode", c_int),
|
|
57
|
+
("modes", POINTER(XRRModeInfo)),
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class XRROutputInfo(Structure):
|
|
62
|
+
_fields_ = [
|
|
63
|
+
("timestamp", Time),
|
|
64
|
+
("crtc", RRCrtc),
|
|
65
|
+
("name", c_char_p),
|
|
66
|
+
("nameLen", c_int),
|
|
67
|
+
("mm_width", c_ulong),
|
|
68
|
+
("mm_height", c_ulong),
|
|
69
|
+
("connection", Connection),
|
|
70
|
+
("subpixel_order", SubpixelOrder),
|
|
71
|
+
("ncrtc", c_int),
|
|
72
|
+
("crtcs", POINTER(RRCrtc)),
|
|
73
|
+
("nclone", c_int),
|
|
74
|
+
("clones", POINTER(RROutput)),
|
|
75
|
+
("nmode", c_int),
|
|
76
|
+
("npreferred", c_int),
|
|
77
|
+
("modes", POINTER(RRMode)),
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
class XRRCrtcInfo(Structure):
|
|
81
|
+
_fields_ = [
|
|
82
|
+
("timestamp", Time),
|
|
83
|
+
("x", c_int),
|
|
84
|
+
("y", c_int),
|
|
85
|
+
("width", c_uint),
|
|
86
|
+
("height", c_uint),
|
|
87
|
+
("mode", RRMode),
|
|
88
|
+
("rotation", c_int),
|
|
89
|
+
("noutput", c_int),
|
|
90
|
+
("outputs", POINTER(RROutput)),
|
|
91
|
+
("rotations", c_ushort),
|
|
92
|
+
("npossible", c_int),
|
|
93
|
+
("possible", POINTER(RROutput)),
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if lib:
|
|
98
|
+
XRRQueryVersion = lib.XRRQueryVersion
|
|
99
|
+
XRRQueryVersion.argtypes = [POINTER(Display), POINTER(c_int), POINTER(c_int)]
|
|
100
|
+
XRRQueryVersion.restype = c_int
|
|
101
|
+
|
|
102
|
+
XRRGetScreenResources = lib.XRRGetScreenResources
|
|
103
|
+
XRRGetScreenResources.argtypes = [POINTER(Display), Window]
|
|
104
|
+
XRRGetScreenResources.restype = POINTER(XRRScreenResources)
|
|
105
|
+
|
|
106
|
+
XRRGetOutputPrimary = lib.XRRGetOutputPrimary
|
|
107
|
+
XRRGetOutputPrimary.argtypes = [POINTER(Display), Window]
|
|
108
|
+
XRRGetOutputPrimary.restype = RROutput
|
|
109
|
+
|
|
110
|
+
XRRGetScreenResourcesCurrent = lib.XRRGetScreenResourcesCurrent
|
|
111
|
+
XRRGetScreenResourcesCurrent.argtypes = [POINTER(Display), Window]
|
|
112
|
+
XRRGetScreenResourcesCurrent.restype = POINTER(XRRScreenResources)
|
|
113
|
+
|
|
114
|
+
XRRFreeScreenResources = lib.XRRFreeScreenResources
|
|
115
|
+
XRRFreeScreenResources.argtypes = [POINTER(XRRScreenResources)]
|
|
116
|
+
XRRFreeScreenResources.restype = None
|
|
117
|
+
|
|
118
|
+
XRRGetOutputInfo = lib.XRRGetOutputInfo
|
|
119
|
+
XRRGetOutputInfo.argtypes = [POINTER(Display), POINTER(XRRScreenResources), RROutput]
|
|
120
|
+
XRRGetOutputInfo.restype = POINTER(XRROutputInfo)
|
|
121
|
+
|
|
122
|
+
XRRFreeOutputInfo = lib.XRRFreeOutputInfo
|
|
123
|
+
XRRFreeOutputInfo.argtypes = [POINTER(XRROutputInfo)]
|
|
124
|
+
XRRFreeOutputInfo.restype = None
|
|
125
|
+
|
|
126
|
+
XRRGetCrtcInfo = lib.XRRGetCrtcInfo
|
|
127
|
+
XRRGetCrtcInfo.argtypes = [POINTER(Display), POINTER(XRRScreenResources), RRCrtc]
|
|
128
|
+
XRRGetCrtcInfo.restype = POINTER(XRRCrtcInfo)
|
|
129
|
+
|
|
130
|
+
XRRSetCrtcConfig = lib.XRRSetCrtcConfig
|
|
131
|
+
XRRSetCrtcConfig.argtypes = argtypes = [POINTER(Display), POINTER(XRRScreenResources), RRCrtc, Time, c_int, c_int, RRMode, c_int, POINTER(RROutput), c_int]
|
|
132
|
+
XRRSetCrtcConfig.restype = c_int
|
|
133
|
+
|
|
134
|
+
XRRFreeCrtcInfo = lib.XRRFreeCrtcInfo
|
|
135
|
+
XRRFreeCrtcInfo.argtypes = [POINTER(XRRCrtcInfo)]
|
|
136
|
+
XRRFreeCrtcInfo.restype = None
|
|
137
|
+
|
|
138
|
+
def list_connected_outputs():
|
|
139
|
+
dpy = XOpenDisplay(None)
|
|
140
|
+
if not dpy:
|
|
141
|
+
raise RuntimeError("Cannot open DISPLAY")
|
|
142
|
+
|
|
143
|
+
root = XDefaultRootWindow(dpy)
|
|
144
|
+
res_p = XRRGetScreenResources(dpy, root)
|
|
145
|
+
if not res_p:
|
|
146
|
+
XCloseDisplay(dpy)
|
|
147
|
+
raise RuntimeError("Failed to get screen resources")
|
|
148
|
+
|
|
149
|
+
res = res_p.contents
|
|
150
|
+
outputs = []
|
|
151
|
+
for i in range(res.noutput):
|
|
152
|
+
out_id = res.outputs[i]
|
|
153
|
+
info_p = XRRGetOutputInfo(dpy, res_p, out_id)
|
|
154
|
+
if info_p:
|
|
155
|
+
info = info_p.contents
|
|
156
|
+
if info.connection == 0: # Connected.
|
|
157
|
+
outputs.append(info.name.decode())
|
|
158
|
+
XRRFreeOutputInfo(info_p)
|
|
159
|
+
|
|
160
|
+
XRRFreeScreenResources(res_p)
|
|
161
|
+
XCloseDisplay(dpy)
|
|
162
|
+
return outputs
|
|
163
|
+
|
|
164
|
+
if __name__ == "__main__":
|
|
165
|
+
for name in list_connected_outputs():
|
|
166
|
+
print(name)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from ctypes import Structure, c_ushort, c_ulong, c_int, c_void_p, POINTER
|
|
5
|
+
import pyglet.lib
|
|
6
|
+
from pyglet.libs.x11.xlib import Visual
|
|
7
|
+
|
|
8
|
+
lib = None
|
|
9
|
+
try:
|
|
10
|
+
lib = pyglet.lib.load_library("Xrender")
|
|
11
|
+
except ImportError:
|
|
12
|
+
if pyglet.options.debug_lib:
|
|
13
|
+
warnings.warn("XRender could not be loaded.")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class XRenderDirectFormat(Structure):
|
|
17
|
+
_fields_ = [
|
|
18
|
+
('red', c_ushort),
|
|
19
|
+
('redMask', c_ushort),
|
|
20
|
+
('green', c_ushort),
|
|
21
|
+
('greenMask', c_ushort),
|
|
22
|
+
('blue', c_ushort),
|
|
23
|
+
('blueMask', c_ushort),
|
|
24
|
+
('alpha', c_ushort),
|
|
25
|
+
('alphaMask', c_ushort),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
class XRenderPictFormat(Structure):
|
|
29
|
+
_fields_ = [
|
|
30
|
+
('id', c_ulong),
|
|
31
|
+
('type', c_int),
|
|
32
|
+
('depth', c_int),
|
|
33
|
+
('direct', XRenderDirectFormat),
|
|
34
|
+
('colormap', c_ulong),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
# XRenderFindVisualFormat(Display *dpy, Visual *visual)
|
|
38
|
+
try:
|
|
39
|
+
XRenderFindVisualFormat = lib.XRenderFindVisualFormat
|
|
40
|
+
XRenderFindVisualFormat.argtypes = [c_void_p, POINTER(Visual)]
|
|
41
|
+
XRenderFindVisualFormat.restype = POINTER(XRenderPictFormat)
|
|
42
|
+
except ValueError:
|
|
43
|
+
XRenderFindVisualFormat = None
|
pyglet/libs/x11/xsync.py
CHANGED
|
@@ -406,6 +406,49 @@ XSyncGetPriority = _lib.XSyncGetPriority
|
|
|
406
406
|
XSyncGetPriority.restype = c_int
|
|
407
407
|
XSyncGetPriority.argtypes = [POINTER(Display), XID, POINTER(c_int)]
|
|
408
408
|
|
|
409
|
+
# Shape kind
|
|
410
|
+
ShapeBounding = 0
|
|
411
|
+
ShapeClip = 1
|
|
412
|
+
ShapeInput = 2
|
|
413
|
+
|
|
414
|
+
# Shape operation
|
|
415
|
+
ShapeSet = 0
|
|
416
|
+
ShapeUnion = 1
|
|
417
|
+
ShapeIntersect = 2
|
|
418
|
+
ShapeSubtract = 3
|
|
419
|
+
ShapeInvert = 4
|
|
420
|
+
|
|
421
|
+
XShapeCombineRegion = _lib.XShapeCombineRegion
|
|
422
|
+
XShapeCombineRegion.argtypes = [
|
|
423
|
+
POINTER(Display),
|
|
424
|
+
c_void_p,
|
|
425
|
+
ctypes.c_int, # shape kind
|
|
426
|
+
ctypes.c_int, ctypes.c_int, # x, y offset
|
|
427
|
+
c_void_p,
|
|
428
|
+
ctypes.c_int # ShapeOp
|
|
429
|
+
]
|
|
430
|
+
|
|
431
|
+
XShapeCombineMask = _lib.XShapeCombineMask
|
|
432
|
+
XShapeCombineMask.argtypes = [
|
|
433
|
+
Display, # *display
|
|
434
|
+
c_void_p, # dest window
|
|
435
|
+
ctypes.c_int, # shape_kind (e.g., ShapeInput)
|
|
436
|
+
ctypes.c_int, # x offset
|
|
437
|
+
ctypes.c_int, # y offset
|
|
438
|
+
ctypes.c_ulong, # Pixmap (can be 0 for None)
|
|
439
|
+
ctypes.c_int # ShapeOp (e.g., ShapeSet)
|
|
440
|
+
]
|
|
441
|
+
XShapeCombineMask.restype = None
|
|
442
|
+
|
|
443
|
+
XShapeQueryExtension = _lib.XShapeQueryExtension
|
|
444
|
+
XShapeQueryExtension.argtypes = [Display, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)]
|
|
445
|
+
XShapeQueryExtension.restype = Bool
|
|
446
|
+
|
|
447
|
+
def has_shape_support(display: Display) -> bool:
|
|
448
|
+
event_base = ctypes.c_int()
|
|
449
|
+
error_base = ctypes.c_int()
|
|
450
|
+
return XShapeQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
|
|
451
|
+
|
|
409
452
|
|
|
410
453
|
__all__ = ['SYNC_MAJOR_VERSION', 'SYNC_MINOR_VERSION', 'X_SyncInitialize',
|
|
411
454
|
'X_SyncListSystemCounters', 'X_SyncCreateCounter', 'X_SyncSetCounter',
|
pyglet/math.py
CHANGED
|
@@ -191,7 +191,7 @@ class Vec2(_typing.NamedTuple):
|
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
def __lt__(self, other: tuple[float, float]) -> bool:
|
|
194
|
-
return self[0] ** 2 + self[
|
|
194
|
+
return self[0] ** 2 + self[1] ** 2 < other[0] ** 2 + other[1] ** 2
|
|
195
195
|
|
|
196
196
|
@staticmethod
|
|
197
197
|
def from_heading(heading: float, length: float = 1.0) -> Vec2:
|
|
@@ -301,8 +301,7 @@ class Vec2(_typing.NamedTuple):
|
|
|
301
301
|
This simply means the vector will have a length of 1.0. If the vector
|
|
302
302
|
has a length of 0, the original vector will be returned.
|
|
303
303
|
"""
|
|
304
|
-
d
|
|
305
|
-
if d:
|
|
304
|
+
if d := _math.sqrt(self[0] ** 2 + self[1] ** 2):
|
|
306
305
|
return Vec2(self[0] / d, self[1] / d)
|
|
307
306
|
return self
|
|
308
307
|
|
|
@@ -823,7 +822,8 @@ class Vec4(_typing.NamedTuple):
|
|
|
823
822
|
)
|
|
824
823
|
|
|
825
824
|
def __lt__(self, other: Vec4 | tuple[float, float, float, float]) -> bool:
|
|
826
|
-
return self[0] ** 2 + self[1] ** 2 + self[2] ** 2
|
|
825
|
+
return (self[0] ** 2 + self[1] ** 2 + self[2] ** 2 + self[3] ** 2 <
|
|
826
|
+
other[0] ** 2 + other[1] ** 2 + other[2] ** 2 + other[3] ** 2)
|
|
827
827
|
|
|
828
828
|
def length(self) -> float:
|
|
829
829
|
"""Calculate the length of the vector: ``sqrt(x ** 2 + y ** 2 + z ** 2 + w ** 2)``."""
|
|
@@ -872,8 +872,7 @@ class Vec4(_typing.NamedTuple):
|
|
|
872
872
|
This means that the vector will have the same direction, but a length of 1.0.
|
|
873
873
|
If the vector has a length of 0, the original vector will be returned.
|
|
874
874
|
"""
|
|
875
|
-
d
|
|
876
|
-
if d:
|
|
875
|
+
if d := _math.sqrt(self[0] ** 2 + self[1] ** 2 + self[2] ** 2 + self[3] ** 2):
|
|
877
876
|
return Vec4(self[0] / d, self[1] / d, self[2] / d, self[3] / d)
|
|
878
877
|
return self
|
|
879
878
|
|
|
@@ -1053,7 +1052,21 @@ class Mat3(_typing.NamedTuple):
|
|
|
1053
1052
|
def __matmul__(self, other: Mat3) -> Mat3: ...
|
|
1054
1053
|
|
|
1055
1054
|
def __matmul__(self, other) -> Vec3 | Mat3:
|
|
1056
|
-
|
|
1055
|
+
try:
|
|
1056
|
+
# extract the elements in row-column form. (matrix is stored column first)
|
|
1057
|
+
a11, a12, a13, a21, a22, a23, a31, a32, a33 = self
|
|
1058
|
+
b11, b12, b13, b21, b22, b23, b31, b32, b33 = other
|
|
1059
|
+
|
|
1060
|
+
# Multiply and sum rows * columns
|
|
1061
|
+
return Mat3(
|
|
1062
|
+
# Column 1
|
|
1063
|
+
a11 * b11 + a21 * b12 + a31 * b13, a12 * b11 + a22 * b12 + a32 * b13, a13 * b11 + a23 * b12 + a33 * b13,
|
|
1064
|
+
# Column 2
|
|
1065
|
+
a11 * b21 + a21 * b22 + a31 * b23, a12 * b21 + a22 * b22 + a32 * b23, a13 * b21 + a23 * b22 + a33 * b23,
|
|
1066
|
+
# Column 3
|
|
1067
|
+
a11 * b31 + a21 * b32 + a31 * b33, a12 * b31 + a22 * b32 + a32 * b33, a13 * b31 + a23 * b32 + a33 * b33,
|
|
1068
|
+
)
|
|
1069
|
+
except ValueError:
|
|
1057
1070
|
x, y, z = other
|
|
1058
1071
|
# extract the elements in row-column form. (matrix is stored column first)
|
|
1059
1072
|
a11, a12, a13, a21, a22, a23, a31, a32, a33 = self
|
|
@@ -1063,24 +1076,6 @@ class Mat3(_typing.NamedTuple):
|
|
|
1063
1076
|
a13 * x + a23 * y + a33 * z,
|
|
1064
1077
|
)
|
|
1065
1078
|
|
|
1066
|
-
if not isinstance(other, Mat3):
|
|
1067
|
-
msg = "Can only multiply with Mat3 or Vec3 types"
|
|
1068
|
-
raise TypeError(msg)
|
|
1069
|
-
|
|
1070
|
-
# extract the elements in row-column form. (matrix is stored column first)
|
|
1071
|
-
a11, a12, a13, a21, a22, a23, a31, a32, a33 = self
|
|
1072
|
-
b11, b12, b13, b21, b22, b23, b31, b32, b33 = other
|
|
1073
|
-
|
|
1074
|
-
# Multiply and sum rows * columns
|
|
1075
|
-
return Mat3(
|
|
1076
|
-
# Column 1
|
|
1077
|
-
a11 * b11 + a21 * b12 + a31 * b13, a12 * b11 + a22 * b12 + a32 * b13, a13 * b11 + a23 * b12 + a33 * b13,
|
|
1078
|
-
# Column 2
|
|
1079
|
-
a11 * b21 + a21 * b22 + a31 * b23, a12 * b21 + a22 * b22 + a32 * b23, a13 * b21 + a23 * b22 + a33 * b23,
|
|
1080
|
-
# Column 3
|
|
1081
|
-
a11 * b31 + a21 * b32 + a31 * b33, a12 * b31 + a22 * b32 + a32 * b33, a13 * b31 + a23 * b32 + a33 * b33,
|
|
1082
|
-
)
|
|
1083
|
-
|
|
1084
1079
|
def __repr__(self) -> str:
|
|
1085
1080
|
return f"{self.__class__.__name__}{self[0:3]}\n {self[3:6]}\n {self[6:9]}"
|
|
1086
1081
|
|
|
@@ -1357,7 +1352,26 @@ class Mat4(_typing.NamedTuple):
|
|
|
1357
1352
|
def __matmul__(self, other: Mat4) -> Mat4: ...
|
|
1358
1353
|
|
|
1359
1354
|
def __matmul__(self, other):
|
|
1360
|
-
|
|
1355
|
+
try:
|
|
1356
|
+
# extract the elements in row-column form. (matrix is stored column first)
|
|
1357
|
+
a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44 = self
|
|
1358
|
+
b11, b12, b13, b14, b21, b22, b23, b24, b31, b32, b33, b34, b41, b42, b43, b44 = other
|
|
1359
|
+
# Multiply and sum rows * columns:
|
|
1360
|
+
return Mat4(
|
|
1361
|
+
# Column 1
|
|
1362
|
+
a11 * b11 + a21 * b12 + a31 * b13 + a41 * b14, a12 * b11 + a22 * b12 + a32 * b13 + a42 * b14,
|
|
1363
|
+
a13 * b11 + a23 * b12 + a33 * b13 + a43 * b14, a14 * b11 + a24 * b12 + a34 * b13 + a44 * b14,
|
|
1364
|
+
# Column 2
|
|
1365
|
+
a11 * b21 + a21 * b22 + a31 * b23 + a41 * b24, a12 * b21 + a22 * b22 + a32 * b23 + a42 * b24,
|
|
1366
|
+
a13 * b21 + a23 * b22 + a33 * b23 + a43 * b24, a14 * b21 + a24 * b22 + a34 * b23 + a44 * b24,
|
|
1367
|
+
# Column 3
|
|
1368
|
+
a11 * b31 + a21 * b32 + a31 * b33 + a41 * b34, a12 * b31 + a22 * b32 + a32 * b33 + a42 * b34,
|
|
1369
|
+
a13 * b31 + a23 * b32 + a33 * b33 + a43 * b34, a14 * b31 + a24 * b32 + a34 * b33 + a44 * b34,
|
|
1370
|
+
# Column 4
|
|
1371
|
+
a11 * b41 + a21 * b42 + a31 * b43 + a41 * b44, a12 * b41 + a22 * b42 + a32 * b43 + a42 * b44,
|
|
1372
|
+
a13 * b41 + a23 * b42 + a33 * b43 + a43 * b44, a14 * b41 + a24 * b42 + a34 * b43 + a44 * b44,
|
|
1373
|
+
)
|
|
1374
|
+
except ValueError:
|
|
1361
1375
|
x, y, z, w = other
|
|
1362
1376
|
# extract the elements in row-column form. (matrix is stored column first)
|
|
1363
1377
|
a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44 = self
|
|
@@ -1368,29 +1382,6 @@ class Mat4(_typing.NamedTuple):
|
|
|
1368
1382
|
x * a14 + y * a24 + z * a34 + w * a44,
|
|
1369
1383
|
)
|
|
1370
1384
|
|
|
1371
|
-
if not isinstance(other, Mat4):
|
|
1372
|
-
msg = "Can only multiply with Mat4 or Vec4 types"
|
|
1373
|
-
raise TypeError(msg)
|
|
1374
|
-
|
|
1375
|
-
# extract the elements in row-column form. (matrix is stored column first)
|
|
1376
|
-
a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44 = self
|
|
1377
|
-
b11, b12, b13, b14, b21, b22, b23, b24, b31, b32, b33, b34, b41, b42, b43, b44 = other
|
|
1378
|
-
# Multiply and sum rows * columns:
|
|
1379
|
-
return Mat4(
|
|
1380
|
-
# Column 1
|
|
1381
|
-
a11 * b11 + a21 * b12 + a31 * b13 + a41 * b14, a12 * b11 + a22 * b12 + a32 * b13 + a42 * b14,
|
|
1382
|
-
a13 * b11 + a23 * b12 + a33 * b13 + a43 * b14, a14 * b11 + a24 * b12 + a34 * b13 + a44 * b14,
|
|
1383
|
-
# Column 2
|
|
1384
|
-
a11 * b21 + a21 * b22 + a31 * b23 + a41 * b24, a12 * b21 + a22 * b22 + a32 * b23 + a42 * b24,
|
|
1385
|
-
a13 * b21 + a23 * b22 + a33 * b23 + a43 * b24, a14 * b21 + a24 * b22 + a34 * b23 + a44 * b24,
|
|
1386
|
-
# Column 3
|
|
1387
|
-
a11 * b31 + a21 * b32 + a31 * b33 + a41 * b34, a12 * b31 + a22 * b32 + a32 * b33 + a42 * b34,
|
|
1388
|
-
a13 * b31 + a23 * b32 + a33 * b33 + a43 * b34, a14 * b31 + a24 * b32 + a34 * b33 + a44 * b34,
|
|
1389
|
-
# Column 4
|
|
1390
|
-
a11 * b41 + a21 * b42 + a31 * b43 + a41 * b44, a12 * b41 + a22 * b42 + a32 * b43 + a42 * b44,
|
|
1391
|
-
a13 * b41 + a23 * b42 + a33 * b43 + a43 * b44, a14 * b41 + a24 * b42 + a34 * b43 + a44 * b44,
|
|
1392
|
-
)
|
|
1393
|
-
|
|
1394
1385
|
def __repr__(self) -> str:
|
|
1395
1386
|
return f"{self.__class__.__name__}{self[0:4]}\n {self[4:8]}\n {self[8:12]}\n {self[12:16]}"
|
|
1396
1387
|
|
pyglet/media/buffered_logger.py
CHANGED
pyglet/media/codecs/ffmpeg.py
CHANGED
|
@@ -126,7 +126,7 @@ class FFmpegException(MediaFormatException):
|
|
|
126
126
|
def ffmpeg_get_audio_buffer_size(audio_format):
|
|
127
127
|
"""Return the audio buffer size
|
|
128
128
|
|
|
129
|
-
Buffer size can
|
|
129
|
+
Buffer size can accommodate 1 sec of audio data.
|
|
130
130
|
"""
|
|
131
131
|
return audio_format.bytes_per_second + FF_INPUT_BUFFER_PADDING_SIZE
|
|
132
132
|
|
|
@@ -385,16 +385,6 @@ def ffmpeg_stream_info(file: FFmpegFile, stream_index: int) -> StreamAudioInfo |
|
|
|
385
385
|
context.sample_rate,
|
|
386
386
|
channel_count,
|
|
387
387
|
)
|
|
388
|
-
if context.format in (AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P):
|
|
389
|
-
info.sample_bits = 8
|
|
390
|
-
elif context.format in (AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
|
|
391
|
-
AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP):
|
|
392
|
-
info.sample_bits = 16
|
|
393
|
-
elif context.format in (AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P):
|
|
394
|
-
info.sample_bits = 32
|
|
395
|
-
else:
|
|
396
|
-
info.sample_format = None
|
|
397
|
-
info.sample_bits = None
|
|
398
388
|
else:
|
|
399
389
|
return None
|
|
400
390
|
return info
|
|
@@ -466,7 +456,7 @@ def ffmpeg_seek_file(file: FFmpegFile, timestamp: float) -> None:
|
|
|
466
456
|
buf = create_string_buffer(128)
|
|
467
457
|
avutil.av_strerror(result, buf, 128)
|
|
468
458
|
descr = buf.value
|
|
469
|
-
raise FFmpegException('Error
|
|
459
|
+
raise FFmpegException('Error occurred while seeking. ' +
|
|
470
460
|
descr.decode())
|
|
471
461
|
|
|
472
462
|
|
|
@@ -634,35 +624,29 @@ class FFmpegSource(StreamingSource):
|
|
|
634
624
|
self._video_stream = stream
|
|
635
625
|
self._video_stream_index = i
|
|
636
626
|
|
|
637
|
-
elif isinstance(info, StreamAudioInfo) and
|
|
627
|
+
elif isinstance(info, StreamAudioInfo) and self._audio_stream is None:
|
|
638
628
|
stream = ffmpeg_open_stream(self._file, i)
|
|
639
629
|
|
|
640
|
-
self.audio_format = AudioFormat(
|
|
641
|
-
channels=min(2, info.channels),
|
|
642
|
-
sample_size=info.sample_bits,
|
|
643
|
-
sample_rate=info.sample_rate)
|
|
644
|
-
self._audio_stream = stream
|
|
645
|
-
self._audio_stream_index = i
|
|
646
|
-
|
|
647
|
-
channel_input = self._get_default_channel_layout(info.channels)
|
|
648
630
|
channels_out = min(2, info.channels)
|
|
631
|
+
channel_input = self._get_default_channel_layout(info.channels)
|
|
649
632
|
channel_output = self._get_default_channel_layout(channels_out)
|
|
650
633
|
|
|
651
|
-
|
|
652
|
-
sample_format
|
|
653
|
-
|
|
654
|
-
if sample_format in (AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P):
|
|
634
|
+
sample_bits = info.sample_bits
|
|
635
|
+
if info.sample_format in (AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P):
|
|
655
636
|
self.tgt_format = AV_SAMPLE_FMT_U8
|
|
656
|
-
elif sample_format in (AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P):
|
|
657
|
-
self.tgt_format = AV_SAMPLE_FMT_S16
|
|
658
|
-
elif sample_format in (AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P):
|
|
659
|
-
self.tgt_format = AV_SAMPLE_FMT_S32
|
|
660
|
-
elif sample_format in (AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP):
|
|
661
|
-
self.tgt_format = AV_SAMPLE_FMT_S16
|
|
662
637
|
else:
|
|
663
|
-
|
|
638
|
+
# No matter the input format, produce S16 samples.
|
|
639
|
+
sample_bits = 16
|
|
640
|
+
self.tgt_format = AV_SAMPLE_FMT_S16
|
|
641
|
+
|
|
642
|
+
self.audio_format = AudioFormat(
|
|
643
|
+
channels=channels_out,
|
|
644
|
+
sample_size=sample_bits,
|
|
645
|
+
sample_rate=info.sample_rate)
|
|
646
|
+
self._audio_stream = stream
|
|
647
|
+
self._audio_stream_index = i
|
|
664
648
|
|
|
665
|
-
self.audio_convert_ctx = self.get_formatted_swr_context(channel_output, sample_rate, channel_input, sample_format)
|
|
649
|
+
self.audio_convert_ctx = self.get_formatted_swr_context(channel_output, info.sample_rate, channel_input, info.sample_format)
|
|
666
650
|
if not self.audio_convert_ctx:
|
|
667
651
|
swresample.swr_free(self.audio_convert_ctx)
|
|
668
652
|
raise FFmpegException('Cannot create sample rate converter.')
|
|
@@ -676,7 +660,7 @@ class FFmpegSource(StreamingSource):
|
|
|
676
660
|
self._events = [] # They don't seem to be used!
|
|
677
661
|
|
|
678
662
|
self.audioq = deque()
|
|
679
|
-
# Make queue big enough to
|
|
663
|
+
# Make queue big enough to accommodate 1.2 sec?
|
|
680
664
|
self._max_len_audioq = self.MAX_QUEUE_SIZE # Need to figure out a correct amount
|
|
681
665
|
if self.audio_format:
|
|
682
666
|
# Buffer 1 sec worth of audio
|
pyglet/media/codecs/gstreamer.py
CHANGED
|
@@ -48,7 +48,7 @@ class _MessageHandler:
|
|
|
48
48
|
"""The main message callback"""
|
|
49
49
|
if message.type == Gst.MessageType.EOS:
|
|
50
50
|
|
|
51
|
-
self.source.queue.put(self.source.
|
|
51
|
+
self.source.queue.put(self.source.sentinel)
|
|
52
52
|
if not self.source.caps:
|
|
53
53
|
raise GStreamerDecodeException("Appears to be an unsupported file")
|
|
54
54
|
|
|
@@ -105,7 +105,7 @@ class _MessageHandler:
|
|
|
105
105
|
class GStreamerSource(StreamingSource):
|
|
106
106
|
|
|
107
107
|
source_instances = weakref.WeakSet()
|
|
108
|
-
|
|
108
|
+
sentinel = object()
|
|
109
109
|
|
|
110
110
|
def __init__(self, filename, file=None):
|
|
111
111
|
self._pipeline = Gst.Pipeline()
|
|
@@ -199,7 +199,7 @@ class GStreamerSource(StreamingSource):
|
|
|
199
199
|
data = bytes()
|
|
200
200
|
while len(data) < num_bytes:
|
|
201
201
|
packet = self.queue.get()
|
|
202
|
-
if packet == self.
|
|
202
|
+
if packet == self.sentinel:
|
|
203
203
|
self._finished.set()
|
|
204
204
|
break
|
|
205
205
|
data += packet
|
pyglet/media/codecs/pyogg.py
CHANGED
|
@@ -287,7 +287,7 @@ class MemoryFLACFileStream(UnclosedFLACFileStream):
|
|
|
287
287
|
|
|
288
288
|
metadata_status = pyogg.flac.FLAC__stream_decoder_process_until_end_of_metadata(self.decoder)
|
|
289
289
|
if not metadata_status: # error
|
|
290
|
-
raise DecodeException("An error
|
|
290
|
+
raise DecodeException("An error occurred when trying to decode the metadata of {}".format(path))
|
|
291
291
|
|
|
292
292
|
def read_callback(self, decoder, buffer, size, data):
|
|
293
293
|
chunk = size.contents.value
|
pyglet/media/codecs/wave.py
CHANGED
|
@@ -25,6 +25,12 @@ class WaveSource(StreamingSource):
|
|
|
25
25
|
|
|
26
26
|
nchannels, sampwidth, framerate, nframes, comptype, compname = self._wave.getparams()
|
|
27
27
|
|
|
28
|
+
if nchannels not in (1, 2):
|
|
29
|
+
raise WAVEDecodeException(f"incompatible channel count {nchannels}")
|
|
30
|
+
|
|
31
|
+
if sampwidth not in (1, 2):
|
|
32
|
+
raise WAVEDecodeException(f"incompatible sample width {sampwidth}")
|
|
33
|
+
|
|
28
34
|
self.audio_format = AudioFormat(channels=nchannels, sample_size=sampwidth * 8, sample_rate=framerate)
|
|
29
35
|
|
|
30
36
|
self._bytes_per_frame = nchannels * sampwidth
|
pyglet/media/codecs/wmf.py
CHANGED
|
@@ -539,19 +539,45 @@ class WMFSource(Source):
|
|
|
539
539
|
self._source_reader.SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, True)
|
|
540
540
|
|
|
541
541
|
# Check sub media type, AKA what kind of codec
|
|
542
|
-
|
|
543
|
-
|
|
542
|
+
source_subtype_guid = com.GUID(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
543
|
+
source_sample_size = c_uint32()
|
|
544
|
+
source_channel_count = c_uint32()
|
|
544
545
|
|
|
545
|
-
|
|
546
|
-
|
|
546
|
+
imfmedia.GetGUID(MF_MT_SUBTYPE, byref(source_subtype_guid))
|
|
547
|
+
try:
|
|
548
|
+
# Some formats such as mp3 do not report this value
|
|
549
|
+
imfmedia.GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, byref(source_sample_size))
|
|
550
|
+
except OSError:
|
|
551
|
+
source_sample_size.value = 0
|
|
552
|
+
imfmedia.GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, byref(source_channel_count))
|
|
553
|
+
|
|
554
|
+
if (
|
|
555
|
+
source_subtype_guid == MFAudioFormat_PCM and
|
|
556
|
+
source_sample_size.value in (8, 16) and
|
|
557
|
+
source_channel_count.value in (1, 2)
|
|
558
|
+
):
|
|
559
|
+
assert _debug(f'WMFAudioDecoder: Found compatible Integer PCM Audio: {source_subtype_guid}')
|
|
547
560
|
else:
|
|
548
|
-
assert _debug(f'WMFAudioDecoder: Found
|
|
549
|
-
|
|
550
|
-
|
|
561
|
+
assert _debug(f'WMFAudioDecoder: Found incompatible Audio: {source_subtype_guid}, '
|
|
562
|
+
f'sample size={source_sample_size.value}, channel count={source_channel_count.value}.'
|
|
563
|
+
f'Attempting to decode/resample.')
|
|
564
|
+
# If audio is compressed or incompatible, attempt to decompress or resample it
|
|
565
|
+
# to standard 16bit integer PCM
|
|
566
|
+
samples_per_sec = c_uint32()
|
|
567
|
+
imfmedia.GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, byref(samples_per_sec))
|
|
551
568
|
|
|
569
|
+
channels_out = min(2, source_channel_count.value)
|
|
570
|
+
|
|
571
|
+
mf_mediatype = IMFMediaType()
|
|
552
572
|
MFCreateMediaType(byref(mf_mediatype))
|
|
553
573
|
mf_mediatype.SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)
|
|
554
574
|
mf_mediatype.SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)
|
|
575
|
+
mf_mediatype.SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, channels_out)
|
|
576
|
+
mf_mediatype.SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16)
|
|
577
|
+
mf_mediatype.SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, samples_per_sec.value)
|
|
578
|
+
mf_mediatype.SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, channels_out * 2)
|
|
579
|
+
mf_mediatype.SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, samples_per_sec.value * channels_out * 2)
|
|
580
|
+
mf_mediatype.SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1)
|
|
555
581
|
|
|
556
582
|
try:
|
|
557
583
|
self._source_reader.SetCurrentMediaType(self._audio_stream_index, None, mf_mediatype)
|
pyglet/media/devices/win32.py
CHANGED
|
@@ -318,7 +318,7 @@ class Win32AudioDeviceManager(base.AbstractAudioDeviceManager):
|
|
|
318
318
|
return dev_id.value, name, description, state.value
|
|
319
319
|
|
|
320
320
|
def get_devices(self, flow=eRender, state=DEVICE_STATE_ACTIVE):
|
|
321
|
-
"""
|
|
321
|
+
"""Gets all of the specified devices (by default, all output and active)."""
|
|
322
322
|
collection = IMMDeviceCollection()
|
|
323
323
|
self._device_enum.EnumAudioEndpoints(flow, state, byref(collection))
|
|
324
324
|
|
pyglet/media/drivers/base.py
CHANGED
|
@@ -378,7 +378,7 @@ class AbstractAudioPlayer(metaclass=ABCMeta):
|
|
|
378
378
|
# Player falling behind
|
|
379
379
|
# Skip at most 12ms if this is a minor desync, otherwise skip the entire
|
|
380
380
|
# difference. this will be noticeable, but the desync is
|
|
381
|
-
# likely already
|
|
381
|
+
# likely already noticeable in context of whatever the application does.
|
|
382
382
|
compensated_bytes = (-desync_bytes
|
|
383
383
|
if extreme_desync
|
|
384
384
|
else min(-desync_bytes, self.desync_correction_bytes_minor))
|
|
@@ -5,6 +5,7 @@ import ctypes
|
|
|
5
5
|
import weakref
|
|
6
6
|
from collections import namedtuple
|
|
7
7
|
|
|
8
|
+
from pyglet.media.exceptions import MediaException
|
|
8
9
|
from pyglet.util import debug_print
|
|
9
10
|
from pyglet.window.win32 import _user32
|
|
10
11
|
|
|
@@ -20,6 +21,9 @@ def _check(hresult):
|
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
def _create_wave_format(audio_format):
|
|
24
|
+
if audio_format.channels > 2 or audio_format.sample_size not in (8, 16):
|
|
25
|
+
raise MediaException(f'Unsupported audio format: {audio_format}')
|
|
26
|
+
|
|
23
27
|
wfx = lib.WAVEFORMATEX()
|
|
24
28
|
wfx.wFormatTag = lib.WAVE_FORMAT_PCM
|
|
25
29
|
wfx.nChannels = audio_format.channels
|
pyglet/media/drivers/listener.py
CHANGED
|
@@ -53,7 +53,7 @@ class AbstractListener(metaclass=ABCMeta):
|
|
|
53
53
|
listener is facing.
|
|
54
54
|
|
|
55
55
|
The orientation is given as a tuple of floats (x, y, z), and has
|
|
56
|
-
no unit. The forward orientation should be
|
|
56
|
+
no unit. The forward orientation should be orthogonal to the
|
|
57
57
|
up orientation.
|
|
58
58
|
|
|
59
59
|
:type: 3-tuple of float
|
|
@@ -69,7 +69,7 @@ class AbstractListener(metaclass=ABCMeta):
|
|
|
69
69
|
of the listener.
|
|
70
70
|
|
|
71
71
|
The orientation is given as a tuple of floats (x, y, z), and has
|
|
72
|
-
no unit. The up orientation should be
|
|
72
|
+
no unit. The up orientation should be orthogonal to the
|
|
73
73
|
forward orientation.
|
|
74
74
|
|
|
75
75
|
:type: 3-tuple of float
|