mirror of
https://github.com/onyx-and-iris/xair-api-python.git
synced 2026-04-18 13:33:31 +00:00
Compare commits
24 Commits
main
...
a1062e92b5
| Author | SHA1 | Date | |
|---|---|---|---|
| a1062e92b5 | |||
| ac382c4c32 | |||
|
|
a09b07e1c2 | ||
|
|
e7d38bb9d7 | ||
|
|
2255da4e53 | ||
|
|
6ab7d03a11 | ||
|
|
87217f6f9c | ||
|
|
fb8d3dee75 | ||
|
|
4973eb3215 | ||
|
|
65a817ed87 | ||
|
|
0b20ac953f | ||
|
|
7015383b98 | ||
|
|
981f4b57f8 | ||
|
|
2732e56a86 | ||
|
|
315dc64feb | ||
|
|
4a36e4a2ce | ||
|
|
858275beda | ||
|
|
d6fe34aef4 | ||
|
|
0606c8d107 | ||
|
|
78cd0b489a | ||
|
|
6944ba5128 | ||
|
|
e4dc4d0b13 | ||
|
|
079d1b308d | ||
|
|
a69734b738 |
36
CHANGELOG.md
36
CHANGELOG.md
@@ -9,7 +9,41 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- [x]
|
||||
- [ ]
|
||||
|
||||
## [2.1.0] - 2022-11-08
|
||||
|
||||
### Added
|
||||
|
||||
- delay keyword argument
|
||||
- bounds checks for vals passed to lin_set/log_set
|
||||
|
||||
### Removed
|
||||
|
||||
- type checks, prefer duck typing
|
||||
|
||||
## [2.0.0] - 2022-11-07
|
||||
|
||||
Some support for the X32 mixer has been added using an adapter module but the code related to the XAir api has been left largely untouched.
|
||||
However, a couple of changes have been made which are breaking, they are as follows:
|
||||
|
||||
### Changed
|
||||
|
||||
- FX class added to fx module. This now deals with osc addresses that begin with "/fx/". Call it with mixer.fx.
|
||||
- FxRtn class added to rtn module. This now deals with addresses that begin with "/rtn/". Call it with mixer.fxreturn
|
||||
- Aux class renamed to AuxRtn in rtn module. Call it with mixer.auxreturn.
|
||||
|
||||
These changes were made to better resemble the underlying osc api and to better describe the function of the classes.
|
||||
|
||||
### Added
|
||||
|
||||
- A small number of X32 tests. More will be added. XAir tests moved into it's own test module.
|
||||
- XAirRemote lower level section added to README.
|
||||
- Links to OSC command documentation added to README.
|
||||
|
||||
### Removed
|
||||
|
||||
- mixer.aux was renamed to mixer.auxreturn
|
||||
|
||||
## [1.1.0] - 2022-09-05
|
||||
|
||||
|
||||
84
README.md
84
README.md
@@ -2,7 +2,7 @@
|
||||
[](https://github.com/onyx-and-iris/xair-api-python/blob/dev/LICENSE)
|
||||
[](https://github.com/psf/black)
|
||||
[](https://pycqa.github.io/isort/)
|
||||

|
||||

|
||||
|
||||
# Xair API
|
||||
|
||||
@@ -40,6 +40,9 @@ import xair_api
|
||||
|
||||
|
||||
def main():
|
||||
kind_id = "XR18"
|
||||
ip = "<ip address>"
|
||||
|
||||
with xair_api.connect(kind_id, ip=ip) as mixer:
|
||||
mixer.strip[8].config.name = "sm7b"
|
||||
mixer.strip[8].mix.on = True
|
||||
@@ -49,21 +52,29 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
kind_id = "MR18"
|
||||
ip = "<ip address>"
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
## API
|
||||
#### `xair_api.connect(kind_id, ip=ip, delay=delay)`
|
||||
|
||||
Currently the following devices are support:
|
||||
Currently the following devices are supported:
|
||||
|
||||
- `XR18`
|
||||
- `MR18`
|
||||
- `XR18`
|
||||
- `XR16`
|
||||
- `XR12`
|
||||
|
||||
The `X32` is partially supported. However, this document covers specifically the `XAir` series.
|
||||
|
||||
The following keyword arguments may be passed:
|
||||
|
||||
- `ip`: ip address of the mixer
|
||||
- `port`: mixer port, defaults to 10023 for x32 and 10024 for xair
|
||||
- `delay`: a delay between each command, defaults to 20ms.
|
||||
- a note about delay, stability may rely on network connection. For wired connections the delay can be safely reduced.
|
||||
|
||||
## API
|
||||
|
||||
### XAirRemote class (higher level)
|
||||
|
||||
`mixer.lr`
|
||||
@@ -82,6 +93,10 @@ A Bus tuple containing a class for each output bus channel
|
||||
|
||||
A DCA tuple containing a class for each DCA group
|
||||
|
||||
`mixer.fx`
|
||||
|
||||
An FX tuple containing a class for each FX channel
|
||||
|
||||
`mixer.fxsend`
|
||||
|
||||
An FXSend tuple containing a class for each FX Send channel
|
||||
@@ -90,13 +105,9 @@ An FXSend tuple containing a class for each FX Send channel
|
||||
|
||||
An FXReturn tuple containing a class for each FX Return channel
|
||||
|
||||
`mixer.aux`
|
||||
`mixer.auxreturn`
|
||||
|
||||
A class representing aux channel
|
||||
|
||||
`mixer.rtn`
|
||||
|
||||
An RTN tuple containing a class for each rtn channel
|
||||
A class representing auxreturn channel
|
||||
|
||||
`mixer.config`
|
||||
|
||||
@@ -122,12 +133,12 @@ Contains the subclasses:
|
||||
Contains the subclasses:
|
||||
(`Config`, `Mix`, `Group`)
|
||||
|
||||
### `Aux`
|
||||
### `FXRtn`
|
||||
|
||||
Contains the subclasses:
|
||||
(`Config`, `Preamp`, `EQ`, `Mix`, `Group`)
|
||||
|
||||
### `Rtn`
|
||||
### `AuxRtn`
|
||||
|
||||
Contains the subclasses:
|
||||
(`Config`, `Preamp`, `EQ`, `Mix`, `Group`)
|
||||
@@ -258,12 +269,14 @@ For the subclass `monitor` the following properties are available
|
||||
|
||||
- `level`: float, -inf to 10.0
|
||||
- `source`: int, from 0 to 14
|
||||
- `chmode` bool
|
||||
- `busmode` bool
|
||||
- `dim` bool
|
||||
- `mono` bool
|
||||
- `mute` bool
|
||||
- `dimfpl` bool
|
||||
- `sourcetrim`: float, from -18.0 to 18.0
|
||||
- `chmode`: bool
|
||||
- `busmode`: bool
|
||||
- `dim`: bool
|
||||
- `dimgain`: float, from -40.0 to 0.0
|
||||
- `mono`: bool
|
||||
- `mute`: bool
|
||||
- `dimfpl`: bool
|
||||
|
||||
for example: `config.monitor.chmode`
|
||||
|
||||
@@ -275,6 +288,29 @@ tuple containing a class for each mute group
|
||||
|
||||
for example: `config.mute_group[0].on = True`
|
||||
|
||||
### XAirRemote class (lower level)
|
||||
|
||||
Send an OSC command directly to the mixer
|
||||
|
||||
- `send(osc command, value)`
|
||||
|
||||
for example:
|
||||
|
||||
```python
|
||||
mixer.send("/ch/01/mix/on", 1)
|
||||
mixer.send("/bus/2/config/name", "somename")
|
||||
```
|
||||
|
||||
Query the value of a command:
|
||||
|
||||
- `query(osc command)`
|
||||
|
||||
for example:
|
||||
|
||||
```python
|
||||
print(mixer.query("/ch/01/mix/on"))
|
||||
```
|
||||
|
||||
### `Tests`
|
||||
|
||||
Unplug any expensive equipment before running tests.
|
||||
@@ -290,6 +326,12 @@ To run all tests:
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
|
||||
|
||||
## Documentation
|
||||
|
||||
[XAir OSC Commands](https://behringer.world/wiki/doku.php?id=x-air_osc)
|
||||
|
||||
[X32 OSC Commands](https://wiki.munichmakerlab.de/images/1/17/UNOFFICIAL_X32_OSC_REMOTE_PROTOCOL_%281%29.pdf)
|
||||
|
||||
## Special Thanks
|
||||
|
||||
[Peter Dikant](https://github.com/peterdikant) for writing the base class
|
||||
|
||||
@@ -2,6 +2,9 @@ import xair_api
|
||||
|
||||
|
||||
def main():
|
||||
kind_id = "XR18"
|
||||
ip = "<ip address>"
|
||||
|
||||
with xair_api.connect(kind_id, ip=ip) as mixer:
|
||||
mixer.strip[8].config.name = "sm7b"
|
||||
mixer.strip[8].config.on = True
|
||||
@@ -11,7 +14,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
kind_id = "MR18"
|
||||
ip = "<ip address>"
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "xair-api"
|
||||
version = "1.1.1"
|
||||
version = "2.2.2"
|
||||
description = "Remote control Behringer X-Air | Midas MR mixers through OSC"
|
||||
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
||||
license = "MIT"
|
||||
@@ -23,4 +23,6 @@ requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
obs = "examples.xair-obs.__main__:main"
|
||||
obs = "scripts:ex_obs"
|
||||
xair = "scripts:test_xair"
|
||||
x32 = "scripts:test_x32"
|
||||
|
||||
17
scripts.py
Normal file
17
scripts.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def ex_obs():
|
||||
path = Path.cwd() / "examples" / "xair_obs" / "."
|
||||
subprocess.run(["py", str(path)])
|
||||
|
||||
|
||||
def test_xair():
|
||||
path = Path.cwd() / "tests" / "xair"
|
||||
subprocess.run(["pytest", "-v", str(path)])
|
||||
|
||||
|
||||
def test_x32():
|
||||
path = Path.cwd() / "tests" / "x32"
|
||||
subprocess.run(["pytest", "-v", str(path)])
|
||||
@@ -1,40 +0,0 @@
|
||||
import sys
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
|
||||
import xair_api
|
||||
from xair_api import kinds
|
||||
|
||||
kind_id = "MR18"
|
||||
ip = "mixer.local"
|
||||
|
||||
tests = xair_api.connect(kind_id, ip=ip)
|
||||
|
||||
kind = kinds.get(kind_id)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Data:
|
||||
"""bounds data to map tests to a kind"""
|
||||
|
||||
name: str = kind.id_
|
||||
dca: int = kind.num_dca - 1
|
||||
strip: int = kind.num_strip - 1
|
||||
bus: int = kind.num_bus - 1
|
||||
fx: int = kind.num_fx - 1
|
||||
rtn: int = kind.num_rtn - 1
|
||||
|
||||
|
||||
data = Data()
|
||||
|
||||
|
||||
def setup_module():
|
||||
print(f"\nRunning tests for kind [{data.name}]\n", file=sys.stdout)
|
||||
tests.worker = threading.Thread(target=tests.run_server)
|
||||
tests.worker.daemon = True
|
||||
tests.worker.start()
|
||||
tests.validate_connection()
|
||||
|
||||
|
||||
def teardown_module():
|
||||
tests.server.shutdown()
|
||||
|
||||
41
tests/x32/__init__.py
Normal file
41
tests/x32/__init__.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import sys
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
|
||||
import xair_api
|
||||
from xair_api import kinds
|
||||
|
||||
kind_id = "X32"
|
||||
ip = "x32.local"
|
||||
|
||||
tests = xair_api.connect(kind_id, ip=ip, delay=0.008)
|
||||
|
||||
kind = kinds.get(kind_id)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Data:
|
||||
"""bounds test data to a kind"""
|
||||
|
||||
name: str = kind.id_
|
||||
dca: int = kind.num_dca - 1
|
||||
strip: int = kind.num_strip - 1
|
||||
bus: int = kind.num_bus - 1
|
||||
fx: int = kind.num_fx - 1
|
||||
auxrtn: int = kind.num_auxrtn - 1
|
||||
matrix: int = kind.num_matrix - 1
|
||||
|
||||
|
||||
data = Data()
|
||||
|
||||
|
||||
def setup_module():
|
||||
print(f"\nRunning tests for kind [{data.name}]\n", file=sys.stdout)
|
||||
tests.worker = threading.Thread(target=tests.run_server)
|
||||
tests.worker.daemon = True
|
||||
tests.worker.start()
|
||||
tests.validate_connection()
|
||||
|
||||
|
||||
def teardown_module():
|
||||
tests.server.shutdown()
|
||||
144
tests/x32/test_adapter.py
Normal file
144
tests/x32/test_adapter.py
Normal file
@@ -0,0 +1,144 @@
|
||||
import pytest
|
||||
|
||||
from tests.x32 import data, tests
|
||||
|
||||
""" STRIP TESTS """
|
||||
|
||||
|
||||
class TestSetAndGetStripMuteHigher:
|
||||
"""Mute"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "strip")[data.strip]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("mute", True), ("mute", False)],
|
||||
)
|
||||
def test_it_sets_and_gets_strip_mute_bool_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
class TestSetAndGetStripMixHigher:
|
||||
"""Mix"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "strip")
|
||||
self.target = getattr(self.target[data.strip], "mix")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("on", True), ("on", False)],
|
||||
)
|
||||
def test_it_sets_and_gets_strip_bool_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
""" BUS TESTS """
|
||||
|
||||
|
||||
class TestSetAndGetBusConfigHigher:
|
||||
"""Config"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "bus")
|
||||
self.target = getattr(self.target[data.bus], "config")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("color", 0), ("color", 15)],
|
||||
)
|
||||
def test_it_sets_and_gets_bus_int_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
""" AUXIN TESTS """
|
||||
|
||||
|
||||
class TestSetAndGetAuxInPreampHigher:
|
||||
"""Preamp"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "auxin")
|
||||
self.target = getattr(self.target[data.auxrtn], "preamp")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("invert", True), ("invert", False)],
|
||||
)
|
||||
def test_it_sets_and_gets_auxrtn_bool_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
""" FX RETURN TESTS """
|
||||
|
||||
|
||||
class TestSetAndGetFXReturnEQHigher:
|
||||
"""EQ"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "fxreturn")
|
||||
self.target = getattr(self.target[data.fx], "eq")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("on", True), ("on", False)],
|
||||
)
|
||||
def test_it_sets_and_gets_fxrtn_bool_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
""" MATRIX TESTS """
|
||||
|
||||
|
||||
class TestSetAndGetMatrixDynHigher:
|
||||
"""Dyn"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "matrix")
|
||||
self.target = getattr(self.target[data.matrix], "dyn")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("mode", "comp"), ("mode", "exp")],
|
||||
)
|
||||
def test_it_sets_and_gets_matrix_string_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
""" MAIN STEREO TESTS """
|
||||
|
||||
|
||||
class TestSetAndGetMainStereoInsertHigher:
|
||||
"""Insert"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "mainst")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("mode", "comp"), ("mode", "exp")],
|
||||
)
|
||||
def test_it_sets_and_gets_mainst_string_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="60" height="20" role="img" aria-label="tests: 67"><title>tests: 67</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="60" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="37" height="20" fill="#555"/><rect x="37" width="23" height="20" fill="#4c1"/><rect width="60" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="195" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">tests</text><text x="195" y="140" transform="scale(.1)" fill="#fff" textLength="270">tests</text><text aria-hidden="true" x="475" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="130">67</text><text x="475" y="140" transform="scale(.1)" fill="#fff" textLength="130">67</text></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="60" height="20" role="img" aria-label="tests: 77"><title>tests: 77</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="60" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="37" height="20" fill="#555"/><rect x="37" width="23" height="20" fill="#4c1"/><rect width="60" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="195" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">tests</text><text x="195" y="140" transform="scale(.1)" fill="#fff" textLength="270">tests</text><text aria-hidden="true" x="475" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="130">77</text><text x="475" y="140" transform="scale(.1)" fill="#fff" textLength="130">77</text></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
39
tests/xair/__init__.py
Normal file
39
tests/xair/__init__.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import sys
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
|
||||
import xair_api
|
||||
from xair_api import kinds
|
||||
|
||||
kind_id = "MR18"
|
||||
ip = "mixer.local"
|
||||
|
||||
tests = xair_api.connect(kind_id, ip=ip, delay=0.008)
|
||||
|
||||
kind = kinds.get(kind_id)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Data:
|
||||
"""bounds test data to a kind"""
|
||||
|
||||
name: str = kind.id_
|
||||
dca: int = kind.num_dca - 1
|
||||
strip: int = kind.num_strip - 1
|
||||
bus: int = kind.num_bus - 1
|
||||
fx: int = kind.num_fx - 1
|
||||
|
||||
|
||||
data = Data()
|
||||
|
||||
|
||||
def setup_module():
|
||||
print(f"\nRunning tests for kind [{data.name}]\n", file=sys.stdout)
|
||||
tests.worker = threading.Thread(target=tests.run_server)
|
||||
tests.worker.daemon = True
|
||||
tests.worker.start()
|
||||
tests.validate_connection()
|
||||
|
||||
|
||||
def teardown_module():
|
||||
tests.server.shutdown()
|
||||
@@ -1,6 +1,7 @@
|
||||
Function RunTests {
|
||||
$coverage = "./tests/pytest_coverage.log"
|
||||
$run_tests = "pytest -v --capture=tee-sys --junitxml=./tests/.coverage.xml"
|
||||
"Running tests in directory $PSScriptRoot" | Write-Host
|
||||
$coverage = Join-Path $PSScriptRoot "pytest_coverage.log"
|
||||
$run_tests = "pytest -v $PSScriptRoot --capture=tee-sys --junitxml=$(Join-Path $PSScriptRoot ".coverage.xml")"
|
||||
$match_pattern = "^=|^\s*$|^Running|^Using|^plugins|^collecting|^tests"
|
||||
|
||||
if ( Test-Path $coverage ) { Clear-Content $coverage }
|
||||
@@ -13,7 +14,7 @@ Function RunTests {
|
||||
}
|
||||
Write-Output "$(Get-TimeStamp)" | Out-File $coverage -Append
|
||||
|
||||
Invoke-Expression "genbadge tests -t 90 -i ./tests/.coverage.xml -o ./tests/$kind.svg"
|
||||
Invoke-Expression "genbadge tests -t 90 -i $(Join-Path $PSScriptRoot ".coverage.xml") -o $(Join-Path $PSScriptRoot "$kind.svg")"
|
||||
}
|
||||
|
||||
Function Get-TimeStamp {
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from tests import data, tests
|
||||
from tests.xair import data, tests
|
||||
|
||||
"""
|
||||
Not every subclass is tested for every superclass to avoid redundancy.
|
||||
@@ -106,6 +106,23 @@ class TestSetAndGetLRGEQHigher:
|
||||
""" STRIP TESTS """
|
||||
|
||||
|
||||
class TestSetAndGetStripMuteHigher:
|
||||
"""Mute"""
|
||||
|
||||
__test__ = True
|
||||
|
||||
def setup_class(self):
|
||||
self.target = getattr(tests, "strip")[data.strip]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"param,value",
|
||||
[("mute", True), ("mute", False)],
|
||||
)
|
||||
def test_it_sets_and_gets_strip_mute_bool_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
class TestSetAndGetStripMixHigher:
|
||||
"""Mix"""
|
||||
|
||||
@@ -259,7 +276,7 @@ class TestSetAndGetStripAutomixHigher:
|
||||
"param,value",
|
||||
[("group", 0), ("group", 2)],
|
||||
)
|
||||
def test_it_sets_and_gets_fxsend_int_params(self, param, value):
|
||||
def test_it_sets_and_gets_strip_int_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
@@ -267,7 +284,7 @@ class TestSetAndGetStripAutomixHigher:
|
||||
"param,value",
|
||||
[("weight", -10.5), ("weight", 3.5)],
|
||||
)
|
||||
def test_it_sets_and_gets_fxsend_float_params(self, param, value):
|
||||
def test_it_sets_and_gets_strip_float_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
@@ -326,7 +343,7 @@ class TestSetAndGetBusDynHigher:
|
||||
assert getattr(self.target, param) == value
|
||||
|
||||
|
||||
class TestSetAndGetBusDynHigher:
|
||||
class TestSetAndGetBusEQHigher:
|
||||
"""EQ"""
|
||||
|
||||
__test__ = True
|
||||
@@ -368,6 +385,6 @@ class TestSetAndGetFXSendGroupHigher:
|
||||
"param,value",
|
||||
[("dca", 0), ("dca", 12), ("mute", 3), ("mute", 8)],
|
||||
)
|
||||
def test_it_sets_and_gets_bus_bool_params(self, param, value):
|
||||
def test_it_sets_and_gets_fxsend_int_params(self, param, value):
|
||||
setattr(self.target, param, value)
|
||||
assert getattr(self.target, param) == value
|
||||
40
xair_api/adapter.py
Normal file
40
xair_api/adapter.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from .bus import Bus as IBus
|
||||
from .lr import LR as ILR
|
||||
from .rtn import AuxRtn as IAuxRtn
|
||||
from .rtn import FxRtn as IFxRtn
|
||||
|
||||
|
||||
class Bus(IBus):
|
||||
@property
|
||||
def address(self):
|
||||
return f"/bus/{str(self.index).zfill(2)}"
|
||||
|
||||
|
||||
class AuxRtn(IAuxRtn):
|
||||
@property
|
||||
def address(self):
|
||||
return f"/auxin/{str(self.index).zfill(2)}"
|
||||
|
||||
|
||||
class FxRtn(IFxRtn):
|
||||
@property
|
||||
def address(self):
|
||||
return f"/fxrtn/{str(self.index).zfill(2)}"
|
||||
|
||||
|
||||
class MainStereo(ILR):
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/main/st"
|
||||
|
||||
|
||||
class MainMono(ILR):
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/main/m"
|
||||
|
||||
|
||||
class Matrix(ILR):
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/mtx/{str(self.index).zfill(2)}"
|
||||
@@ -1,6 +1,7 @@
|
||||
import abc
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import EQ, GEQ, Automix, Config, Dyn, Gate, Group, Insert, Mix, Preamp
|
||||
|
||||
|
||||
@@ -52,7 +53,8 @@ class Bus(IBus):
|
||||
Mix,
|
||||
Group,
|
||||
)
|
||||
}
|
||||
},
|
||||
"mute": mute_prop(),
|
||||
},
|
||||
)
|
||||
return BUS_cls(remote, index)
|
||||
|
||||
@@ -57,8 +57,6 @@ class Config(IConfig):
|
||||
|
||||
@amixenable.setter
|
||||
def amixenable(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("amixenable is a bool parameter")
|
||||
self.setter("amixenable", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -67,8 +65,6 @@ class Config(IConfig):
|
||||
|
||||
@amixlock.setter
|
||||
def amixlock(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("amixlock is a bool parameter")
|
||||
self.setter("amixlock", 1 if val else 0)
|
||||
|
||||
class MuteGroup:
|
||||
@@ -87,8 +83,6 @@ class Config(IConfig):
|
||||
|
||||
@on.setter
|
||||
def on(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("on is a boolean parameter")
|
||||
self.setter(f"{self.i}", 1 if val else 0)
|
||||
|
||||
class Monitor:
|
||||
@@ -112,8 +106,6 @@ class Config(IConfig):
|
||||
|
||||
@source.setter
|
||||
def source(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("source is an int parameter")
|
||||
self.setter(f"source", val)
|
||||
|
||||
@property
|
||||
@@ -122,10 +114,8 @@ class Config(IConfig):
|
||||
|
||||
@sourcetrim.setter
|
||||
def sourcetrim(self, val: float):
|
||||
if not isinstance(val, float):
|
||||
raise XAirRemoteError(
|
||||
"sourcetrim is a float parameter, expected value in range -18 to 18"
|
||||
)
|
||||
if not -18 <= val <= 18:
|
||||
raise XAirRemoteError("expected value in range -18.0 to 18.0")
|
||||
self.setter("sourcetrim", lin_set(-18, 18, val))
|
||||
|
||||
@property
|
||||
@@ -134,8 +124,6 @@ class Config(IConfig):
|
||||
|
||||
@chmode.setter
|
||||
def chmode(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("chmode is a bool parameter")
|
||||
self.setter("chmode", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -144,8 +132,6 @@ class Config(IConfig):
|
||||
|
||||
@busmode.setter
|
||||
def busmode(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("busmode is a bool parameter")
|
||||
self.setter("busmode", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -154,10 +140,8 @@ class Config(IConfig):
|
||||
|
||||
@dimgain.setter
|
||||
def dimgain(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(
|
||||
"dimgain is an int parameter, expected value in range -40 to 0"
|
||||
)
|
||||
if not -40 <= val <= 0:
|
||||
raise XAirRemoteError("expected value in range -40 to 0")
|
||||
self.setter("dimatt", lin_set(-40, 0, val))
|
||||
|
||||
@property
|
||||
@@ -166,8 +150,6 @@ class Config(IConfig):
|
||||
|
||||
@dim.setter
|
||||
def dim(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("dim is a bool parameter")
|
||||
self.setter("dim", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -176,8 +158,6 @@ class Config(IConfig):
|
||||
|
||||
@mono.setter
|
||||
def mono(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("mono is a bool parameter")
|
||||
self.setter("mono", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -186,8 +166,6 @@ class Config(IConfig):
|
||||
|
||||
@mute.setter
|
||||
def mute(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("mute is a bool parameter")
|
||||
self.setter("mute", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -196,8 +174,6 @@ class Config(IConfig):
|
||||
|
||||
@dimfpl.setter
|
||||
def dimfpl(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("dimfpl is a bool parameter")
|
||||
self.setter("dimfpl", 1 if val else 0)
|
||||
|
||||
|
||||
|
||||
@@ -35,18 +35,22 @@ class DCA(IDCA):
|
||||
|
||||
@on.setter
|
||||
def on(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("on is a boolean parameter")
|
||||
self.setter("on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
def mute(self) -> bool:
|
||||
return not self.on
|
||||
|
||||
@mute.setter
|
||||
def mute(self, val: bool):
|
||||
self.on = not val
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.getter("config/name")[0]
|
||||
|
||||
@name.setter
|
||||
def name(self, val: str):
|
||||
if not isinstance(val, str):
|
||||
raise XAirRemoteError("name is a str parameter")
|
||||
self.setter("config/name")[0]
|
||||
|
||||
@property
|
||||
@@ -55,6 +59,4 @@ class DCA(IDCA):
|
||||
|
||||
@color.setter
|
||||
def color(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("color is an int parameter")
|
||||
self.setter("config/color", val)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import abc
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import EQ, GEQ, Automix, Config, Dyn, Gate, Group, Insert, Mix, Preamp
|
||||
|
||||
|
||||
@@ -23,6 +24,22 @@ class IFX(abc.ABC):
|
||||
pass
|
||||
|
||||
|
||||
class FX(IFX):
|
||||
"""Concrete class for fx"""
|
||||
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/fx/{self.index}"
|
||||
|
||||
@property
|
||||
def type(self) -> int:
|
||||
return self.getter("type")[0]
|
||||
|
||||
@type.setter
|
||||
def type(self, val: int):
|
||||
self.setter("type", val)
|
||||
|
||||
|
||||
class FXSend(IFX):
|
||||
"""Concrete class for fxsend"""
|
||||
|
||||
@@ -44,7 +61,8 @@ class FXSend(IFX):
|
||||
f"{_cls.__name__}{remote.kind}", (_cls, cls), {}
|
||||
)(remote, index)
|
||||
for _cls in (Config, Mix, Group)
|
||||
}
|
||||
},
|
||||
"mute": mute_prop(),
|
||||
},
|
||||
)
|
||||
return FXSEND_cls(remote, index)
|
||||
@@ -52,21 +70,3 @@ class FXSend(IFX):
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/fxsend/{self.index}"
|
||||
|
||||
|
||||
class FXReturn(IFX):
|
||||
"""Concrete class for fxreturn"""
|
||||
|
||||
@property
|
||||
def address(self) -> str:
|
||||
return f"/fx/{self.index}"
|
||||
|
||||
@property
|
||||
def type(self) -> int:
|
||||
return self.getter("type")[0]
|
||||
|
||||
@type.setter
|
||||
def type(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("type is an integer parameter")
|
||||
self.setter("type", val)
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
"""
|
||||
# osc slightly different, interface would need adjusting to support this mixer.
|
||||
|
||||
@dataclass
|
||||
class X32KindMap:
|
||||
id_: str = "X32"
|
||||
num_dca: int = 8
|
||||
num_strip: int = 32
|
||||
num_bus: int = 16
|
||||
num_fx: int = 8
|
||||
num_rtn: int = 6
|
||||
"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class KindMap:
|
||||
@@ -21,14 +8,24 @@ class KindMap:
|
||||
|
||||
|
||||
@dataclass
|
||||
class MR18KindMap(KindMap):
|
||||
# note ch 17-18 defined as aux rtn
|
||||
class X32KindMap(KindMap):
|
||||
id_: str
|
||||
num_dca: int = 8
|
||||
num_strip: int = 32
|
||||
num_bus: int = 16
|
||||
num_fx: int = 8
|
||||
num_auxrtn: int = 8
|
||||
num_matrix: int = 6
|
||||
|
||||
|
||||
@dataclass
|
||||
class XR18KindMap(KindMap):
|
||||
# note ch 17-18 defined as aux return
|
||||
id_: str
|
||||
num_dca: int = 4
|
||||
num_strip: int = 16
|
||||
num_bus: int = 6
|
||||
num_fx: int = 4
|
||||
num_rtn: int = 4
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -38,7 +35,6 @@ class XR16KindMap(KindMap):
|
||||
num_strip: int = 16
|
||||
num_bus: int = 4
|
||||
num_fx: int = 4
|
||||
num_rtn: int = 4
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -48,12 +44,12 @@ class XR12KindMap(KindMap):
|
||||
num_strip: int = 12
|
||||
num_bus: int = 2
|
||||
num_fx: int = 4
|
||||
num_rtn: int = 4
|
||||
|
||||
|
||||
_kinds = {
|
||||
"XR18": MR18KindMap(id_="XR18"),
|
||||
"MR18": MR18KindMap(id_="MR18"),
|
||||
"X32": X32KindMap(id_="X32"),
|
||||
"MR18": XR18KindMap(id_="MR18"),
|
||||
"XR18": XR18KindMap(id_="XR18"),
|
||||
"XR16": XR16KindMap(id_="XR16"),
|
||||
"XR12": XR12KindMap(id_="XR12"),
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import abc
|
||||
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
|
||||
|
||||
|
||||
class ILR(abc.ABC):
|
||||
"""Abstract Base Class for buses"""
|
||||
|
||||
def __init__(self, remote):
|
||||
def __init__(self, remote, index: Optional[int] = None):
|
||||
self._remote = remote
|
||||
if index is not None:
|
||||
self.index = index + 1
|
||||
|
||||
def getter(self, param: str):
|
||||
self._remote.send(f"{self.address}/{param}")
|
||||
@@ -26,7 +30,7 @@ class LR(ILR):
|
||||
"""Concrete class for buses"""
|
||||
|
||||
@classmethod
|
||||
def make(cls, remote):
|
||||
def make(cls, remote, index=None):
|
||||
"""
|
||||
Factory function for LR
|
||||
|
||||
@@ -41,19 +45,20 @@ class LR(ILR):
|
||||
**{
|
||||
_cls.__name__.lower(): type(
|
||||
f"{_cls.__name__}{remote.kind}", (_cls, cls), {}
|
||||
)(remote)
|
||||
)(remote, index)
|
||||
for _cls in (
|
||||
Config,
|
||||
Dyn,
|
||||
Insert,
|
||||
GEQ.make(),
|
||||
EQ.make_sixband(cls, remote),
|
||||
EQ.make_sixband(cls, remote, index),
|
||||
Mix,
|
||||
)
|
||||
},
|
||||
"mute": mute_prop(),
|
||||
},
|
||||
)
|
||||
return LR_cls(remote)
|
||||
return LR_cls(remote, index)
|
||||
|
||||
@property
|
||||
def address(self) -> str:
|
||||
|
||||
@@ -9,8 +9,6 @@ def bool_prop(param):
|
||||
return self.getter(param)[0] == 1
|
||||
|
||||
def fset(self, val):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError(f"{param} is a boolean parameter")
|
||||
self.setter(param, 1 if val else 0)
|
||||
|
||||
return property(fget, fset)
|
||||
@@ -23,8 +21,6 @@ def string_prop(param):
|
||||
return self.getter(param)[0]
|
||||
|
||||
def fset(self, val):
|
||||
if not isinstance(val, str):
|
||||
raise XAirRemoteError(f"{param} is a string parameter")
|
||||
self.setter(param, val)
|
||||
|
||||
return property(fget, fset)
|
||||
@@ -37,8 +33,6 @@ def int_prop(param):
|
||||
return int(self.getter(param)[0])
|
||||
|
||||
def fset(self, val):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(f"{param} is an integer parameter")
|
||||
self.setter(param, val)
|
||||
|
||||
return property(fget, fset)
|
||||
@@ -51,8 +45,6 @@ def float_prop(param):
|
||||
return round(self.getter(param)[0], 1)
|
||||
|
||||
def fset(self, val):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(f"{param} is a float parameter")
|
||||
self.setter(param, val)
|
||||
|
||||
return property(fget, fset)
|
||||
@@ -72,6 +64,18 @@ def geq_prop(param):
|
||||
return round(lin_get(-15, 15, self.getter(param)[0]), 1)
|
||||
|
||||
def fset(self, val):
|
||||
if not -15 <= val <= 15:
|
||||
raise XAirRemoteError("expected value in range -15.0 to 15.0")
|
||||
self.setter(param, lin_set(-15, 15, val))
|
||||
|
||||
return property(fget, fset)
|
||||
|
||||
|
||||
def mute_prop():
|
||||
def fget(self):
|
||||
return not self.mix.on
|
||||
|
||||
def fset(self, val):
|
||||
self.mix.on = not val
|
||||
|
||||
return property(fget, fset)
|
||||
|
||||
@@ -2,6 +2,7 @@ import abc
|
||||
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
|
||||
|
||||
|
||||
@@ -25,26 +26,24 @@ class IRtn(abc.ABC):
|
||||
pass
|
||||
|
||||
|
||||
class Aux(IRtn):
|
||||
class AuxRtn(IRtn):
|
||||
"""Concrete class for aux"""
|
||||
|
||||
@classmethod
|
||||
def make(cls, remote):
|
||||
def make(cls, remote, index=None):
|
||||
"""
|
||||
Factory function for aux
|
||||
|
||||
Factory function for auxrtn
|
||||
Creates a mixin of shared subclasses, sets them as class attributes.
|
||||
|
||||
Returns an Aux class of a kind.
|
||||
Returns an AuxRtn class of a kind.
|
||||
"""
|
||||
AUX_cls = type(
|
||||
f"Aux{remote.kind}",
|
||||
AUXRTN_cls = type(
|
||||
f"AuxRtn{remote.kind}",
|
||||
(cls,),
|
||||
{
|
||||
**{
|
||||
_cls.__name__.lower(): type(
|
||||
f"{_cls.__name__}{remote.kind}", (_cls, cls), {}
|
||||
)(remote)
|
||||
)(remote, index)
|
||||
for _cls in (
|
||||
Config,
|
||||
Preamp,
|
||||
@@ -52,35 +51,34 @@ class Aux(IRtn):
|
||||
Mix,
|
||||
Group,
|
||||
)
|
||||
}
|
||||
},
|
||||
"mute": mute_prop(),
|
||||
},
|
||||
)
|
||||
return AUX_cls(remote)
|
||||
return AUXRTN_cls(remote, index)
|
||||
|
||||
@property
|
||||
def address(self):
|
||||
return "/rtn/aux"
|
||||
|
||||
|
||||
class Rtn(IRtn):
|
||||
class FxRtn(IRtn):
|
||||
"""Concrete class for rtn"""
|
||||
|
||||
@classmethod
|
||||
def make(cls, remote, index):
|
||||
"""
|
||||
Factory function for rtn
|
||||
|
||||
Factory function for fxrtn
|
||||
Creates a mixin of shared subclasses, sets them as class attributes.
|
||||
|
||||
Returns an Rtn class of a kind.
|
||||
Returns an FxRtn class of a kind.
|
||||
"""
|
||||
RTN_cls = type(
|
||||
f"Rtn{remote.kind.id_}",
|
||||
FXRTN_cls = type(
|
||||
f"FxRtn{remote.kind}",
|
||||
(cls,),
|
||||
{
|
||||
**{
|
||||
_cls.__name__.lower(): type(
|
||||
f"{_cls.__name__}{remote.kind.id_}", (_cls, cls), {}
|
||||
f"{_cls.__name__}{remote.kind}", (_cls, cls), {}
|
||||
)(remote, index)
|
||||
for _cls in (
|
||||
Config,
|
||||
@@ -89,10 +87,11 @@ class Rtn(IRtn):
|
||||
Mix,
|
||||
Group,
|
||||
)
|
||||
}
|
||||
},
|
||||
"mute": mute_prop(),
|
||||
},
|
||||
)
|
||||
return RTN_cls(remote, index)
|
||||
return FXRTN_cls(remote, index)
|
||||
|
||||
@property
|
||||
def address(self):
|
||||
|
||||
@@ -5,7 +5,7 @@ from .meta import geq_prop
|
||||
from .util import _get_fader_val, _set_fader_val, lin_get, lin_set, log_get, log_set
|
||||
|
||||
"""
|
||||
Classes shared by /ch, /rtn, /rt/aux, /bus, /fxsend, /lr
|
||||
Classes shared by /ch, /rtn, /rtn/aux, /bus, /fxsend, /lr
|
||||
"""
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ class Config:
|
||||
|
||||
@name.setter
|
||||
def name(self, val: str):
|
||||
if not isinstance(val, str):
|
||||
raise XAirRemoteError("name is a string parameter")
|
||||
self.setter("name", val)
|
||||
|
||||
@property
|
||||
@@ -31,8 +29,6 @@ class Config:
|
||||
|
||||
@color.setter
|
||||
def color(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("color is an int parameter")
|
||||
self.setter("color", val)
|
||||
|
||||
@property
|
||||
@@ -41,8 +37,6 @@ class Config:
|
||||
|
||||
@inputsource.setter
|
||||
def inputsource(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("inputsource is an int parameter")
|
||||
self.setter("insrc", val)
|
||||
|
||||
@property
|
||||
@@ -51,8 +45,6 @@ class Config:
|
||||
|
||||
@usbreturn.setter
|
||||
def usbreturn(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("usbreturn is an int parameter")
|
||||
self.setter("rtnsrc", val)
|
||||
|
||||
|
||||
@@ -68,10 +60,8 @@ class Preamp:
|
||||
|
||||
@usbtrim.setter
|
||||
def usbtrim(self, val: float):
|
||||
if not isinstance(val, float):
|
||||
raise XAirRemoteError(
|
||||
"usbtrim is a float parameter, expected value in range -18 to 18"
|
||||
)
|
||||
if not -18 <= val <= 18:
|
||||
raise XAirRemoteError("expected value in range -18.0 to 18.0")
|
||||
self.setter("rtntrim", lin_set(-18, 18, val))
|
||||
|
||||
@property
|
||||
@@ -80,8 +70,6 @@ class Preamp:
|
||||
|
||||
@usbinput.setter
|
||||
def usbinput(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("rtnsw is a bool parameter")
|
||||
self.setter("rtnsw", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -90,8 +78,6 @@ class Preamp:
|
||||
|
||||
@invert.setter
|
||||
def invert(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("invert is a bool parameter")
|
||||
self.setter("invert", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -100,8 +86,6 @@ class Preamp:
|
||||
|
||||
@highpasson.setter
|
||||
def highpasson(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("hpon is a bool parameter")
|
||||
self.setter("hpon", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -110,8 +94,8 @@ class Preamp:
|
||||
|
||||
@highpassfilter.setter
|
||||
def highpassfilter(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("highpassfilter is an int parameter")
|
||||
if not 20 <= val <= 400:
|
||||
raise XAirRemoteError("expected value in range 20 to 400")
|
||||
self.setter("hpf", log_set(20, 400, val))
|
||||
|
||||
|
||||
@@ -127,8 +111,6 @@ class Gate:
|
||||
|
||||
@on.setter
|
||||
def on(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("on is a boolean parameter")
|
||||
self.setter("on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -139,8 +121,8 @@ class Gate:
|
||||
@mode.setter
|
||||
def mode(self, val: str):
|
||||
opts = ("gate", "exp2", "exp3", "exp4", "duck")
|
||||
if not isinstance(val, str) and val not in opts:
|
||||
raise XAirRemoteError(f"mode is a string parameter, expected one of {opts}")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.setter("mode", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -149,10 +131,8 @@ class Gate:
|
||||
|
||||
@threshold.setter
|
||||
def threshold(self, val: float):
|
||||
if not isinstance(val, float):
|
||||
raise XAirRemoteError(
|
||||
"threshold is a float parameter, expected value in range -80 to 0"
|
||||
)
|
||||
if not -80 <= val <= 0:
|
||||
raise XAirRemoteError("expected value in range -80.0 to 0.0")
|
||||
self.setter("thr", lin_set(-80, 0, val))
|
||||
|
||||
@property
|
||||
@@ -161,10 +141,8 @@ class Gate:
|
||||
|
||||
@range.setter
|
||||
def range(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(
|
||||
"range is an int parameter, expected value in range 3 to 60"
|
||||
)
|
||||
if not 3 <= val <= 60:
|
||||
raise XAirRemoteError("expected value in range 3 to 60")
|
||||
self.setter("range", lin_set(3, 60, val))
|
||||
|
||||
@property
|
||||
@@ -173,10 +151,8 @@ class Gate:
|
||||
|
||||
@attack.setter
|
||||
def attack(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(
|
||||
"attack is an int parameter, expected value in range 0 to 120"
|
||||
)
|
||||
if not 0 <= val <= 120:
|
||||
raise XAirRemoteError("expected value in range 0 to 120")
|
||||
self.setter("attack", lin_set(0, 120, val))
|
||||
|
||||
@property
|
||||
@@ -186,6 +162,8 @@ 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.setter("hold", log_set(0.02, 2000, val))
|
||||
|
||||
@property
|
||||
@@ -194,10 +172,8 @@ class Gate:
|
||||
|
||||
@release.setter
|
||||
def release(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(
|
||||
"release is an int parameter, expected value in range 5 to 4000"
|
||||
)
|
||||
if not 5 <= val <= 4000:
|
||||
raise XAirRemoteError("expected value in range 5 to 4000")
|
||||
self.setter("release", log_set(5, 4000, val))
|
||||
|
||||
@property
|
||||
@@ -206,8 +182,6 @@ class Gate:
|
||||
|
||||
@keysource.setter
|
||||
def keysource(self, val):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("keysource is an int parameter")
|
||||
self.setter("keysrc", val)
|
||||
|
||||
@property
|
||||
@@ -216,8 +190,6 @@ class Gate:
|
||||
|
||||
@filteron.setter
|
||||
def filteron(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("filteron is a boolean parameter")
|
||||
self.setter("filter/on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -226,8 +198,6 @@ class Gate:
|
||||
|
||||
@filtertype.setter
|
||||
def filtertype(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("filtertype is an int parameter")
|
||||
self.setter("filter/type", val)
|
||||
|
||||
@property
|
||||
@@ -237,6 +207,8 @@ 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.setter("filter/f", log_set(20, 20000, val))
|
||||
|
||||
|
||||
@@ -252,8 +224,6 @@ class Dyn:
|
||||
|
||||
@on.setter
|
||||
def on(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("on is a boolean parameter")
|
||||
self.setter("on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -264,8 +234,8 @@ class Dyn:
|
||||
@mode.setter
|
||||
def mode(self, val: str):
|
||||
opts = ("comp", "exp")
|
||||
if not isinstance(val, str) and val not in opts:
|
||||
raise XAirRemoteError(f"mode is a string parameter, expected one of {opts}")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.setter("mode", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -276,8 +246,8 @@ class Dyn:
|
||||
@det.setter
|
||||
def det(self, val: str):
|
||||
opts = ("peak", "rms")
|
||||
if not isinstance(val, str) and val not in opts:
|
||||
raise XAirRemoteError(f"det is a string parameter, expected one of {opts}")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.setter("det", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -288,8 +258,8 @@ class Dyn:
|
||||
@env.setter
|
||||
def env(self, val: str):
|
||||
opts = ("lin", "log")
|
||||
if not isinstance(val, str) and val not in opts:
|
||||
raise XAirRemoteError(f"env is a string parameter, expected one of {opts}")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.setter("env", opts.index(val))
|
||||
|
||||
@property
|
||||
@@ -298,10 +268,8 @@ class Dyn:
|
||||
|
||||
@threshold.setter
|
||||
def threshold(self, val: float):
|
||||
if not isinstance(val, float):
|
||||
raise XAirRemoteError(
|
||||
"threshold is a float parameter, expected value in range -80 to 0"
|
||||
)
|
||||
if not -60 <= val <= 0:
|
||||
raise XAirRemoteError("expected value in range -60.0 to 0")
|
||||
self.setter("thr", lin_set(-60, 0, val))
|
||||
|
||||
@property
|
||||
@@ -311,8 +279,6 @@ class Dyn:
|
||||
|
||||
@ratio.setter
|
||||
def ratio(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("ratio is an int parameter")
|
||||
self.setter("ratio", val)
|
||||
|
||||
@property
|
||||
@@ -321,10 +287,8 @@ class Dyn:
|
||||
|
||||
@knee.setter
|
||||
def knee(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(
|
||||
"knee is an int parameter, expected value in range 0 to 5"
|
||||
)
|
||||
if not 0 <= val <= 5:
|
||||
raise XAirRemoteError("expected value in range 0 to 5")
|
||||
self.setter("knee", lin_set(0, 5, val))
|
||||
|
||||
@property
|
||||
@@ -333,6 +297,8 @@ 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.setter("mgain", lin_set(0, 24, val))
|
||||
|
||||
@property
|
||||
@@ -341,6 +307,8 @@ class Dyn:
|
||||
|
||||
@attack.setter
|
||||
def attack(self, val: int):
|
||||
if not 0 <= val <= 120:
|
||||
raise XAirRemoteError("expected value in range 0 to 120")
|
||||
self.setter("attack", lin_set(0, 120, val))
|
||||
|
||||
@property
|
||||
@@ -350,6 +318,8 @@ 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.setter("hold", log_set(0.02, 2000, val))
|
||||
|
||||
@property
|
||||
@@ -358,10 +328,8 @@ class Dyn:
|
||||
|
||||
@release.setter
|
||||
def release(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(
|
||||
"release is an int parameter, expected value in range 5 to 4000"
|
||||
)
|
||||
if not 5 <= val <= 4000:
|
||||
raise XAirRemoteError("expected value in range 5 to 4000")
|
||||
self.setter("release", log_set(5, 4000, val))
|
||||
|
||||
@property
|
||||
@@ -370,10 +338,8 @@ class Dyn:
|
||||
|
||||
@mix.setter
|
||||
def mix(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError(
|
||||
"mix is an int parameter, expected value in range 0 to 5"
|
||||
)
|
||||
if not 0 <= val <= 100:
|
||||
raise XAirRemoteError("expected value in range 0 to 100")
|
||||
self.setter("mix", lin_set(0, 100, val))
|
||||
|
||||
@property
|
||||
@@ -382,8 +348,6 @@ class Dyn:
|
||||
|
||||
@keysource.setter
|
||||
def keysource(self, val):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("keysource is an int parameter")
|
||||
self.setter("keysrc", val)
|
||||
|
||||
@property
|
||||
@@ -392,8 +356,6 @@ class Dyn:
|
||||
|
||||
@auto.setter
|
||||
def auto(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("auto is a boolean parameter")
|
||||
self.setter("auto", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -402,8 +364,6 @@ class Dyn:
|
||||
|
||||
@filteron.setter
|
||||
def filteron(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("filteron is a boolean parameter")
|
||||
self.setter("filter/on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -412,8 +372,6 @@ class Dyn:
|
||||
|
||||
@filtertype.setter
|
||||
def filtertype(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("filtertype is an int parameter")
|
||||
self.setter("filter/type", val)
|
||||
|
||||
@property
|
||||
@@ -423,6 +381,8 @@ 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.setter("filter/f", log_set(20, 20000, val))
|
||||
|
||||
|
||||
@@ -438,8 +398,6 @@ class Insert:
|
||||
|
||||
@on.setter
|
||||
def on(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("on is a boolean parameter")
|
||||
self.setter("on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -448,8 +406,6 @@ class Insert:
|
||||
|
||||
@sel.setter
|
||||
def sel(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("sel is an int parameter")
|
||||
self.setter("sel", val)
|
||||
|
||||
|
||||
@@ -495,8 +451,6 @@ class EQ:
|
||||
|
||||
@on.setter
|
||||
def on(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("on is a boolean parameter")
|
||||
self.setter("on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -507,8 +461,8 @@ class EQ:
|
||||
@mode.setter
|
||||
def mode(self, val: str):
|
||||
opts = ("peq", "geq", "teq")
|
||||
if not isinstance(val, str) and val not in opts:
|
||||
raise XAirRemoteError(f"mode is a string parameter, expected one of {opts}")
|
||||
if val not in opts:
|
||||
raise XAirRemoteError(f"expected one of {opts}")
|
||||
self.setter("mode", opts.index(val))
|
||||
|
||||
class EQBand:
|
||||
@@ -530,8 +484,6 @@ class EQ:
|
||||
|
||||
@type.setter
|
||||
def type(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("type is an int parameter")
|
||||
self.setter(f"type", val)
|
||||
|
||||
@property
|
||||
@@ -541,6 +493,8 @@ 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.setter("f", log_set(20, 20000, val))
|
||||
|
||||
@property
|
||||
@@ -549,6 +503,8 @@ 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.setter("g", lin_set(-15, 15, val))
|
||||
|
||||
@property
|
||||
@@ -558,6 +514,8 @@ 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.setter("q", log_set(0.3, 10, val))
|
||||
|
||||
|
||||
@@ -600,8 +558,6 @@ class Mix:
|
||||
|
||||
@on.setter
|
||||
def on(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("on is a boolean parameter")
|
||||
self.setter("on", 1 if val else 0)
|
||||
|
||||
@property
|
||||
@@ -619,8 +575,6 @@ class Mix:
|
||||
|
||||
@lr.setter
|
||||
def lr(self, val: bool):
|
||||
if not isinstance(val, bool):
|
||||
raise XAirRemoteError("lr is a boolean parameter")
|
||||
self.setter("lr", 1 if val else 0)
|
||||
|
||||
|
||||
@@ -636,8 +590,6 @@ class Group:
|
||||
|
||||
@dca.setter
|
||||
def dca(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("dca is an int parameter")
|
||||
self.setter("dca", val)
|
||||
|
||||
@property
|
||||
@@ -646,8 +598,6 @@ class Group:
|
||||
|
||||
@mute.setter
|
||||
def mute(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("mute is an int parameter")
|
||||
self.setter("mute", val)
|
||||
|
||||
|
||||
@@ -663,8 +613,6 @@ class Automix:
|
||||
|
||||
@group.setter
|
||||
def group(self, val: int):
|
||||
if not isinstance(val, int):
|
||||
raise XAirRemoteError("group is an int parameter")
|
||||
self.setter("group", val)
|
||||
|
||||
@property
|
||||
@@ -673,8 +621,6 @@ class Automix:
|
||||
|
||||
@weight.setter
|
||||
def weight(self, val: float):
|
||||
if not isinstance(val, float):
|
||||
raise XAirRemoteError(
|
||||
"weight is a float parameter, expected value in range -12 to 12"
|
||||
)
|
||||
if not -12 <= val <= 12:
|
||||
raise XAirRemoteError("expected value in range -12.0 to 12.0")
|
||||
self.setter("weight", lin_set(-12, 12, val))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import abc
|
||||
|
||||
from .errors import XAirRemoteError
|
||||
from .meta import mute_prop
|
||||
from .shared import EQ, GEQ, Automix, Config, Dyn, Gate, Group, Insert, Mix, Preamp
|
||||
|
||||
|
||||
@@ -35,6 +36,7 @@ class Strip(IStrip):
|
||||
|
||||
Returns a Strip class of a kind.
|
||||
"""
|
||||
|
||||
STRIP_cls = type(
|
||||
f"Strip{remote.kind}",
|
||||
(cls,),
|
||||
@@ -55,6 +57,7 @@ class Strip(IStrip):
|
||||
Automix,
|
||||
)
|
||||
},
|
||||
"mute": mute_prop(),
|
||||
},
|
||||
)
|
||||
return STRIP_cls(remote, index)
|
||||
|
||||
103
xair_api/xair.py
103
xair_api/xair.py
@@ -1,8 +1,9 @@
|
||||
import abc
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
@@ -13,15 +14,15 @@ from pythonosc.dispatcher import Dispatcher
|
||||
from pythonosc.osc_message_builder import OscMessageBuilder
|
||||
from pythonosc.osc_server import BlockingOSCUDPServer
|
||||
|
||||
from . import kinds
|
||||
from . import adapter, kinds
|
||||
from .bus import Bus
|
||||
from .config import Config
|
||||
from .dca import DCA
|
||||
from .errors import XAirRemoteError
|
||||
from .fx import FXReturn, FXSend
|
||||
from .fx import FX, FXSend
|
||||
from .kinds import KindMap
|
||||
from .lr import LR
|
||||
from .rtn import Aux, Rtn
|
||||
from .rtn import AuxRtn, FxRtn
|
||||
from .strip import Strip
|
||||
|
||||
|
||||
@@ -30,15 +31,12 @@ class OSCClientServer(BlockingOSCUDPServer):
|
||||
super().__init__(("", 0), dispatcher)
|
||||
self.xr_address = address
|
||||
|
||||
def send_message(self, address: str, value: str):
|
||||
def send_message(self, address: str, vals: Optional[Union[str, list]]):
|
||||
builder = OscMessageBuilder(address=address)
|
||||
if value is None:
|
||||
values = list()
|
||||
elif isinstance(value, list):
|
||||
values = value
|
||||
else:
|
||||
values = [value]
|
||||
for val in values:
|
||||
vals = vals if vals is not None else []
|
||||
if not isinstance(vals, list):
|
||||
vals = [vals]
|
||||
for val in vals:
|
||||
builder.add_arg(val)
|
||||
msg = builder.build()
|
||||
self.socket.sendto(msg.dgram, self.xr_address)
|
||||
@@ -47,21 +45,20 @@ 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
|
||||
_WAIT_TIME = 0.025
|
||||
_REFRESH_TIMEOUT = 5
|
||||
|
||||
XAIR_PORT = 10024
|
||||
|
||||
info_response = []
|
||||
_info_response = []
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
dispatcher = Dispatcher()
|
||||
dispatcher.set_default_handler(self.msg_handler)
|
||||
self.xair_ip = kwargs["ip"] or self._ip_from_toml()
|
||||
self.xair_port = kwargs["port"] or self.XAIR_PORT
|
||||
if not (self.xair_ip and self.xair_port):
|
||||
raise XAirRemoteError("No valid ip or password detected")
|
||||
self.xair_port = kwargs["port"]
|
||||
self._delay = kwargs["delay"]
|
||||
if not self.xair_ip:
|
||||
raise XAirRemoteError("No valid ip detected")
|
||||
self.server = OSCClientServer((self.xair_ip, self.xair_port), dispatcher)
|
||||
|
||||
def __enter__(self):
|
||||
@@ -79,26 +76,32 @@ class XAirRemote(abc.ABC):
|
||||
def validate_connection(self):
|
||||
self.send("/xinfo")
|
||||
time.sleep(self._CONNECT_TIMEOUT)
|
||||
if len(self.info_response) > 0:
|
||||
print(f"Successfully connected to {self.info_response[2]}.")
|
||||
else:
|
||||
print(
|
||||
"Error: Failed to setup OSC connection to mixer. Please check for correct ip address."
|
||||
if not self.info_response:
|
||||
raise XAirRemoteError(
|
||||
"Failed to setup OSC connection to mixer. Please check for correct ip address."
|
||||
)
|
||||
print(
|
||||
f"Successfully connected to {self.info_response[2]} at {self.info_response[0]}."
|
||||
)
|
||||
|
||||
@property
|
||||
def info_response(self):
|
||||
return self._info_response
|
||||
|
||||
def run_server(self):
|
||||
self.server.serve_forever()
|
||||
|
||||
def msg_handler(self, addr, *data):
|
||||
self.info_response = data[:]
|
||||
self.logger.debug(f"received: {addr} {data if data else ''}")
|
||||
self._info_response = data[:]
|
||||
|
||||
def send(self, address: str, param: Optional[str] = None):
|
||||
self.server.send_message(address, param)
|
||||
time.sleep(self._WAIT_TIME)
|
||||
def send(self, addr: str, param: Optional[str] = None):
|
||||
self.logger.debug(f"sending: {addr} {param if param is not None else ''}")
|
||||
self.server.send_message(addr, param)
|
||||
time.sleep(self._delay)
|
||||
|
||||
def _query(self, address):
|
||||
def query(self, address):
|
||||
self.send(address)
|
||||
time.sleep(self._WAIT_TIME)
|
||||
return self.info_response
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_tr):
|
||||
@@ -112,8 +115,26 @@ def _make_remote(kind: KindMap) -> XAirRemote:
|
||||
The returned class will subclass XAirRemote.
|
||||
"""
|
||||
|
||||
def init(self, *args, **kwargs):
|
||||
defaultkwargs = {"ip": None, "port": None}
|
||||
def init_x32(self, *args, **kwargs):
|
||||
defaultkwargs = {"ip": None, "port": 10023, "delay": 0.02}
|
||||
kwargs = defaultkwargs | kwargs
|
||||
XAirRemote.__init__(self, *args, **kwargs)
|
||||
self.kind = kind
|
||||
self.mainst = adapter.MainStereo.make(self)
|
||||
self.mainmono = adapter.MainMono.make(self)
|
||||
self.matrix = tuple(
|
||||
adapter.Matrix.make(self, i) for i in range(kind.num_matrix)
|
||||
)
|
||||
self.strip = tuple(Strip.make(self, i) for i in range(kind.num_strip))
|
||||
self.bus = tuple(adapter.Bus.make(self, i) for i in range(kind.num_bus))
|
||||
self.dca = tuple(DCA(self, i) for i in range(kind.num_dca))
|
||||
self.fx = tuple(FX(self, i) for i in range(kind.num_fx))
|
||||
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)
|
||||
|
||||
def init_xair(self, *args, **kwargs):
|
||||
defaultkwargs = {"ip": None, "port": 10024, "delay": 0.02}
|
||||
kwargs = defaultkwargs | kwargs
|
||||
XAirRemote.__init__(self, *args, **kwargs)
|
||||
self.kind = kind
|
||||
@@ -121,17 +142,25 @@ def _make_remote(kind: KindMap) -> XAirRemote:
|
||||
self.strip = tuple(Strip.make(self, i) for i in range(kind.num_strip))
|
||||
self.bus = tuple(Bus.make(self, i) for i in range(kind.num_bus))
|
||||
self.dca = tuple(DCA(self, i) for i in range(kind.num_dca))
|
||||
self.fx = tuple(FX(self, i) for i in range(kind.num_fx))
|
||||
self.fxsend = tuple(FXSend.make(self, i) for i in range(kind.num_fx))
|
||||
self.fxreturn = tuple(FXReturn(self, i) for i in range(kind.num_fx))
|
||||
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.aux = Aux.make(self)
|
||||
self.rtn = tuple(Rtn.make(self, i) for i in range(kind.num_rtn))
|
||||
|
||||
if kind.id_ == "X32":
|
||||
return type(
|
||||
f"XAirRemote{kind}",
|
||||
(XAirRemote,),
|
||||
{
|
||||
"__init__": init_x32,
|
||||
},
|
||||
)
|
||||
return type(
|
||||
f"XAirRemote{kind}",
|
||||
(XAirRemote,),
|
||||
{
|
||||
"__init__": init,
|
||||
"__init__": init_xair,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user