xair-api 2.3.1__py3-none-any.whl → 2.4.0__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.
xair_api/adapter.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from .bus import Bus as IBus
2
+ from .headamp import HeadAmp as IHeadAmp
2
3
  from .lr import LR as ILR
3
4
  from .rtn import AuxRtn as IAuxRtn
4
5
  from .rtn import FxRtn as IFxRtn
@@ -38,3 +39,9 @@ class Matrix(ILR):
38
39
  @property
39
40
  def address(self) -> str:
40
41
  return f"/mtx/{str(self.index).zfill(2)}"
42
+
43
+
44
+ class HeadAmp(IHeadAmp):
45
+ @property
46
+ def address(self):
47
+ return f"/headamp/{str(self.index).zfill(3)}"
xair_api/errors.py CHANGED
@@ -1,2 +1,14 @@
1
1
  class XAirRemoteError(Exception):
2
2
  """Base error class for XAIR Remote."""
3
+
4
+
5
+ class XAirRemoteConnectionTimeoutError(XAirRemoteError):
6
+ """Exception raised when a connection attempt times out"""
7
+
8
+ def __init__(self, ip, port):
9
+ self.ip = ip
10
+ self.port = port
11
+
12
+ super().__init__(
13
+ f"Timeout attempting to connect to mixer at {self.ip}:{self.port}"
14
+ )
xair_api/headamp.py ADDED
@@ -0,0 +1,49 @@
1
+ import abc
2
+ import logging
3
+
4
+ from . import util
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ class IHeadAmp(abc.ABC):
10
+ """Abstract Base Class for headamps"""
11
+
12
+ def __init__(self, remote, index: int):
13
+ self._remote = remote
14
+ self.index = index + 1
15
+ self.logger = logger.getChild(self.__class__.__name__)
16
+
17
+ def getter(self, param: str):
18
+ return self._remote.query(f"{self.address}/{param}")
19
+
20
+ def setter(self, param: str, val: int):
21
+ self._remote.send(f"{self.address}/{param}", val)
22
+
23
+ @abc.abstractmethod
24
+ def address(self):
25
+ pass
26
+
27
+
28
+ class HeadAmp(IHeadAmp):
29
+ """Concrete class for headamps"""
30
+
31
+ @property
32
+ def address(self):
33
+ return f"/headamp/{str(self.index).zfill(2)}"
34
+
35
+ @property
36
+ def gain(self):
37
+ return round(util.lin_get(-12, 60, self.getter("gain")[0]), 1)
38
+
39
+ @gain.setter
40
+ def gain(self, val):
41
+ self.setter("gain", util.lin_set(-12, 60, val))
42
+
43
+ @property
44
+ def phantom(self):
45
+ return self.getter("phantom")[0] == 1
46
+
47
+ @phantom.setter
48
+ def phantom(self, val):
49
+ self.setter("phantom", 1 if val else 0)
xair_api/kinds.py CHANGED
@@ -16,6 +16,7 @@ class X32KindMap(KindMap):
16
16
  num_fx: int = 8
17
17
  num_auxrtn: int = 8
18
18
  num_matrix: int = 6
19
+ num_headamp: int = 127
19
20
 
20
21
 
21
22
  @dataclass
xair_api/util.py CHANGED
@@ -1,6 +1,35 @@
1
1
  import functools
2
+ import time
2
3
  from math import exp, log
3
4
 
5
+ from .errors import XAirRemoteConnectionTimeoutError
6
+
7
+
8
+ def timeout(func):
9
+ """
10
+ Times out the validate_connection function once time elapsed exceeds remote.connect_timeout.
11
+ """
12
+
13
+ @functools.wraps(func)
14
+ def wrapper(*args, **kwargs):
15
+ remote, *_ = args
16
+
17
+ err = None
18
+ start = time.time()
19
+ while time.time() < start + remote.connect_timeout:
20
+ try:
21
+ func(*args, **kwargs)
22
+ remote.logger.debug(f"login time: {round(time.time() - start, 2)}")
23
+ err = None
24
+ break
25
+ except XAirRemoteConnectionTimeoutError as e:
26
+ err = e
27
+ continue
28
+ if err:
29
+ raise err
30
+
31
+ return wrapper
32
+
4
33
 
5
34
  def lin_get(min, max, val):
6
35
  return min + (max - min) * val
xair_api/xair.py CHANGED
@@ -14,12 +14,13 @@ from pythonosc.dispatcher import Dispatcher
14
14
  from pythonosc.osc_message_builder import OscMessageBuilder
15
15
  from pythonosc.osc_server import BlockingOSCUDPServer
16
16
 
17
- from . import adapter, kinds
17
+ from . import adapter, kinds, util
18
18
  from .bus import Bus
