mirror of
https://github.com/onyx-and-iris/xair-api-python.git
synced 2026-04-07 16:43:32 +00:00
Compare commits
21 Commits
add-send-c
...
add-headam
| Author | SHA1 | Date | |
|---|---|---|---|
| 3010b44b09 | |||
| f26de42b89 | |||
| 6bdd4a0040 | |||
|
|
b53ed46014 | ||
| caaf2689ff | |||
| 7e7aa1b4de | |||
| 2dc096e306 | |||
| ed397e57aa | |||
| 718ecbd982 | |||
| 69cabb3db0 | |||
| 6a2df6352d | |||
| 9c1fa36aed | |||
| 3a70a4c578 | |||
| 8b1b2c7f79 | |||
| 1e5e458105 | |||
| e05460e998 | |||
| d27824d1cf | |||
| 764195a452 | |||
| b295fee6e1 | |||
| 06be2f2831 | |||
| 2d0c0f91f0 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -131,3 +131,5 @@ dmypy.json
|
||||
# config, quick test
|
||||
config.toml
|
||||
quick.py
|
||||
|
||||
.vscode/
|
||||
39
CHANGELOG.md
39
CHANGELOG.md
@@ -9,8 +9,43 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- [x] Send class mixed into Strip, AuxRtn, FxRtn. May now be accessed with {Class}.send
|
||||
- [x] Sends example added
|
||||
- [ ]
|
||||
|
||||
## [2.4.0] - 2025-01-04
|
||||
|
||||
### Added
|
||||
|
||||
- HeadAmp class to all kinds for enabling phantom power and setting preamp gain.
|
||||
- headamp example.
|
||||
|
||||
## [2.3.2] - 2024-02-16
|
||||
|
||||
### Added
|
||||
|
||||
- Configurable kwarg `connect_timeout` added. Defaults to 2 seconds.
|
||||
- New error class `XAirRemoteConnectionTimeoutError`. Raised if a connection validation times out.
|
||||
- timeout kwarg + Errors section added to README.
|
||||
|
||||
## [2.3.1] - 2024-02-15
|
||||
|
||||
### Changed
|
||||
|
||||
- Module level loggers implemented
|
||||
- class loggers are now child loggers
|
||||
- Passing an incorrect kind_id to the entry point now raises an XAirRemoteError.
|
||||
- Passing a value out of bounds to a setter now logs a warning instead of raising an exception.
|
||||
- Send class added to README.
|
||||
|
||||
## [2.2.4] - 2024-02-14
|
||||
|
||||
### Added
|
||||
|
||||
- Send class mixed into Strip, AuxRtn, FxRtn. May now be accessed with {Class}.send
|
||||
- Sends example added
|
||||
|
||||
### Changed
|
||||
|
||||
- delay kwarg now applies to getters. See [Issue #6](https://github.com/onyx-and-iris/xair-api-python/issues/6).
|
||||
|
||||
## [2.2.0] - 2022-11-08
|
||||
|
||||
|
||||
37
README.md
37
README.md
@@ -1,7 +1,6 @@
|
||||
[](https://badge.fury.io/py/xair-api)
|
||||
[](https://github.com/onyx-and-iris/xair-api-python/blob/dev/LICENSE)
|
||||
[](https://github.com/psf/black)
|
||||
[](https://pycqa.github.io/isort/)
|
||||
[](https://github.com/astral-sh/ruff)
|
||||

|
||||
|
||||
# Xair API
|
||||
@@ -55,7 +54,7 @@ if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
#### `xair_api.connect(kind_id, ip=ip, delay=delay)`
|
||||
#### `xair_api.connect(kind_id, ip=ip, delay=0.02, connect_timeout=2)`
|
||||
|
||||
Currently the following devices are supported:
|
||||
|
||||
@@ -72,6 +71,7 @@ The following keyword arguments may be passed:
|
||||
- `port`: mixer port, defaults to 10023 for x32 and 10024 for xair
|
||||
- `delay`: a delay between each command (applies to the getters). Defaults to 20ms.
|
||||
- a note about delay, stability may rely on network connection. For wired connections the delay can be safely reduced.
|
||||
- `connect_timeout`: amount of time to wait for a validated connection. Defaults to 2s.
|
||||
|
||||
## API
|
||||
|
||||
@@ -113,6 +113,10 @@ A class representing auxreturn channel
|
||||
|
||||
A class representing the main config settings
|
||||
|
||||
`mixer.headamp`
|
||||
|
||||
A class representing the channel preamps (phantom power/gain).
|
||||
|
||||
### `LR`
|
||||
|
||||
Contains the subclasses:
|
||||
@@ -121,7 +125,7 @@ Contains the subclasses:
|
||||
### `Strip`
|
||||
|
||||
Contains the subclasses:
|
||||
(`Config`, `Preamp`, `Gate`, `Dyn`, `Insert`, `GEQ`, `EQ`, `Mix`, `Group`, `Automix`)
|
||||
(`Config`, `Preamp`, `Gate`, `Dyn`, `Insert`, `GEQ`, `EQ`, `Mix`, `Group`, `Automix`, `Send`)
|
||||
|
||||
### `Bus`
|
||||
|
||||
@@ -136,12 +140,19 @@ Contains the subclasses:
|
||||
### `FXRtn`
|
||||
|
||||
Contains the subclasses:
|
||||
(`Config`, `Preamp`, `EQ`, `Mix`, `Group`)
|
||||
(`Config`, `Preamp`, `EQ`, `Mix`, `Group`, `Send`)
|
||||
|
||||
### `AuxRtn`
|
||||
|
||||
Contains the subclasses:
|
||||
(`Config`, `Preamp`, `EQ`, `Mix`, `Group`)
|
||||
(`Config`, `Preamp`, `EQ`, `Mix`, `Group`, `Send`)
|
||||
|
||||
### `HeadAmp`
|
||||
|
||||
The following properties are available:
|
||||
|
||||
- `gain`: float, from -12.0 to 60.0
|
||||
- `phantom`: bool
|
||||
|
||||
### `Subclasses`
|
||||
|
||||
@@ -288,6 +299,12 @@ tuple containing a class for each mute group
|
||||
|
||||
for example: `config.mute_group[0].on = True`
|
||||
|
||||
### `Send`
|
||||
|
||||
- `level`: float, -inf to 10.0
|
||||
|
||||
for example: `mixer.strip[10].send[3].level = -16.5`
|
||||
|
||||
### XAirRemote class (lower level)
|
||||
|
||||
Send an OSC command directly to the mixer
|
||||
@@ -311,6 +328,14 @@ for example:
|
||||
print(mixer.query("/ch/01/mix/on"))
|
||||
```
|
||||
|
||||
### Errors
|
||||
|
||||
- `errors.XAirRemoteError`: Base error class for XAIR Remote.
|
||||
- `errors.XAirRemoteConnectionTimeoutError`:Exception raised when a connection attempt times out.
|
||||
- The following attributes are available:
|
||||
- `ip`: IP of the mixer.
|
||||
- `port`: Port of the mixer.
|
||||
|
||||
### `Tests`
|
||||
|
||||
Unplug any expensive equipment before running tests.
|
||||
|
||||
20
examples/headamp/__main__.py
Normal file
20
examples/headamp/__main__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Warning this script enables the phantom power for strip 09
|
||||
|
||||
import logging
|
||||
|
||||
import xair_api
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
def main():
|
||||
with xair_api.connect("XR18", ip="mixer.local") as mixer:
|
||||
mixer.headamp[8].phantom = True
|
||||
for i in range(-12, -6):
|
||||
mixer.headamp[8].gain = i
|
||||
print(mixer.headamp[8].gain)
|
||||
input("Press Enter to continue...")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
354
poetry.lock
generated
354
poetry.lock
generated
@@ -1,92 +1,79 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "22.1.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
|
||||
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
|
||||
tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "22.8.0"
|
||||
description = "The uncompromising code formatter."
|
||||
optional = false
|
||||
python-versions = ">=3.6.2"
|
||||
files = [
|
||||
{file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"},
|
||||
{file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"},
|
||||
{file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"},
|
||||
{file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"},
|
||||
{file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"},
|
||||
{file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"},
|
||||
{file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"},
|
||||
{file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"},
|
||||
{file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"},
|
||||
{file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"},
|
||||
{file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"},
|
||||
{file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"},
|
||||
{file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"},
|
||||
{file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"},
|
||||
{file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"},
|
||||
{file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"},
|
||||
{file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"},
|
||||
{file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"},
|
||||
{file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"},
|
||||
{file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"},
|
||||
{file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"},
|
||||
{file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"},
|
||||
{file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.0"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
pathspec = ">=0.9.0"
|
||||
platformdirs = ">=2"
|
||||
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.7.4)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.3"
|
||||
description = "Composable command line interface toolkit"
|
||||
name = "cachetools"
|
||||
version = "5.5.0"
|
||||
description = "Extensible memoizing collections and decorators"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
|
||||
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
|
||||
{file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"},
|
||||
{file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
[[package]]
|
||||
name = "chardet"
|
||||
version = "5.2.0"
|
||||
description = "Universal encoding detector for Python 3"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
|
||||
{file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
|
||||
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "distlib"
|
||||
version = "0.3.9"
|
||||
description = "Distribution utilities"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
|
||||
{file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.0"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
|
||||
{file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "3.16.1"
|
||||
description = "A platform independent file lock."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
|
||||
{file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"]
|
||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"]
|
||||
typing = ["typing-extensions (>=4.12.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "1.1.1"
|
||||
@@ -98,83 +85,42 @@ files = [
|
||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.10.1"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
optional = false
|
||||
python-versions = ">=3.6.1,<4.0"
|
||||
files = [
|
||||
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
|
||||
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
colors = ["colorama (>=0.4.3,<0.5.0)"]
|
||||
pipfile-deprecated-finder = ["pipreqs", "requirementslib"]
|
||||
plugins = ["setuptools"]
|
||||
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "0.4.3"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
|
||||
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "21.3"
|
||||
version = "24.2"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.10.1"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"},
|
||||
{file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"},
|
||||
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
|
||||
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "2.5.2"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
version = "4.3.6"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
|
||||
{file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
|
||||
{file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
|
||||
{file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
|
||||
docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
|
||||
type = ["mypy (>=1.11.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.0.0"
|
||||
version = "1.5.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
|
||||
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@@ -182,52 +128,56 @@ dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "py"
|
||||
version = "1.11.0"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
name = "pyenv-inspect"
|
||||
version = "0.4.0"
|
||||
description = "An auxiliary library for the virtualenv-pyenv and tox-pyenv-redux plugins"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
{file = "pyenv-inspect-0.4.0.tar.gz", hash = "sha256:ec429d1d81b67ab0b08a0408414722a79d24fd1845a5b264267e44e19d8d60f0"},
|
||||
{file = "pyenv_inspect-0.4.0-py3-none-any.whl", hash = "sha256:618683ae7d3e6db14778d58aa0fc6b3170180d944669b5d35a8aa4fb7db550d2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.9"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
name = "pyproject-api"
|
||||
version = "1.8.0"
|
||||
description = "API to interact with the python pyproject.toml based projects"
|
||||
optional = false
|
||||
python-versions = ">=3.6.8"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||
{file = "pyproject_api-1.8.0-py3-none-any.whl", hash = "sha256:3d7d347a047afe796fd5d1885b1e391ba29be7169bd2f102fcd378f04273d228"},
|
||||
{file = "pyproject_api-1.8.0.tar.gz", hash = "sha256:77b8049f2feb5d33eefcc21b57f1e279636277a8ac8ad6b5871037b243778496"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=24.1"
|
||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
docs = ["furo (>=2024.8.6)", "sphinx-autodoc-typehints (>=2.4.1)"]
|
||||
testing = ["covdefaults (>=2.3)", "pytest (>=8.3.3)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.1.3"
|
||||
version = "7.4.4"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"},
|
||||
{file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"},
|
||||
{file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"},
|
||||
{file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=19.2.0"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
py = ">=1.8.2"
|
||||
tomli = ">=1.0.0"
|
||||
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
|
||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-randomly"
|
||||
@@ -254,6 +204,33 @@ files = [
|
||||
{file = "python_osc-1.8.0-py3-none-any.whl", hash = "sha256:9e2abb2fc9ba2c356f8e951609a03c9c7017bf0bad82cca8490e9b8af9e92a0b"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.8.6"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.8.6-py3-none-linux_armv6l.whl", hash = "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3"},
|
||||
{file = "ruff-0.8.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1"},
|
||||
{file = "ruff-0.8.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807"},
|
||||
{file = "ruff-0.8.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25"},
|
||||
{file = "ruff-0.8.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d"},
|
||||
{file = "ruff-0.8.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75"},
|
||||
{file = "ruff-0.8.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315"},
|
||||
{file = "ruff-0.8.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188"},
|
||||
{file = "ruff-0.8.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf"},
|
||||
{file = "ruff-0.8.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117"},
|
||||
{file = "ruff-0.8.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe"},
|
||||
{file = "ruff-0.8.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d"},
|
||||
{file = "ruff-0.8.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a"},
|
||||
{file = "ruff-0.8.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76"},
|
||||
{file = "ruff-0.8.6-py3-none-win32.whl", hash = "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764"},
|
||||
{file = "ruff-0.8.6-py3-none-win_amd64.whl", hash = "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905"},
|
||||
{file = "ruff-0.8.6-py3-none-win_arm64.whl", hash = "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162"},
|
||||
{file = "ruff-0.8.6.tar.gz", hash = "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
@@ -265,7 +242,80 @@ files = [
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tox"
|
||||
version = "4.23.2"
|
||||
description = "tox is a generic virtualenv management and test command line tool"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tox-4.23.2-py3-none-any.whl", hash = "sha256:452bc32bb031f2282881a2118923176445bac783ab97c874b8770ab4c3b76c38"},
|
||||
{file = "tox-4.23.2.tar.gz", hash = "sha256:86075e00e555df6e82e74cfc333917f91ecb47ffbc868dcafbd2672e332f4a2c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cachetools = ">=5.5"
|
||||
chardet = ">=5.2"
|
||||
colorama = ">=0.4.6"
|
||||
filelock = ">=3.16.1"
|
||||
packaging = ">=24.1"
|
||||
platformdirs = ">=4.3.6"
|
||||
pluggy = ">=1.5"
|
||||
pyproject-api = ">=1.8"
|
||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
||||
typing-extensions = {version = ">=4.12.2", markers = "python_version < \"3.11\""}
|
||||
virtualenv = ">=20.26.6"
|
||||
|
||||
[package.extras]
|
||||
test = ["devpi-process (>=1.0.2)", "pytest (>=8.3.3)", "pytest-mock (>=3.14)"]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "virtualenv"
|
||||
version = "20.28.1"
|
||||
description = "Virtual Python Environment builder"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "virtualenv-20.28.1-py3-none-any.whl", hash = "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb"},
|
||||
{file = "virtualenv-20.28.1.tar.gz", hash = "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
distlib = ">=0.3.7,<1"
|
||||
filelock = ">=3.12.2,<4"
|
||||
platformdirs = ">=3.9.1,<5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
||||
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "virtualenv-pyenv"
|
||||
version = "0.5.0"
|
||||
description = "A virtualenv Python discovery plugin for pyenv-installed interpreters"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "virtualenv-pyenv-0.5.0.tar.gz", hash = "sha256:7b0e5fe3dfbdf484f4cf9b01e1f98111e398db6942237910f666356e6293597f"},
|
||||
{file = "virtualenv_pyenv-0.5.0-py3-none-any.whl", hash = "sha256:21750247e36c55b3c547cfdeb08f51a3867fe7129922991a4f9c96980c0a4a5d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyenv-inspect = ">=0.4,<0.5"
|
||||
virtualenv = "*"
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "def96d1658f870a9820fef363ee6a04455f1d895e15a189ea4f39801f168552f"
|
||||
content-hash = "03c4b24c8bf12ad78f55f6e99a5001183bbb855bf8ef841dd3522fb79c1f7288"
|
||||
|
||||
114
pyproject.toml
114
pyproject.toml
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "xair-api"
|
||||
version = "2.2.4a0"
|
||||
version = "2.4.0"
|
||||
description = "Remote control Behringer X-Air | Midas MR mixers through OSC"
|
||||
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
||||
license = "MIT"
|
||||
@@ -13,10 +13,11 @@ python-osc = "^1.8.0"
|
||||
tomli = { version = "^2.0.1", python = "<3.11" }
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pytest = "^7.1.2"
|
||||
pytest = "^7.4.4"
|
||||
pytest-randomly = "^3.12.0"
|
||||
black = "^22.6.0"
|
||||
isort = "^5.10.1"
|
||||
ruff = "^0.8.6"
|
||||
tox = "^4.23.2"
|
||||
virtualenv-pyenv = "^0.5.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
@@ -27,3 +28,108 @@ obs = "scripts:ex_obs"
|
||||
sends = "scripts:ex_sends"
|
||||
xair = "scripts:test_xair"
|
||||
x32 = "scripts:test_x32"
|
||||
all = "scripts:test_all"
|
||||
|
||||
[tool.tox]
|
||||
legacy_tox_ini = """
|
||||
[tox]
|
||||
envlist = py310,py311,py312
|
||||
|
||||
[testenv]
|
||||
setenv = VIRTUALENV_DISCOVERY=pyenv
|
||||
allowlist_externals = poetry
|
||||
commands =
|
||||
poetry install -v
|
||||
poetry run pytest tests/
|
||||
"""
|
||||
|
||||
[tool.ruff]
|
||||
lint.select = [
|
||||
"E",
|
||||
"F",
|
||||
]
|
||||
lint.ignore = [
|
||||
"E501",
|
||||
]
|
||||
lint.fixable = [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"I",
|
||||
"N",
|
||||
"Q",
|
||||
"S",
|
||||
"T",
|
||||
"W",
|
||||
"ANN",
|
||||
"ARG",
|
||||
"BLE",
|
||||
"COM",
|
||||
"DJ",
|
||||
"DTZ",
|
||||
"EM",
|
||||
"ERA",
|
||||
"EXE",
|
||||
"FBT",
|
||||
"ICN",
|
||||
"INP",
|
||||
"ISC",
|
||||
"NPY",
|
||||
"PD",
|
||||
"PGH",
|
||||
"PIE",
|
||||
"PL",
|
||||
"PT",
|
||||
"PTH",
|
||||
"PYI",
|
||||
"RET",
|
||||
"RSE",
|
||||
"RUF",
|
||||
"SIM",
|
||||
"SLF",
|
||||
"TCH",
|
||||
"TID",
|
||||
"TRY",
|
||||
"UP",
|
||||
"YTT",
|
||||
]
|
||||
lint.unfixable = []
|
||||
exclude = [
|
||||
".bzr",
|
||||
".direnv",
|
||||
".eggs",
|
||||
".git",
|
||||
".git-rewrite",
|
||||
".hg",
|
||||
".mypy_cache",
|
||||
".nox",
|
||||
".pants.d",
|
||||
".pytype",
|
||||
".ruff_cache",
|
||||
".svn",
|
||||
".tox",
|
||||
".venv",
|
||||
"__pypackages__",
|
||||
"_build",
|
||||
"buck-out",
|
||||
"build",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"venv",
|
||||
]
|
||||
line-length = 88
|
||||
lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||
target-version = "py312"
|
||||
|
||||
[tool.ruff.lint.mccabe]
|
||||
max-complexity = 10
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"__init__.py" = [
|
||||
"E402",
|
||||
"F401",
|
||||
]
|
||||
@@ -21,3 +21,7 @@ def test_xair():
|
||||
def test_x32():
|
||||
path = Path.cwd() / "tests" / "x32"
|
||||
subprocess.run(["pytest", "-v", str(path)])
|
||||
|
||||
|
||||
def test_all():
|
||||
subprocess.run(["tox"])
|
||||
|
||||
@@ -8,7 +8,7 @@ from xair_api import kinds
|
||||
kind_id = "X32"
|
||||
ip = "x32.local"
|
||||
|
||||
tests = xair_api.connect(kind_id, ip=ip, delay=0.008)
|
||||
tests = xair_api.connect(kind_id, ip=ip)
|
||||
|
||||
kind = kinds.get(kind_id)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from xair_api import kinds
|
||||
kind_id = "MR18"
|
||||
ip = "mixer.local"
|
||||
|
||||
tests = xair_api.connect(kind_id, ip=ip, delay=0.008)
|
||||
tests = xair_api.connect(kind_id, ip=ip)
|
||||
|
||||
kind = kinds.get(kind_id)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .bus import Bus as IBus
|
||||
from .headamp import HeadAmp as IHeadAmp
|
||||
from .lr import LR as ILR
|
||||
from .rtn import AuxRtn as IAuxRtn
|
||||
from .rtn import FxRtn as IFxRtn
|
||||
@@ -25,16 +26,22 @@ class FxRtn(IFxRtn):
|
||||
class MainStereo(ILR):
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/main/st"
|
||||
return "/main/st"
|
||||
|
||||
|
||||
class MainMono(ILR):
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/main/m"
|
||||
return "/main/m"
|
||||
|
||||
|
||||
class Matrix(ILR):
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/mtx/{str(self.index).zfill(2)}"
|
||||
|
||||
|
||||
class HeadAmp(IHeadAmp):
|
||||
@property
|
||||
def address(self):
|
||||
return f"/headamp/{str(self.index).zfill(3)}"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import abc
|
||||
import logging
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import EQ, GEQ, Automix, Config, Dyn, Gate, Group, Insert, Mix, Preamp
|
||||
from .shared import EQ, GEQ, Config, Dyn, Group, Insert, Mix
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IBus(abc.ABC):
|
||||
@@ -11,6 +13,7 @@ class IBus(abc.ABC):
|
||||
def __init__(self, remote, index: int):
|
||||
self._remote = remote
|
||||
self.index = index + 1
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str):
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import abc
|
||||
import logging
|
||||
|
||||
from . import kinds, util
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import bool_prop
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IConfig(abc.ABC):
|
||||
"""Abstract Base Class for config"""
|
||||
|
||||
def __init__(self, remote):
|
||||
self._remote = remote
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str):
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
@@ -33,8 +36,8 @@ class Config(IConfig):
|
||||
Returns a Config class of a kind.
|
||||
"""
|
||||
LINKS_cls = _make_links_mixins[remote.kind.id_]
|
||||
MUTEGROUP_cls = type(f"MuteGroup", (Config.MuteGroup, cls), {})
|
||||
MONITOR_cls = type(f"ConfigMonitor", (Config.Monitor, cls), {})
|
||||
MUTEGROUP_cls = type("MuteGroup", (Config.MuteGroup, cls), {})
|
||||
MONITOR_cls = type("ConfigMonitor", (Config.Monitor, cls), {})
|
||||
CONFIG_cls = type(
|
||||
f"Config{remote.kind}",
|
||||
(cls, LINKS_cls),
|
||||
@@ -47,7 +50,7 @@ class Config(IConfig):
|
||||
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/config"
|
||||
return "/config"
|
||||
|
||||
@property
|
||||
def amixenable(self) -> bool:
|
||||
@@ -105,7 +108,7 @@ class Config(IConfig):
|
||||
|
||||
@source.setter
|
||||
def source(self, val: int):
|
||||
self.setter(f"source", val)
|
||||
self.setter("source", val)
|
||||
|
||||
@property
|
||||
def sourcetrim(self) -> float:
|
||||
@@ -114,7 +117,9 @@ class Config(IConfig):
|
||||
@sourcetrim.setter
|
||||
def sourcetrim(self, val: float):
|
||||
if not -18 <= val <= 18:
|
||||
raise XAirRemoteError("expected value in range -18.0 to 18.0")
|
||||
self.logger.warning(
|
||||
f"sourcetrim got {val}, expected value in range -18.0 to 18.0"
|
||||
)
|
||||
self.setter("sourcetrim", util.lin_set(-18, 18, val))
|
||||
|
||||
@property
|
||||
@@ -140,7 +145,9 @@ class Config(IConfig):
|
||||
@dimgain.setter
|
||||
def dimgain(self, val: int):
|
||||
if not -40 <= val <= 0:
|
||||
raise XAirRemoteError("expected value in range -40 to 0")
|
||||
self.logger.warning(
|
||||
f"dimgain got {val}, expected value in range -40 to 0"
|
||||
)
|
||||
self.setter("dimatt", util.lin_set(-40, 0, val))
|
||||
|
||||
@property
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import abc
|
||||
import logging
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IDCA(abc.ABC):
|
||||
@@ -9,6 +10,7 @@ class IDCA(abc.ABC):
|
||||
def __init__(self, remote, index: int):
|
||||
self._remote = remote
|
||||
self.index = index + 1
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str) -> tuple:
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
@@ -50,7 +52,7 @@ class DCA(IDCA):
|
||||
|
||||
@name.setter
|
||||
def name(self, val: str):
|
||||
self.setter("config/name")[0]
|
||||
self.setter("config/name", val)
|
||||
|
||||
@property
|
||||
def color(self) -> int:
|
||||
|
||||
@@ -1,2 +1,14 @@
|
||||
class XAirRemoteError(Exception):
|
||||
"""Base error class for XAIR Remote."""
|
||||
|
||||
|
||||
class XAirRemoteConnectionTimeoutError(XAirRemoteError):
|
||||
"""Exception raised when a connection attempt times out"""
|
||||
|
||||
def __init__(self, ip, port):
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
|
||||
super().__init__(
|
||||
f"Timeout attempting to connect to mixer at {self.ip}:{self.port}"
|
||||
)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import abc
|
||||
import logging
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import EQ, GEQ, Automix, Config, Dyn, Gate, Group, Insert, Mix, Preamp
|
||||
from .shared import Config, Group, Mix
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IFX(abc.ABC):
|
||||
@@ -11,6 +13,7 @@ class IFX(abc.ABC):
|
||||
def __init__(self, remote, index: int):
|
||||
self._remote = remote
|
||||
self.index = index + 1
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str):
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
|
||||
49
xair_api/headamp.py
Normal file
49
xair_api/headamp.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import abc
|
||||
import logging
|
||||
|
||||
from . import util
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IHeadAmp(abc.ABC):
|
||||
"""Abstract Base Class for headamps"""
|
||||
|
||||
def __init__(self, remote, index: int):
|
||||
self._remote = remote
|
||||
self.index = index + 1
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str):
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
|
||||
def setter(self, param: str, val: int):
|
||||
self._remote.send(f"{self.address}/{param}", val)
|
||||
|
||||
@abc.abstractmethod
|
||||
def address(self):
|
||||
pass
|
||||
|
||||
|
||||
class HeadAmp(IHeadAmp):
|
||||
"""Concrete class for headamps"""
|
||||
|
||||
@property
|
||||
def address(self):
|
||||
return f"/headamp/{str(self.index).zfill(2)}"
|
||||
|
||||
@property
|
||||
def gain(self):
|
||||
return round(util.lin_get(-12, 60, self.getter("gain")[0]), 1)
|
||||
|
||||
@gain.setter
|
||||
def gain(self, val):
|
||||
self.setter("gain", util.lin_set(-12, 60, val))
|
||||
|
||||
@property
|
||||
def phantom(self):
|
||||
return self.getter("phantom")[0] == 1
|
||||
|
||||
@phantom.setter
|
||||
def phantom(self, val):
|
||||
self.setter("phantom", 1 if val else 0)
|
||||
@@ -16,6 +16,7 @@ class X32KindMap(KindMap):
|
||||
num_fx: int = 8
|
||||
num_auxrtn: int = 8
|
||||
num_matrix: int = 6
|
||||
num_headamp: int = 127
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import abc
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import EQ, GEQ, Automix, Config, Dyn, Gate, Group, Insert, Mix, Preamp
|
||||
from .shared import EQ, GEQ, Config, Dyn, Insert, Mix
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ILR(abc.ABC):
|
||||
@@ -13,6 +15,7 @@ class ILR(abc.ABC):
|
||||
self._remote = remote
|
||||
if index is not None:
|
||||
self.index = index + 1
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str):
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
@@ -61,4 +64,4 @@ class LR(ILR):
|
||||
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/lr"
|
||||
return "/lr"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from .errors import XAirRemoteError
|
||||
from .util import lin_get, lin_set
|
||||
|
||||
|
||||
@@ -51,13 +50,6 @@ def float_prop(param):
|
||||
|
||||
|
||||
def geq_prop(param):
|
||||
# fmt: off
|
||||
opts = {
|
||||
"1k": 1000, "1k25": 1250, "1k6": 1600, "2k": 2000, "3k15": 3150, "4k": 4000,
|
||||
"5k": 5000, "6k3": 6300, "8k": 8000, "10k": 10000, "12k5": 12500, "16k": 16000,
|
||||
"20k": 20000,
|
||||
}
|
||||
# fmt: on
|
||||
param = param.replace("_", ".")
|
||||
|
||||
def fget(self) -> float:
|
||||
@@ -65,7 +57,9 @@ def geq_prop(param):
|
||||
|
||||
def fset(self, val):
|
||||
if not -15 <= val <= 15:
|
||||
raise XAirRemoteError("expected value in range -15.0 to 15.0")
|
||||
self.logger.warning(
|
||||
f"slider_{param} got {val}, expected value in range -15.0 to 15.0"
|
||||
)
|
||||
self.setter(param, lin_set(-15, 15, val))
|
||||
|
||||
return property(fget, fset)
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import abc
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import (
|
||||
EQ,
|
||||
GEQ,
|
||||
Automix,
|
||||
Config,
|
||||
Dyn,
|
||||
Gate,
|
||||
Group,
|
||||
Insert,
|
||||
Mix,
|
||||
Preamp,
|
||||
Send,
|
||||
)
|
||||
from .shared import EQ, Config, Group, Mix, Preamp, Send
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IRtn(abc.ABC):
|
||||
@@ -25,6 +15,7 @@ class IRtn(abc.ABC):
|
||||
self._remote = remote
|
||||
if index is not None:
|
||||
self.index = index + 1
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str):
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from typing import Optional, Union
|
||||
|
||||
from . import util
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import geq_prop
|
||||
|
||||
"""
|
||||
@@ -61,7 +60,9 @@ class Preamp:
|
||||
@usbtrim.setter
|
||||
def usbtrim(self, val: float):
|
||||
if not -18 <= val <= 18:
|
||||
raise XAirRemoteError("expected value in range -18.0 to 18.0")
|
||||
self.logger.warning(
|
||||
f"usbtrim got {val}, expected value in range -18.0 to 18.0"
|
||||
)
|
||||
self.setter("rtntrim", util.lin_set(-18, 18, val))
|
||||
|
||||
@property
|
||||
@@ -95,7 +96,9 @@ class Preamp:
|
||||
@highpassfilter.setter
|
||||
def highpassfilter(self, val: int):
|
||||
if not 20 <= val <= 400:
|
||||
raise XAirRemoteError("expected value in range 20 to 400")
|
||||
self.logger.warning(
|
||||
f"highpassfilter got {val}, expected value in range 20 to 400"
|
||||
)
|
||||
self.setter("hpf", util.log_set(20, 400, val))
|
||||
|
||||
|
||||
@@ -122,7 +125,7 @@ class Gate:
|
||||
def mode(self, val: str):
|
||||
opts = ("gate", "exp2", "exp3", "exp4", "duck")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.logger.warning(f"mode got {val}, expected one of {opts}")
|
||||
self.setter("mode", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -132,7 +135,9 @@ class Gate:
|
||||
@threshold.setter
|
||||
def threshold(self, val: float):
|
||||
if not -80 <= val <= 0:
|
||||
raise XAirRemoteError("expected value in range -80.0 to 0.0")
|
||||
self.logger.warning(
|
||||
f"threshold got {val}, expected value in range -80.0 to 0.0"
|
||||
)
|
||||
self.setter("thr", util.lin_set(-80, 0, val))
|
||||
|
||||
@property
|
||||
@@ -142,7 +147,7 @@ class Gate:
|
||||
@range.setter
|
||||
def range(self, val: int):
|
||||
if not 3 <= val <= 60:
|
||||
raise XAirRemoteError("expected value in range 3 to 60")
|
||||
self.logger.warning(f"range got {val}, expected value in range 3 to 60")
|
||||
self.setter("range", util.lin_set(3, 60, val))
|
||||
|
||||
@property
|
||||
@@ -152,7 +157,7 @@ class Gate:
|
||||
@attack.setter
|
||||
def attack(self, val: int):
|
||||
if not 0 <= val <= 120:
|
||||
raise XAirRemoteError("expected value in range 0 to 120")
|
||||
self.logger.warning(f"attack got {val}, expected value in range 0 to 120")
|
||||
self.setter("attack", util.lin_set(0, 120, val))
|
||||
|
||||
@property
|
||||
@@ -163,7 +168,9 @@ class Gate:
|
||||
@hold.setter
|
||||
def hold(self, val: float):
|
||||
if not 0.02 <= val <= 2000:
|
||||
raise XAirRemoteError("expected value in range 0.02 to 2000.0")
|
||||
self.logger.warning(
|
||||
f"hold got {val}, expected value in range 0.02 to 2000.0"
|
||||
)
|
||||
self.setter("hold", util.log_set(0.02, 2000, val))
|
||||
|
||||
@property
|
||||
@@ -173,7 +180,7 @@ class Gate:
|
||||
@release.setter
|
||||
def release(self, val: int):
|
||||
if not 5 <= val <= 4000:
|
||||
raise XAirRemoteError("expected value in range 5 to 4000")
|
||||
self.logger.warning(f"release got {val}, expected value in range 5 to 4000")
|
||||
self.setter("release", util.log_set(5, 4000, val))
|
||||
|
||||
@property
|
||||
@@ -208,7 +215,9 @@ class Gate:
|
||||
@filterfreq.setter
|
||||
def filterfreq(self, val: Union[float, int]):
|
||||
if not 20 <= val <= 20000:
|
||||
raise XAirRemoteError("expected value in range 20 to 20000")
|
||||
self.logger.warning(
|
||||
f"filterfreq got {val}, expected value in range 20 to 20000"
|
||||
)
|
||||
self.setter("filter/f", util.log_set(20, 20000, val))
|
||||
|
||||
|
||||
@@ -235,7 +244,7 @@ class Dyn:
|
||||
def mode(self, val: str):
|
||||
opts = ("comp", "exp")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.logger.warning(f"mode got {val}, expected one of {opts}")
|
||||
self.setter("mode", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -247,7 +256,7 @@ class Dyn:
|
||||
def det(self, val: str):
|
||||
opts = ("peak", "rms")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.logger.warning(f"det got {val}, expected one of {opts}")
|
||||
self.setter("det", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -259,7 +268,7 @@ class Dyn:
|
||||
def env(self, val: str):
|
||||
opts = ("lin", "log")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.logger.warning(f"env got {val}, expected one of {opts}")
|
||||
self.setter("env", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -269,7 +278,9 @@ class Dyn:
|
||||
@threshold.setter
|
||||
def threshold(self, val: float):
|
||||
if not -60 <= val <= 0:
|
||||
raise XAirRemoteError("expected value in range -60.0 to 0")
|
||||
self.logger.warning(
|
||||
f"threshold got {val}, expected value in range -60.0 to 0"
|
||||
)
|
||||
self.setter("thr", util.lin_set(-60, 0, val))
|
||||
|
||||
@property
|
||||
@@ -288,7 +299,7 @@ class Dyn:
|
||||
@knee.setter
|
||||
def knee(self, val: int):
|
||||
if not 0 <= val <= 5:
|
||||
raise XAirRemoteError("expected value in range 0 to 5")
|
||||
self.logger.warning(f"knee got {val}, expected value in range 0 to 5")
|
||||
self.setter("knee", util.lin_set(0, 5, val))
|
||||
|
||||
@property
|
||||
@@ -298,7 +309,7 @@ class Dyn:
|
||||
@mgain.setter
|
||||
def mgain(self, val: float):
|
||||
if not 0 <= val <= 24:
|
||||
raise XAirRemoteError("expected value in range 0.0 to 24.0")
|
||||
self.logger.warning(f"mgain got {val}, expected value in range 0.0 to 24.0")
|
||||
self.setter("mgain", util.lin_set(0, 24, val))
|
||||
|
||||
@property
|
||||
@@ -308,7 +319,7 @@ class Dyn:
|
||||
@attack.setter
|
||||
def attack(self, val: int):
|
||||
if not 0 <= val <= 120:
|
||||
raise XAirRemoteError("expected value in range 0 to 120")
|
||||
self.logger.warning(f"attack got {val}, expected value in range 0 to 120")
|
||||
self.setter("attack", util.lin_set(0, 120, val))
|
||||
|
||||
@property
|
||||
@@ -319,7 +330,9 @@ class Dyn:
|
||||
@hold.setter
|
||||
def hold(self, val: float):
|
||||
if not 0.02 <= val <= 2000:
|
||||
raise XAirRemoteError("expected value in range 0.02 to 2000.0")
|
||||
self.logger.warning(
|
||||
f"hold got {val}, expected value in range 0.02 to 2000.0"
|
||||
)
|
||||
self.setter("hold", util.log_set(0.02, 2000, val))
|
||||
|
||||
@property
|
||||
@@ -329,7 +342,7 @@ class Dyn:
|
||||
@release.setter
|
||||
def release(self, val: int):
|
||||
if not 5 <= val <= 4000:
|
||||
raise XAirRemoteError("expected value in range 5 to 4000")
|
||||
self.logger.warning(f"release got {val}, expected value in range 5 to 4000")
|
||||
self.setter("release", util.log_set(5, 4000, val))
|
||||
|
||||
@property
|
||||
@@ -339,7 +352,7 @@ class Dyn:
|
||||
@mix.setter
|
||||
def mix(self, val: int):
|
||||
if not 0 <= val <= 100:
|
||||
raise XAirRemoteError("expected value in range 0 to 100")
|
||||
self.logger.warning(f"mix got {val}, expected value in range 0 to 100")
|
||||
self.setter("mix", util.lin_set(0, 100, val))
|
||||
|
||||
@property
|
||||
@@ -382,7 +395,9 @@ class Dyn:
|
||||
@filterfreq.setter
|
||||
def filterfreq(self, val: Union[float, int]):
|
||||
if not 20 <= val <= 20000:
|
||||
raise XAirRemoteError("expected value in range 20 to 20000")
|
||||
self.logger.warning(
|
||||
f"filterfreq got {val}, expected value in range 20 to 20000"
|
||||
)
|
||||
self.setter("filter/f", util.log_set(20, 20000, val))
|
||||
|
||||
|
||||
@@ -462,7 +477,7 @@ class EQ:
|
||||
def mode(self, val: str):
|
||||
opts = ("peq", "geq", "teq")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.logger.warning(f"mode got {val}, expected one of {opts}")
|
||||
self.setter("mode", opts.index(val))
|
||||
|
||||
class EQBand:
|
||||
@@ -481,7 +496,7 @@ class EQ:
|
||||
|
||||
@type.setter
|
||||
def type(self, val: int):
|
||||
self.setter(f"type", val)
|
||||
self.setter("type", val)
|
||||
|
||||
@property
|
||||
def frequency(self) -> float:
|
||||
@@ -491,7 +506,9 @@ class EQ:
|
||||
@frequency.setter
|
||||
def frequency(self, val: float):
|
||||
if not 20 <= val <= 20000:
|
||||
raise XAirRemoteError("expected value in range 20.0 to 20000.0")
|
||||
self.logger.warning(
|
||||
f"frequency got {val}, expected value in range 20.0 to 20000.0"
|
||||
)
|
||||
self.setter("f", util.log_set(20, 20000, val))
|
||||
|
||||
@property
|
||||
@@ -501,7 +518,9 @@ class EQ:
|
||||
@gain.setter
|
||||
def gain(self, val: float):
|
||||
if not -15 <= val <= 15:
|
||||
raise XAirRemoteError("expected value in range -15.0 to 15.0")
|
||||
self.logger.warning(
|
||||
f"gain got {val}, expected value in range -15.0 to 15.0"
|
||||
)
|
||||
self.setter("g", util.lin_set(-15, 15, val))
|
||||
|
||||
@property
|
||||
@@ -512,7 +531,9 @@ class EQ:
|
||||
@quality.setter
|
||||
def quality(self, val: float):
|
||||
if not 0.3 <= val <= 10:
|
||||
raise XAirRemoteError("expected value in range 0.3 to 10.0")
|
||||
self.logger.warning(
|
||||
f"quality got {val}, expected value in range 0.3 to 10.0"
|
||||
)
|
||||
self.setter("q", util.log_set(0.3, 10, val))
|
||||
|
||||
|
||||
@@ -528,7 +549,7 @@ class GEQ:
|
||||
f"slider_{param}": geq_prop(param)
|
||||
for param in [
|
||||
"20", "25", "31_5", "40", "50", "63", "80", "100", "125",
|
||||
"160", "200", "250", "315" "400", "500", "630", "800", "1k",
|
||||
"160", "200", "250", "315", "400", "500", "630", "800", "1k",
|
||||
"1k25", "1k6", "2k", "2k5", "3k15", "4k", "5k", "6k3", "8k",
|
||||
"10k", "12k5", "16k", "20k",
|
||||
]
|
||||
@@ -620,7 +641,9 @@ class Automix:
|
||||
@weight.setter
|
||||
def weight(self, val: float):
|
||||
if not -12 <= val <= 12:
|
||||
raise XAirRemoteError("expected value in range -12.0 to 12.0")
|
||||
self.logger.warning(
|
||||
f"weight got {val}, expected value in range -12.0 to 12.0"
|
||||
)
|
||||
self.setter("weight", util.lin_set(-12, 12, val))
|
||||
|
||||
|
||||
@@ -641,10 +664,10 @@ class Send:
|
||||
|
||||
@property
|
||||
@util.db_from
|
||||
def level(self):
|
||||
def level(self) -> float:
|
||||
return self.getter("level")[0]
|
||||
|
||||
@level.setter
|
||||
@util.db_to
|
||||
def level(self, val):
|
||||
def level(self, val: float):
|
||||
self.setter("level", val)
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
import abc
|
||||
import logging
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import (
|
||||
EQ,
|
||||
GEQ,
|
||||
Automix,
|
||||
Config,
|
||||
Dyn,
|
||||
Gate,
|
||||
Group,
|
||||
Insert,
|
||||
Mix,
|
||||
Preamp,
|
||||
Send,
|
||||
)
|
||||
from .shared import EQ, Automix, Config, Dyn, Gate, Group, Insert, Mix, Preamp, Send
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IStrip(abc.ABC):
|
||||
@@ -23,6 +13,7 @@ class IStrip(abc.ABC):
|
||||
def __init__(self, remote, index: int):
|
||||
self._remote = remote
|
||||
self.index = index + 1
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
|
||||
def getter(self, param: str) -> tuple:
|
||||
return self._remote.query(f"{self.address}/{param}")
|
||||
|
||||
@@ -1,6 +1,35 @@
|
||||
import functools
|
||||
import time
|
||||
from math import exp, log
|
||||
|
||||
from .errors import XAirRemoteConnectionTimeoutError
|
||||
|
||||
|
||||
def timeout(func):
|
||||
"""
|
||||
Times out the validate_connection function once time elapsed exceeds remote.connect_timeout.
|
||||
"""
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
remote, *_ = args
|
||||
|
||||
err = None
|
||||
start = time.time()
|
||||
while time.time() < start + remote.connect_timeout:
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
remote.logger.debug(f"login time: {round(time.time() - start, 2)}")
|
||||
err = None
|
||||
break
|
||||
except XAirRemoteConnectionTimeoutError as e:
|
||||
err = e
|
||||
continue
|
||||
if err:
|
||||
raise err
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def lin_get(min, max, val):
|
||||
return min + (max - min) * val
|
||||
|
||||
@@ -14,17 +14,20 @@ from pythonosc.dispatcher import Dispatcher
|
||||
from pythonosc.osc_message_builder import OscMessageBuilder
|
||||
from pythonosc.osc_server import BlockingOSCUDPServer
|
||||
|
||||
from . import adapter, kinds
|
||||
from . import adapter, kinds, util
|
||||
from .bus import Bus
|
||||
from .config import Config
|
||||
from .dca import DCA
|
||||
from .errors import XAirRemoteError
|
||||
from .errors import XAirRemoteConnectionTimeoutError, XAirRemoteError
|
||||
from .fx import FX, FXSend
|
||||
from .headamp import HeadAmp
|
||||
from .kinds import KindMap
|
||||
from .lr import LR
|
||||
from .rtn import AuxRtn, FxRtn
|
||||
from .strip import Strip
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OSCClientServer(BlockingOSCUDPServer):
|
||||
def __init__(self, address: str, dispatcher: Dispatcher):
|
||||
@@ -45,10 +48,6 @@ class OSCClientServer(BlockingOSCUDPServer):
|
||||
class XAirRemote(abc.ABC):
|
||||
"""Handles the communication with the mixer via the OSC protocol"""
|
||||
|
||||
logger = logging.getLogger("xair.xairremote")
|
||||
|
||||
_CONNECT_TIMEOUT = 0.5
|
||||
|
||||
_info_response = []
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@@ -57,6 +56,8 @@ class XAirRemote(abc.ABC):
|
||||
self.xair_ip = kwargs["ip"] or self._ip_from_toml()
|
||||
self.xair_port = kwargs["port"]
|
||||
self._delay = kwargs["delay"]
|
||||
self.connect_timeout = kwargs["connect_timeout"]
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
if not self.xair_ip:
|
||||
raise XAirRemoteError("No valid ip detected")
|
||||
self.server = OSCClientServer((self.xair_ip, self.xair_port), dispatcher)
|
||||
@@ -73,14 +74,11 @@ class XAirRemote(abc.ABC):
|
||||
conn = tomllib.load(f)
|
||||
return conn["connection"].get("ip")
|
||||
|
||||
@util.timeout
|
||||
def validate_connection(self):
|
||||
self.send("/xinfo")
|
||||
time.sleep(self._CONNECT_TIMEOUT)
|
||||
if not self.info_response:
|
||||
raise XAirRemoteError(
|
||||
"Failed to setup OSC connection to mixer. Please check for correct ip address."
|
||||
)
|
||||
print(
|
||||
if not self.query("/xinfo"):
|
||||
raise XAirRemoteConnectionTimeoutError(self.xair_ip, self.xair_port)
|
||||
self.logger.info(
|
||||
f"Successfully connected to {self.info_response[2]} at {self.info_response[0]}."
|
||||
)
|
||||
|
||||
@@ -116,7 +114,12 @@ def _make_remote(kind: KindMap) -> XAirRemote:
|
||||
"""
|
||||
|
||||
def init_x32(self, *args, **kwargs):
|
||||
defaultkwargs = {"ip": None, "port": 10023, "delay": 0.02}
|
||||
defaultkwargs = {
|
||||
"ip": None,
|
||||
"port": 10023,
|
||||
"delay": 0.02,
|
||||
"connect_timeout": 2,
|
||||
}
|
||||
kwargs = defaultkwargs | kwargs
|
||||
XAirRemote.__init__(self, *args, **kwargs)
|
||||
self.kind = kind
|
||||
@@ -132,9 +135,15 @@ def _make_remote(kind: KindMap) -> XAirRemote:
|
||||
self.fxreturn = tuple(adapter.FxRtn.make(self, i) for i in range(kind.num_fx))
|
||||
self.auxin = tuple(adapter.AuxRtn.make(self, i) for i in range(kind.num_auxrtn))
|
||||
self.config = Config.make(self)
|
||||
self.headamp = tuple(adapter.HeadAmp(self, i) for i in range(kind.num_headamp))
|
||||
|
||||
def init_xair(self, *args, **kwargs):
|
||||
defaultkwargs = {"ip": None, "port": 10024, "delay": 0.02}
|
||||
defaultkwargs = {
|
||||
"ip": None,
|
||||
"port": 10024,
|
||||
"delay": 0.02,
|
||||
"connect_timeout": 2,
|
||||
}
|
||||
kwargs = defaultkwargs | kwargs
|
||||
XAirRemote.__init__(self, *args, **kwargs)
|
||||
self.kind = kind
|
||||
@@ -147,6 +156,7 @@ def _make_remote(kind: KindMap) -> XAirRemote:
|
||||
self.fxreturn = tuple(FxRtn.make(self, i) for i in range(kind.num_fx))
|
||||
self.auxreturn = AuxRtn.make(self)
|
||||
self.config = Config.make(self)
|
||||
self.headamp = tuple(HeadAmp(self, i) for i in range(kind.num_strip))
|
||||
|
||||
if kind.id_ == "X32":
|
||||
return type(
|
||||
@@ -174,9 +184,10 @@ def request_remote_obj(kind_id: str, *args, **kwargs) -> XAirRemote:
|
||||
|
||||
Returns a reference to an XAirRemote class of a kind
|
||||
"""
|
||||
|
||||
XAIRREMOTE_cls = None
|
||||
try:
|
||||
XAIRREMOTE_cls = _remotes[kind_id]
|
||||
except ValueError as e:
|
||||
raise SystemExit(e)
|
||||
except KeyError as e:
|
||||
raise XAirRemoteError(f"Unknown mixer kind '{kind_id}'") from e
|
||||
return XAIRREMOTE_cls(*args, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user