LinkPython-extern 1.3.0a2__cp312-cp312-win_arm64.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.
Binary file
link/__init__.py ADDED
@@ -0,0 +1,12 @@
1
+ """""" # start delvewheel patch
2
+ def _delvewheel_patch_1_13_0():
3
+ import os
4
+ if os.path.isdir(libs_dir := os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, '.'))):
5
+ os.add_dll_directory(libs_dir)
6
+
7
+
8
+ _delvewheel_patch_1_13_0()
9
+ del _delvewheel_patch_1_13_0
10
+ # end delvewheel patch
11
+
12
+ from _link import *
link/__init__.pyi ADDED
@@ -0,0 +1,257 @@
1
+ # Docstrings derived from:
2
+ # https://github.com/Ableton/link/blob/Link-3.0.6/include/ableton/Link.hpp
3
+
4
+ from typing import Any, Callable
5
+
6
+ class Clock:
7
+ def micros(self) -> int:
8
+ """Return the current system time in microseconds."""
9
+
10
+ class SessionState:
11
+ def tempo(self) -> float:
12
+ """Return the tempo of the timeline, in Beats Per Minute.
13
+
14
+ This is a stable value that is appropriate for display
15
+ to the user. Beat time progress will not necessarily match this tempo
16
+ exactly because of clock drift compensation.
17
+
18
+ """
19
+
20
+ def setTempo(self, __tempo: float, __time: int) -> None:
21
+ """Set the timeline tempo to the given bpm value, taking
22
+ effect at the given time.
23
+ """
24
+
25
+ def beatAtTime(self, __time: int, __quantum: float) -> float:
26
+ """Get the beat value corresponding to the given time
27
+ for the given quantum.
28
+
29
+ The magnitude of the resulting beat value is
30
+ unique to this Link instance, but its phase with respect to
31
+ the provided quantum is shared among all session
32
+ peers. For non-negative beat values, the following
33
+ property holds: fmod(beatAtTime(t, q), q) == phaseAtTime(t, q)
34
+
35
+ """
36
+
37
+ def phaseAtTime(self, __time: int, __quantum: float) -> float:
38
+ """Get the session phase at the given time for the given
39
+ quantum.
40
+
41
+ The result is in the interval [0, quantum). The
42
+ result is equivalent to fmod(beatAtTime(t, q), q) for
43
+ non-negative beat values. This method is convenient if the
44
+ client is only interested in the phase and not the beat
45
+ magnitude. Also, unlike fmod, it handles negative beat values
46
+ correctly.
47
+
48
+ """
49
+
50
+ def timeAtBeat(self, __beat: float, __quantum: float) -> float:
51
+ """Get the time at which the given beat occurs for the
52
+ given quantum.
53
+
54
+ The inverse of beatAtTime, assuming a constant
55
+ tempo. beatAtTime(timeAtBeat(b, q), q) === b.
56
+
57
+ """
58
+
59
+ def requestBeatAtTime(self, __beat: float, __time: int, __quantum: float) -> None:
60
+ """Attempt to map the given beat to the given time in the
61
+ context of the given quantum.
62
+
63
+ This method behaves differently depending on the
64
+ state of the session. If no other peers are connected,
65
+ then this instance is in a session by itself and is free to
66
+ re-map the beat/time relationship whenever it pleases. In this
67
+ case, beatAtTime(time, quantum) == beat after this method has
68
+ been called.
69
+
70
+ If there are other peers in the session, this instance
71
+ should not abruptly re-map the beat/time relationship in the
72
+ session because that would lead to beat discontinuities among
73
+ the other peers. In this case, the given beat will be mapped
74
+ to the next time value greater than the given time with the
75
+ same phase as the given beat.
76
+
77
+ This method is specifically designed to enable the concept of
78
+ "quantized launch" in client applications. If there are no other
79
+ peers in the session, then an event (such as starting
80
+ transport) happens immediately when it is requested. If there
81
+ are other peers, however, we wait until the next time at which
82
+ the session phase matches the phase of the event, thereby
83
+ executing the event in-phase with the other peers in the
84
+ session. The client only needs to invoke this method to
85
+ achieve this behavior and should not need to explicitly check
86
+ the number of peers.
87
+
88
+ """
89
+
90
+ def isPlaying(self) -> bool:
91
+ """Return True if the transport is playing, False otherwise."""
92
+
93
+ def setIsPlaying(self, __isPlaying: bool, __time: int) -> None:
94
+ """Set if transport should be playing or stopped, taking effect
95
+ at the given time.
96
+ """
97
+
98
+ def forceBeatAtTime(self, __beat: float, __time: int, __quantum: float) -> None:
99
+ """Rudely re-map the beat/time relationship for all peers
100
+ in a session.
101
+
102
+ DANGER: This method should only be needed in
103
+ certain special circumstances. Most applications should not
104
+ use it. It is very similar to requestBeatAtTime except that it
105
+ does not fall back to the quantizing behavior when it is in a
106
+ session with other peers. Calling this method will
107
+ unconditionally map the given beat to the given time and
108
+ broadcast the result to the session. This is very anti-social
109
+ behavior and should be avoided.
110
+
111
+ One of the few legitimate uses of this method is to
112
+ synchronize a Link session with an external clock source. By
113
+ periodically forcing the beat/time mapping according to an
114
+ external clock source, a peer can effectively bridge that
115
+ clock into a Link session. Much care must be taken at the
116
+ application layer when implementing such a feature so that
117
+ users do not accidentally disrupt Link sessions that they may
118
+ join.
119
+
120
+ """
121
+
122
+ def timeForIsPlaying(self) -> int:
123
+ """Get the time in microseconds at which a transport start/stop occurs."""
124
+
125
+ def requestBeatAtStartPlayingTime(self, __beat: float, __quantum: float) -> None:
126
+ """Convenience function to attempt to map the given beat to the time
127
+ when transport is starting to play in context of the given quantum.
128
+
129
+ This function evaluates to a no-op if isPlaying() equals false.
130
+
131
+ """
132
+
133
+ def setIsPlayingAndRequestBeatAtTime(
134
+ self,
135
+ __isPlaying: bool,
136
+ __time: int,
137
+ __beat: float,
138
+ __quantum: float,
139
+ ) -> None:
140
+ """Convenience function to start or stop transport at a given time and
141
+ attempt to map the given beat to this time in context of the given quantum.
142
+ """
143
+
144
+ class Link:
145
+ """Represents a participant in a Link session.
146
+
147
+ Each Link instance has its own session state which
148
+ represents a beat timeline and a transport start/stop state. The
149
+ timeline starts running from beat 0 at the initial tempo when
150
+ constructed. The timeline always advances at a speed defined by
151
+ its current tempo, even if transport is stopped. Synchronizing to the
152
+ transport start/stop state of Link is optional for every peer.
153
+ The transport start/stop state is only shared with other peers when
154
+ start/stop synchronization is enabled.
155
+
156
+ A Link instance is initially disabled after construction, which
157
+ means that it will not communicate on the network. Once enabled,
158
+ a Link instance initiates network communication in an effort to
159
+ discover other peers. When peers are discovered, they immediately
160
+ become part of a shared Link session.
161
+
162
+ """
163
+
164
+ enabled: bool
165
+ """Indicates if Link is currently enabled.
166
+
167
+ To start Link, set this attribute to True.
168
+
169
+ """
170
+
171
+ startStopSyncEnabled: bool
172
+ """Indicates if start/stop synchronization is enabled.
173
+
174
+ To enable start/stop synchronization, set this attribute to True.
175
+
176
+ """
177
+
178
+ def __init__(self, __bpm: float) -> None:
179
+ """
180
+ :param bpm: The initial tempo of the session.
181
+ """
182
+
183
+ def numPeers(self) -> int:
184
+ """Return the number of peers currently connected in the Link session."""
185
+
186
+ def clock(self) -> Clock:
187
+ """Return the clock used by Link.
188
+
189
+ The Clock type is a platform-dependent representation
190
+ of the system clock. It exposes a micros() method, which is a
191
+ normalized representation of the current system time in
192
+ microseconds.
193
+
194
+ """
195
+
196
+ def captureAppSessionState(self) -> SessionState:
197
+ """Capture the current Link Session State from an application thread.
198
+
199
+ Provides a mechanism for capturing the Link Session
200
+ State from an application thread (other than the audio thread).
201
+ The returned Session State stores a snapshot of the current Link
202
+ state, so it should be captured and used in a local scope.
203
+ Storing the it for later use in a different context is not
204
+ advised because it will provide an outdated view.
205
+
206
+ """
207
+
208
+ def commitAppSessionState(self, __state: SessionState) -> None:
209
+ """Commit the given Session State to the Link session from an
210
+ application thread.
211
+
212
+ The given Session State will replace the current Link
213
+ Session State. Modifications of the Session State will be
214
+ communicated to other peers in the session.
215
+
216
+ :param state: The session state to be committed.
217
+
218
+ """
219
+
220
+ captureSessionState = captureAppSessionState
221
+ commitSessionState = commitAppSessionState
222
+
223
+ def setNumPeersCallback(self, __callback: Callable[[int], Any]) -> None:
224
+ """Register a callback to be notified when the number of
225
+ peers in the Link session changes.
226
+
227
+ The callback is invoked on a Link-managed thread.
228
+
229
+ :param callback:
230
+ The callback to be invoked. It should take one argument,
231
+ the new number of peers.
232
+
233
+ """
234
+
235
+ def setTempoCallback(self, __callback: Callable[[float], Any]) -> None:
236
+ """Register a callback to be notified when the session
237
+ tempo changes.
238
+
239
+ The callback is invoked on a Link-managed thread.
240
+
241
+ :param callback:
242
+ The callback to be invoked. It should take one argument,
243
+ the new tempo.
244
+
245
+ """
246
+
247
+ def setStartStopCallback(self, __callback: Callable[[bool], Any]) -> None:
248
+ """Register a callback to be notified when the state of
249
+ start/stop isPlaying changes.
250
+
251
+ The callback is invoked on a Link-managed thread.
252
+
253
+ :param callback:
254
+ The callback to be invoked. It should take one argument,
255
+ the new start/stop state.
256
+
257
+ """
link/py.typed ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ Version: 1.13.0
2
+ Arguments: ['C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-jwfxrg94\\cp312-win_arm64\\build\\venv\\Scripts\\delvewheel', 'repair', '-w', 'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-jwfxrg94\\cp312-win_arm64\\repaired_wheel', '-v', 'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-jwfxrg94\\cp312-win_arm64\\built_wheel\\linkpython_extern-1.3.0a2-cp312-cp312-win_arm64.whl']
@@ -0,0 +1,110 @@
1
+ Metadata-Version: 2.4
2
+ Name: LinkPython-extern
3
+ Version: 1.3.0a2
4
+ Summary: A Python wrapper for Ableton Link, wheels included!
5
+ Keywords: ableton,ableton link,link,music,sync
6
+ Author: gonzaloflirt
7
+ Maintainer: thegamecracks
8
+ License-Expression: Unlicense
9
+ License-File: LICENSE.md
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: C++
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Topic :: System :: Networking
15
+ Project-URL: Homepage, https://github.com/thegamecracks/link-python
16
+ Requires-Python: <3.15,>=3.9
17
+ Description-Content-Type: text/markdown
18
+
19
+ # LinkPython-extern
20
+
21
+ [![PyPI](https://img.shields.io/pypi/v/LinkPython-extern?label=View%20on%20pypi&style=flat-square)](https://pypi.org/project/LinkPython-extern/)
22
+ [![Build](https://github.com/thegamecracks/link-python/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/thegamecracks/link-python/actions/workflows/build_wheels.yml)
23
+ [![Tests](https://github.com/thegamecracks/link-python/actions/workflows/pytest.yml/badge.svg)](https://github.com/thegamecracks/link-python/actions/workflows/pytest.yml)
24
+
25
+ A Python wrapper for [Ableton Link], forked from gonzaloflirt's [link-python]
26
+ to streamline the user experience with new methods, type stubs, and pre-built
27
+ wheels.
28
+
29
+ ```py
30
+ from link import Link
31
+
32
+ link = Link(120)
33
+ clock = link.clock()
34
+ micros = clock.micros()
35
+
36
+ state = link.captureAppSessionState()
37
+ beat = state.beatAtTime(micros, 4)
38
+ phase = state.phaseAtTime(micros, 4)
39
+ ```
40
+
41
+ You can see the full API documentation in [`__init__.pyi`], or look at
42
+ the [LinkHut.py] example which is equivalent to Ableton Link's
43
+ [linkhut] example.
44
+
45
+ For asyncio usage, consider trying out the [aalink] project!
46
+
47
+ ## Installation
48
+
49
+ This project can be installed from PyPI under the [LinkPython-extern] name:
50
+
51
+ ```sh
52
+ pip install LinkPython-extern
53
+ ```
54
+
55
+ Note that we are *not* the same as [LinkPython], which is a different fork
56
+ of link-python by munshkr.
57
+
58
+ ## Python compatibility
59
+
60
+ | | v1.0.0 | v1.0.1 | v1.0.4 | v1.1.0 | v1.2.0 | v1.3.0a1 | main |
61
+ |----------------|:------:|:------:|:------:|:------:|:------:|:--------:|:----:|
62
+ | CPython 3.6 | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
63
+ | CPython 3.7 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
64
+ | CPython 3.8 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
65
+ | CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
66
+ | CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
67
+ | CPython 3.11 | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
68
+ | CPython 3.12 | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
69
+ | CPython 3.13\* | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ |
70
+ | CPython 3.14 | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
71
+ | CPython 3.15 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
72
+ | CPython 3.16+ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
73
+
74
+ \* CPython 3.13's experimental free-threading builds are not supported.
75
+
76
+ ## Building from source
77
+
78
+ If you want to build this package from source, you will need CMake installed.
79
+ You however do not need to manually build the project, as scikit-build-core will
80
+ handle invoking cmake when you install it with pip. To install directly
81
+ from the main branch:
82
+
83
+ ```sh
84
+ pip install git+https://github.com/thegamecracks/link-python
85
+ ```
86
+
87
+ If building from the repository directly, make sure to clone all submodules using:
88
+
89
+ ```sh
90
+ git clone --recurse-submodules https://github.com/thegamecracks/link-python
91
+ # or, if already cloned:
92
+ git submodule update --init --recursive
93
+ ```
94
+
95
+ ## License
96
+
97
+ This project is written under [Unlicense] but also depends on,
98
+ among other libraries, [Ableton Link] and [pybind11].
99
+ Please mind the licenses of those libraries and their dependencies.
100
+
101
+ [Ableton Link]: https://github.com/ableton/link.git
102
+ [link-python]: https://github.com/gonzaloflirt/link-python
103
+ [`__init__.pyi`]: https://github.com/thegamecracks/link-python/blob/master/src-py/link/__init__.pyi
104
+ [LinkHut.py]: https://github.com/thegamecracks/link-python/blob/master/example/LinkHut.py
105
+ [linkhut]: https://github.com/Ableton/link/blob/master/examples/linkhut/main.cpp
106
+ [aalink]: https://github.com/artfwo/aalink
107
+ [LinkPython-extern]: https://pypi.org/project/LinkPython-extern/
108
+ [LinkPython]: https://github.com/munshkr/link-python
109
+ [Unlicense]: /LICENSE.md
110
+ [pybind11]: https://github.com/pybind/pybind11
@@ -0,0 +1,10 @@
1
+ _link.cp312-win_arm64.pyd,sha256=cmJvIPEj7F3k-8k24-55DkwR6yJkZsvRpVGpNtFkZBo,425472
2
+ link/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ link/__init__.py,sha256=rGDu4Yax7gSRebC3oZgFR011dTuOhwNDbu64MyH6D2I,339
4
+ link/__init__.pyi,sha256=iH9aWhrUkK1hlxRXA9Vj25O_oMnwQkhGTpWgDDOvzJA,10014
5
+ linkpython_extern-1.3.0a2.data/platlib/msvcp140-5f1c5dd31916990d94181e07bc3afb32.dll,sha256=Xxxd0xkWmQ2UGB4HvDr7Mr49tY8EO5-NZJ4kFYYvZr8,1387552
6
+ linkpython_extern-1.3.0a2.dist-info/DELVEWHEEL,sha256=K5EMwJOX-hpCzBbpzhMtj6chRmEgz5ztzy_wk02-yVg,418
7
+ linkpython_extern-1.3.0a2.dist-info/METADATA,sha256=ddTInlH5ohPK1qhriPjJr57ap_aBfnMEguAe1CVgQjY,4592
8
+ linkpython_extern-1.3.0a2.dist-info/RECORD,,
9
+ linkpython_extern-1.3.0a2.dist-info/WHEEL,sha256=fnODF-PNtYcPmBGkQYuEMFUKmnTJrZGWNChBROEYn4E,106
10
+ linkpython_extern-1.3.0a2.dist-info/licenses/LICENSE.md,sha256=q5WXlxI4JI6pfbYaXwRHcelpf_KquERaf3hwVuv7sOU,1415
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: scikit-build-core 0.12.2
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-win_arm64
5
+
@@ -0,0 +1,27 @@
1
+ This depends on [Link](https://github.com/ableton/link.git) and [pybind11](https://github.com/pybind/pybind11).
2
+ Please mind the licenses of those libraries and their dependencies
3
+
4
+ This is free and unencumbered software released into the public domain.
5
+
6
+ Anyone is free to copy, modify, publish, use, compile, sell, or
7
+ distribute this software, either in source code form or as a compiled
8
+ binary, for any purpose, commercial or non-commercial, and by any
9
+ means.
10
+
11
+ In jurisdictions that recognize copyright laws, the author or authors
12
+ of this software dedicate any and all copyright interest in the
13
+ software to the public domain. We make this dedication for the benefit
14
+ of the public at large and to the detriment of our heirs and
15
+ successors. We intend this dedication to be an overt act of
16
+ relinquishment in perpetuity of all present and future rights to this
17
+ software under copyright law.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
+ OTHER DEALINGS IN THE SOFTWARE.
26
+
27
+ For more information, please refer to <http://unlicense.org>