19
19
  from .config import Config
20
20
  from .dca import DCA
21
- from .errors import XAirRemoteError
21
+ from .errors import XAirRemoteConnectionTimeoutError, XAirRemoteError
22
22
  from .fx import FX, FXSend
23
+ from .headamp import HeadAmp
23
24
  from .kinds import KindMap
24
25
  from .lr import LR
25
26
  from .rtn import AuxRtn, FxRtn
@@ -47,8 +48,6 @@ class OSCClientServer(BlockingOSCUDPServer):
47
48
  class XAirRemote(abc.ABC):
48
49
  """Handles the communication with the mixer via the OSC protocol"""
49
50
 
50
- _CONNECT_TIMEOUT = 0.5
51
-
52
51
  _info_response = []
53
52
 
54
53
  def __init__(self, **kwargs):
@@ -57,6 +56,7 @@ class XAirRemote(abc.ABC):
57
56
  self.xair_ip = kwargs["ip"] or self._ip_from_toml()
58
57
  self.xair_port = kwargs["port"]
59
58
  self._delay = kwargs["delay"]
59
+ self.connect_timeout = kwargs["connect_timeout"]
60
60
  self.logger = logger.getChild(self.__class__.__name__)
61
61
  if not self.xair_ip:
62
62
  raise XAirRemoteError("No valid ip detected")
@@ -74,13 +74,10 @@ class XAirRemote(abc.ABC):
74
74
  conn = tomllib.load(f)
75
75
  return conn["connection"].get("ip")
76
76
 
77
+ @util.timeout
77
78
  def validate_connection(self):
78
- self.send("/xinfo")
79
- time.sleep(self._CONNECT_TIMEOUT)
80
- if not self.info_response:
81
- raise XAirRemoteError(
82
- "Failed to setup OSC connection to mixer. Please check for correct ip address."
83
- )
79
+ if not self.query("/xinfo"):
80
+ raise XAirRemoteConnectionTimeoutError(self.xair_ip, self.xair_port)
84
81
  self.logger.info(
85
82
  f"Successfully connected to {self.info_response[2]} at {self.info_response[0]}."
86
83
  )
