# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['behringer_mixer']

package_data = \
{'': ['*']}

install_requires = \
['python-osc>=1.8.0,<2.0.0']

setup_kwargs = {
    'name': 'behringer-mixer',
    'version': '0.4.5',
    'description': 'Module to get basic information from Behringer digital mixers eg X32/XAir etc.',
    'long_description': '# behringer-mixer\nPython module to get basic information from Behringer digital mixers eg X32/XAir etc.\n\nInitial inspiration (and some code) comes from https://github.com/onyx-and-iris/xair-api-python.\n\n## What it does and what it doesn\'t do.\nThis module is a simple interface to a series of Behringer digital mixers.  It does NOT support all parameters or controls.  It is primarily focussed on getting and setting fader information.  It supports getting this information, both on a once off basis and subscribing for real-time updates.\n\nIt currently supports the following functionality for all channels/busses/matrices/auxin/dcas/main/lr:\n- Fader Value (float and dB) [get/set]\n- Fader Mute status [get/set]\n- Fader Name [get]\n\nIt also supports\n- Current scene/snapshot [get]\n- Change scene/snapshot [set]\n- Control USB Player/Recorder [get/set]\n- Current USB Filename [get]\n- Firmware version\n\nIf you want a module that allows you to control the full functionality of the mixer, eg configuring effects/eq etc then I would recommend checking out https://github.com/onyx-and-iris/xair-api-python instead.\n\n## Prerequisites\n\n-   Python 3.10 or greater\n\n## Installation\n\n```\npip install behringer-mixer\n```\n\n## Usage\n\nThis module depends on the asyncio module to handle multiple runnings tasks simultaneously.\n\n### Example\n```python\nimport asyncio\nimport logging\nfrom behringer_mixer import mixer_api\n\ndef updates_function(data):\n    print(f"The property {data.get(\'property\')} has been set to {data.get(\'value\')}")\n\nasync def main():\n    mixer  = mixer_api.create("X32", ip="192.168.201.149", logLevel=logging.WARNING)\n    await mixer.start()\n    state = await mixer.reload()\n    state = mixer.state()\n    print(state)\n    asyncio.create_task(mixer.subscribe(updates_function))\n    await mixer.set_value("/ch/1/mix_fader", 10)\n    await asyncio.sleep(20)\n\nif __name__ == "__main__":\n    asyncio.run(main())\n```\n\n### Property Keys\nThe data returned by both the `state` and `subscription` callback function is based on a number of property keys for the mixer.  While these keys are \'similar\' to the values used in the OSC commands they are not always the same.\n\nEach key is a mixture of a base \'group\' key eg `/ch/1/` and a more specific key.  \nThey keys have also been altered slightly to maintain a consistent approach between different mixers. eg. For channel/bus numbers the leading zero has been removed. on the XAir mixers the main fader is `/main/lr` whereas on the X32 it is `/main/st`.  This modules returns both as `/main/st`.\n\n#### `mixer_api.create("<mixer_type>", ip="<ip_address>")`\nThe code is written to support the following mixer types:\n- `X32`\n- `XR18`\n- `XR16`\n- `XR12`\n\nThe following keyword arguments may be passed:\n\n-   `ip`: ip address of the mixer (Required)\n-   `port`: mixer port, defaults to 10023 for x32 and 10024 for xair\n-   `delay`: a delay between each command, defaults to 20ms.\n    -   a note about delay, stability may rely on network connection. For wired connections the delay can be safely reduced.  \n-   `logLevel`: the level of logging, defaults to warning (enums from logging eg logging.DEBUG)\n\nThe create function only creates an instance of the mixer, it does not \'connect\' to it.\nYou should call the `mixer.start()` function to prepare communication and then call `mixer.validate_connection()` to check that the connection to the mixer worked.\n\n#### `mixer.firmware()`\nReturns the firmware version of the mixer.\n`\n#### `mixer.info()`\nReturns information about the mixer, giving the number of channels/busses etc as well as the base part of the \'address\' for that component.\n```\n        {\n            "channel": {\n                "number": 32,\n                "base_address": "ch",\n            },\n            "bus": {\n                "number": 16,\n                "base_address": "bus",\n            },\n            "matrix": {\n                "number": 6,\n                "base_address": "mtx",\n            },\n            "dca": {\n                "number": 8,\n                "base_address": "dca",\n            },\n            "fx": {\n                "number": 10,\n                "base_address": "fx",\n            },\n            "auxrtn": {\n                "number": 8,\n                "base_address": "auxrtn",\n            },\n            "scenes": {\n                "number": 100,\n                "base_address": "scene",\n            },\n        }\n```\n\n#### `mixer.last_received()`\nReturns a unix timestamp giving the last time data was received from the mixer.\n\n#### async `mixer.load_scene(scene_number)`\nChanges the current/scene snapshot of the mixer.\n`scene_number` is the scene number as stored on the mixer.\n\n#### `mixer.name()`\nReturns the network name of the mixer.\n\n#### async `mixer.query(address)` (Low Level Call)\nThis is a low level call and returns the response of a previous `send` call. You should not need to call this, but rely on the managed state instead.\n\n#### async `mixer.reload()`\nCauses the the mixer to be requeried for it\'s current state. This only updates the module\'s internal state.  You would then need to call `mixer.state()` to receive the updated state.\n\n#### async `mixer.send(address, value)` (Low Level Call)\nThis is a low level call to send an OSC message to the mixer.  As this is a low level call, the address of the OSC message being sent would have to conform to that required by the mixer in its documenation, no changing of the address is performed.  This call does not update the internal state. You should not need to call this, but rely on the managed state instead.\n\n#### async `mixer.set_value(address, value)`\nTells the mixer to update a particular field parameter to the `value` specified.\n`address` should be in the format returned by the `mixer.state()` call.\n`value` should be in a format appropriate to the address being used. The module does no checking on the appropriateness of the value.\nThis call also updates the internal state of the module.\n\n#### async `mixer.start()`\nStarts the OSC server to process messages. Data will not be returned/processed unless this has been run\n\n#### `mixer.state(<address>)`\nReturns the current state of the mixer. If the optional address parameter is provided then the current state of that address is returned.  If the parameter is not provided then the entire state is returned as a dictionary of values.\n```\n{\n\t\'/ch/1/mix_fader\': 0.75,\n\t\'/ch/1/mix_fader_db\': 0.0,\n    ...\n\t\'/ch/1/mix_on\': False,\n\t\'/ch/2/mix_on\': False,\n\t\'/ch/1/config_name\': \'VOX 1\',\n\t...\n\t\'/bus/1/mix_fader\': 0.37829911708831787,\n\t\'/bus/1/mix_fader_db\': -19.7,\n\t...\n\t\'/bus/4/mix_on\': True,\n\t...\n\t\'/bus/2/config_name\': \'\',\n\t...\n\t\'/dca/3/config_name\': \'Drums\',\n\t...\n\t\'/main/st/mix_fader\': 0.7497556209564209,\n\t\'/main/st/mix_fader_db\': -0.0,\n\t\'/main/st/mix_on\': True,\n\t...\n\t\'/scene/current\': 6\n}\n```\n\n#### async `mixer.stop()`\nStops the OSC server and the ability to process messages\n\n#### async `mixer.subscribe(callback_function)`\nThis registers a `callback_function` that is called whenever there is a change at the mixer on one of the monitored properties.\nThe callback function will receive one dictionary parameter that contains the data that has been updated.\nThe content of this data parameter is as follows\n\n```python\n{ \n    \'property\': \'/ch/01/mix_fader\',\n    \'value\': 0.85\n}\n```\n\n#### async `mixer.subscription_connected()`\nReturns true if the module has received data from the mixer in the last 15 seconds. \n\n#### async `mixer.subscription_status_register(callback_function)`\nRegister a function to be called when the subscription status changes.  This function is called when `subscription_connected()` changes.\n\n#### async `mixer.unsubscribe()`\nStops the module listening to real time updates\n\n#### async `mixer.validate_connection()`\nReturns `True` if the connection to the mixer is successful, `False` otherwise.\n\n\n## Tests\n\nThese tests attempt to connect to a mixer to exercise get/set from the channels.\nThe tests will change the state of the mixer, so it is recommended you save the current settings before running.\nIt is also recommended that any amplifier is turned off as feedback could occur if signals are present on the channels.\n\nTo run all tests:\n\n`pytest -v`.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n\n## Documentation\n\n[XAir OSC Commands](https://behringer.world/wiki/doku.php?id=x-air_osc)\n\n[X32 OSC Commands](https://wiki.munichmakerlab.de/images/1/17/UNOFFICIAL_X32_OSC_REMOTE_PROTOCOL_%281%29.pdf)\n\n## Special Thanks\n\n[Onyx-and-Iris](https://github.com/onyx-and-iris) for writing the XAir Python module\n',
    'author': 'wrodie',
    'author_email': 'warren@rodie.net',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/wrodie/behringer-mixer',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.10,<4.0',
}


setup(**setup_kwargs)