@@ -117,7 +114,12 @@ def _make_remote(kind: KindMap) -> XAirRemote:
117
114
  """
118
115
 
119
116
  def init_x32(self, *args, **kwargs):
120
- defaultkwargs = {"ip": None, "port": 10023, "delay": 0.02}
117
+ defaultkwargs = {
118
+ "ip": None,
119
+ "port": 10023,
120
+ "delay": 0.02,
121
+ "connect_timeout": 2,
122
+ }
121
123
  kwargs = defaultkwargs | kwargs
122
124
  XAirRemote.__init__(self, *args, **kwargs)
123
125
  self.kind = kind
@@ -133,9 +135,15 @@ def _make_remote(kind: KindMap) -> XAirRemote:
133
135
  self.fxreturn = tuple(adapter.FxRtn.make(self, i) for i in range(kind.num_fx))
134
136
  self.auxin = tuple(adapter.AuxRtn.make(self, i) for i in range(kind.num_auxrtn))
135
137
  self.config = Config.make(self)
138
+ self.headamp = tuple(adapter.HeadAmp(self, i) for i in range(kind.num_headamp))
136
139
 
137
140
  def init_xair(self, *args, **kwargs):
138
- defaultkwargs = {"ip": None, "port": 10024, "delay": 0.02}
141
+ defaultkwargs = {
142
+ "ip": None,
143
+ "port": 10024,
144
+ "delay": 0.02,
145
+ "connect_timeout": 2,
146
+ }
139
147
  kwargs = defaultkwargs | kwargs
140
148
  XAirRemote.__init__(self, *args, **kwargs)
141
149
  self.kind = kind
@@ -148,6 +156,7 @@ def _make_remote(kind: KindMap) -> XAirRemote:
148
156
  self.fxreturn = tuple(FxRtn.make(self, i) for i in range(kind.num_fx))
149
157
  self.auxreturn = AuxRtn.make(self)
150
158
  self.config = Config.make(self)
159
+ self.headamp = tuple(HeadAmp(self, i) for i in range(kind.num_strip))
151
160
 
152
161
  if kind.id_ == "X32":
153
162
  return type(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xair-api
3
- Version: 2.3.1
3
+ Version: 2.4.0
4
4
  Summary: Remote control Behringer X-Air | Midas MR mixers through OSC
5
5
  Home-page: https://github.com/onyx-and-iris/xair-api-python
6
6
  License: MIT
@@ -11,6 +11,8 @@ Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
14
16
  Requires-Dist: python-osc (>=1.8.0,<2.0.0)
15
17
  Requires-Dist: tomli (>=2.0.1,<3.0.0) ; python_version < "3.11"
16
18
  Project-URL: Repository, https://github.com/onyx-and-iris/xair-api-python
@@ -18,8 +20,7 @@ Description-Content-Type: text/markdown
18
20
 
19
21
  [![PyPI version](https://badge.fury.io/py/xair-api.svg)](https://badge.fury.io/py/xair-api)
20
22
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/onyx-and-iris/xair-api-python/blob/dev/LICENSE)
21
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
22
- [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
23
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
23
24
  ![Tests Status](./tests/xair/MR18.svg?dummy=8484744)
24
25
 
25
26
  # Xair API
@@ -73,7 +74,7 @@ if __name__ == "__main__":
73
74
  main()
74
75
  ```
75
76
 
76
- #### `xair_api.connect(kind_id, ip=ip, delay=delay)`
77
+ #### `xair_api.connect(kind_id, ip=ip, delay=0.02, connect_timeout=2)`
77
78
 
78
79
  Currently the following devices are supported:
79
80
 
@@ -90,6 +91,7 @@ The following keyword arguments may be passed:
90
91
  - `port`: mixer port, defaults to 10023 for x32 and 10024 for xair
91
92
  - `delay`: a delay between each command (applies to the getters). Defaults to 20ms.
92
93
  - a note about delay, stability may rely on network connection. For wired connections the delay can be safely reduced.
94
+ - `connect_timeout`: amount of time to wait for a validated connection. Defaults to 2s.
93
95
 
94
96
  ## API
95
97
 
@@ -131,6 +133,10 @@ A class representing auxreturn channel
131
133
 
132
134
  A class representing the main config settings
133
135
 
136
+ `mixer.headamp`
137
+
138
+ A class representing the channel preamps (phantom power/gain).
139
+
134
140
  ### `LR`
135
141
 
136
142
  Contains the subclasses:
@@ -161,6 +167,13 @@ Contains the subclasses:
161
167
  Contains the subclasses:
162
168
  (`Config`, `Preamp`, `EQ`, `Mix`, `Group`, `Send`)
163
169
 
170
+ ### `HeadAmp`
171
+
172
+ The following properties are available:
173
+
174
+ - `gain`: float, from -12.0 to 60.0
175
+ - `phantom`: bool
176
+
164
177
  ### `Subclasses`
165
178
 
166
179
  For each subclass the corresponding properties are available.
@@ -335,6 +348,14 @@ for example:
335
348
  print(mixer.query("/ch/01/mix/on"))
336
349
  ```
337
350
 
351
+ ### Errors
352
+
353
+ - `errors.XAirRemoteError`: Base error class for XAIR Remote.
354
+ - `errors.XAirRemoteConnectionTimeoutError`:Exception raised when a connection attempt times out.
355
+ - The following attributes are available:
356
+ - `ip`: IP of the mixer.
357
+ - `port`: Port of the mixer.
358
+
338
359
  ### `Tests`
339
360
 
340
361
  Unplug any expensive equipment before running tests.
@@ -0,0 +1,21 @@
1
+ xair_api/__init__.py,sha256=na_Zd_yo8E1LCoeWrAPJR68Ygdm5R8RRrlqb-UnWMtA,73
2
+ xair_api/adapter.py,sha256=ozQZOstdS3uJRYcnp8Qlx4mSNaKzGlFjWqtKRBF0PlA,963
3
+ xair_api/bus.py,sha256=digswx5ApbLCpF6R7_8OqfvnJ8C9JIFpe8MFxKXbSB0,1771
4
+ xair_api/config.py,sha256=ditmhP770trYIu7eouw4pU3BgOtXwOB8dearYJbhSuw,5853
5
+ xair_api/dca.py,sha256=C-wyBqeAi0qr1qrOKefyIWsJwI8ebs2iV83Q2iC67-k,1443
6
+ xair_api/errors.py,sha256=rfFmAW6QitHe0iB56M48He-qsbvDaKe1_AN_j4-9oUA,411
7
+ xair_api/fx.py,sha256=AzjgpJSHDCWwWRGCWxeGwwsm8jcxl3fJykprk9cwSUM,1811
8
+ xair_api/headamp.py,sha256=tLV4LB1QmLhpo4S8PdKkvS5NgK96-fisnY1bWN-IM-M,1175
9
+ xair_api/kinds.py,sha256=93VLFEgQwDJ4RdpIuf8T6_qqc6pwYCJGcS47UZdPqj8,1147
10
+ xair_api/lr.py,sha256=WL5YnDeLeJPxIK5OdTqZQ3s6UEfQ3-onz99OEdi0-mE,1788
11
+ xair_api/meta.py,sha256=iUWPSP4QcWMW6gyLc5SGDJ49pKZgJrHzFphtL6OFptE,1564
12
+ xair_api/rtn.py,sha256=lOTGSkxsYpc4usIba-reZSRmfa-7JIr_FTThSw6BdLY,3177
13
+ xair_api/shared.py,sha256=ABVTgx9sIH9zZLJLKeZBrhdMXj-WGNuggxrqjn8oa3M,19171
14
+ xair_api/strip.py,sha256=pAFX0Ssq1kC9BghGJhd6ShJ0on16DbkWoickH0jA-Jg,2082
15
+ xair_api/util.py,sha256=Rd2eGhqIjFe29s-0ffQGzs9p5lXsfCRJ91i6BPEVzxE,2263
16
+ xair_api/xair.py,sha256=PEdIYT2236cw5I9MUC5quc-6fnzBz8TM7_XVdzKEhFY,6582
17
+ xair_api-2.4.0.dist-info/entry_points.txt,sha256=hlKDU0C0XSGDitHXAvt6YQfmI99p3eJBaoQqEQhpH2U,126
18
+ xair_api-2.4.0.dist-info/LICENSE,sha256=m2fbtv9II-iQqimTd4zjgynL5vuEqGXauLSDJZycYIo,1124
19
+ xair_api-2.4.0.dist-info/METADATA,sha256=VFhEWE1wd6JhynQ2ZDMbnAUOLO0DoxAZtolKFYccquk,9068
20
+ xair_api-2.4.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
21
+ xair_api-2.4.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.6.1
2
+ Generator: poetry-core 1.9.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,4 +1,5 @@
1
1
  [console_scripts]
2
+ all=scripts:test_all
2
3
  obs=scripts:ex_obs
3
4
  sends=scripts:ex_sends
4
5
  x32=scripts:test_x32
@@ -1,20 +0,0 @@
1
- xair_api/__init__.py,sha256=na_Zd_yo8E1LCoeWrAPJR68Ygdm5R8RRrlqb-UnWMtA,73
2
- xair_api/adapter.py,sha256=icQXeqrYu6iWOJbke6zXdOzxyhAV__dXKrCnuDbZAUU,797
3
- xair_api/bus.py,sha256=digswx5ApbLCpF6R7_8OqfvnJ8C9JIFpe8MFxKXbSB0,1771
4
- xair_api/config.py,sha256=ditmhP770trYIu7eouw4pU3BgOtXwOB8dearYJbhSuw,5853
5
- xair_api/dca.py,sha256=C-wyBqeAi0qr1qrOKefyIWsJwI8ebs2iV83Q2iC67-k,1443
6
- xair_api/errors.py,sha256=RAqGQ3gndR9l8c_RfEBKC0tMsa5_n8F7o3X7ppVHfL8,80
7
- xair_api/fx.py,sha256=AzjgpJSHDCWwWRGCWxeGwwsm8jcxl3fJykprk9cwSUM,1811
8
- xair_api/kinds.py,sha256=ulJJhLpiUuOw5Ir7Q3CQbmAKrd33xq8CIHpAFc5zEdw,1119
9
- xair_api/lr.py,sha256=WL5YnDeLeJPxIK5OdTqZQ3s6UEfQ3-onz99OEdi0-mE,1788
10
- xair_api/meta.py,sha256=iUWPSP4QcWMW6gyLc5SGDJ49pKZgJrHzFphtL6OFptE,1564
11
- xair_api/rtn.py,sha256=lOTGSkxsYpc4usIba-reZSRmfa-7JIr_FTThSw6BdLY,3177
12
- xair_api/shared.py,sha256=ABVTgx9sIH9zZLJLKeZBrhdMXj-WGNuggxrqjn8oa3M,19171
13
- xair_api/strip.py,sha256=pAFX0Ssq1kC9BghGJhd6ShJ0on16DbkWoickH0jA-Jg,2082
14
- xair_api/util.py,sha256=VYgSWxKXnvD3tu564wbr5PTdODNrmGNnsZErER5hY3I,1485
15
- xair_api/xair.py,sha256=966mt1rYbjCtC82vtnKIpbrRYAGFnvgz8ctHxTvDL1Y,6261
16
- xair_api-2.3.1.dist-info/entry_points.txt,sha256=p2vlpkx3x9BZ3Mslqg2ngV3g-mdqwB14oEltOqi8kgg,105
17
- xair_api-2.3.1.dist-info/LICENSE,sha256=m2fbtv9II-iQqimTd4zjgynL5vuEqGXauLSDJZycYIo,1124
18
- xair_api-2.3.1.dist-info/METADATA,sha256=llkWczr78xaVVyGZ-5LjnzpFLxXp8IePPszpjrers_M,8483
19
- xair_api-2.3.1.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
20
- xair_api-2.3.1.dist-info/RECORD,,