diff --git a/README.md b/README.md index d420996..a494636 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # pyCamillaDSP Companion Python library for CamillaDSP. -Works with CamillaDSP version 0.4.0 and up. +Works with CamillaDSP version 0.5.0 and up. Download the library, either by `git clone` or by downloading a zip file of the code. Then unpack the files, go to the folder containing the `setup.py` file and run: ```sh @@ -78,7 +78,9 @@ except IOError as e: ## Methods -The CamillaConnection class provides the following methods: +The CamillaConnection class provides the following methods + +### Basics | Method | Description | |----------|---------------| @@ -88,15 +90,13 @@ The CamillaConnection class provides the following methods: |`get_version()` | Read CamillaDSP version, returns a tuple with 3 elements| |`get_library_version()` | Read pyCamillaDSP version, returns a tuple with 3 elements| |`get_state()` | Get current processing state. Returns one of "RUNNING", "PAUSED" or "INACTIVE".| -|`get_signal_range()` | Get current signal range.| -|`get_signal_range_dB()` | Get current signal range in dB.| -|`get_capture_rate_raw()` | Get current capture rate, raw value.| -|`get_capture_rate()` | Get current capture rate. Returns the nearest common value.| -|`get_update_interval()` | Get current update interval in ms.| -|`set_update_interval(value)` | Set current update interval in ms.| -|`get_rate_adjust()` | Get current value for rate adjust.| |`stop()` | Stop processing and wait for new config if wait mode is active, else exit. | |`exit()` | Stop processing and exit.| + + +### Config handling +| Method | Description | +|----------|---------------| |`reload()` | Reload config from disk.| |`get_config_name()` | Get path to current config file.| |`set_config_name(value)` | Set path to config file.| @@ -108,10 +108,46 @@ The CamillaConnection class provides the following methods: |`read_config_file(path)` | Read a config file from `path`. Returns the loaded config with all optional fields filled with defaults. Raises a CamillaError on errors.| |`read_config(config)` | Read a config from yaml string and return the contents as an obect, with defaults filled out with their default values.| +### Reading status +| Method | Description | +|----------|---------------| +|`get_signal_range()` | Get current signal range.| +|`get_signal_range_dB()` | Get current signal range in dB.| +|`get_capture_signal_rms()` | Get capture signal level rms in dB. Full scale is 0 dB. Returns a list with one element per channel.| +|`get_playback_signal_rms()` | Get playback signal level rms in dB. Full scale is 0 dB. Returns a list with one element per channel.| +|`get_capture_signal_peak()` | Get capture signal level peak in dB. Full scale is 0 dB. Returns a list with one element per channel.| +|`get_playback_signal_peak()` | Get playback signal level peak in dB. Full scale is 0 dB. Returns a list with one element per channel.| +|`get_capture_rate_raw()` | Get current capture rate, raw value.| +|`get_capture_rate()` | Get current capture rate. Returns the nearest common value.| +|`get_update_interval()` | Get current update interval in ms.| +|`set_update_interval(value)` | Set current update interval in ms.| +|`get_rate_adjust()` | Get current value for rate adjust.| +|`get_buffer_level()` | Get current buffer level of the playback device.| +|`get_clipped_samples()` | Get number of clipped samples since the config was loaded.| + +### Volume control +| Method | Description | +|----------|---------------| +|`get_volume()` | Get current volume setting in dB.| +|`set_volume(value)` | Set volume in dB.| # Included examples: -play_wav: Play a wav file. This example reads a configuration from a file, updates the capture device fto point at a given .wav file, and sends this modified config to CamillaDSP. +## read_rms +Read the playback signal level continuously and print in the terminal, until stopped by Ctrl+c. +```sh +python read_rms.py 1234 +``` + +## set_volume +Set the volume control to a new value. First argument is websocket port, second is new volume in dB. +For this to work, CamillaDSP must be running a configuration that has Volume filters in the pipeline for every channel. +```sh +python set_volume.py 1234 -12.3 +``` + +## play_wav +Play a wav file. This example reads a configuration from a file, updates the capture device fto point at a given .wav file, and sends this modified config to CamillaDSP. Usage example: ```sh python play_wav.py 1234 /path/to/wavtest.yml /path/to/music.wav diff --git a/camilladsp/camilladsp.py b/camilladsp/camilladsp.py index 02118ce..08a90f8 100644 --- a/camilladsp/camilladsp.py +++ b/camilladsp/camilladsp.py @@ -4,7 +4,7 @@ import math from threading import Lock -VERSION = (0, 4, 1) +VERSION = (0, 5, 0) STANDARD_RATES = [ 8000, @@ -48,7 +48,7 @@ def __init__(self, host, port): def _query(self, command, arg=None): if self._ws is not None: - if arg: + if arg is not None: query = json.dumps({command: arg}) else: query = json.dumps(command) @@ -152,6 +152,51 @@ def get_signal_range_dB(self): range_dB = -1000 return range_dB + def get_capture_signal_rms(self): + """ + Get capture signal level rms in dB. Full scale is 0 dB. Returns a list with one element per channel. + """ + sigrms = self._query("GetCaptureSignalRms") + sigrms = [float(val) for val in sigrms] + return sigrms + + def get_playback_signal_rms(self): + """ + Get playback signal level rms in dB. Full scale is 0 dB. Returns a list with one element per channel. + """ + sigrms = self._query("GetPlaybackSignalRms") + sigrms = [float(val) for val in sigrms] + return sigrms + + def get_capture_signal_peak(self): + """ + Get capture signal level peak in dB. Full scale is 0 dB. Returns a list with one element per channel. + """ + sigpeak = self._query("GetCaptureSignalPeak") + sigpeak = [float(val) for val in sigpeak] + return sigpeak + + def get_playback_signal_peak(self): + """ + Get playback signal level peak in dB. Full scale is 0 dB. Returns a list with one element per channel. + """ + sigpeak = self._query("GetPlaybackSignalPeak") + sigpeak = [float(val) for val in sigpeak] + return sigpeak + + def get_volume(self): + """ + Get current volume setting in dB. + """ + vol = self._query("GetVolume") + return float(vol) + + def set_volume(self, value): + """ + Set volume in dB. + """ + self._query("SetVolume", arg=float(value)) + def get_capture_rate_raw(self): """ Get current capture rate, raw value. diff --git a/examples/read_rms/read_rms.py b/examples/read_rms/read_rms.py new file mode 100644 index 0000000..d7d5a4e --- /dev/null +++ b/examples/read_rms/read_rms.py @@ -0,0 +1,22 @@ +# play wav +from camilladsp import CamillaConnection +import sys +import time + +try: + port = int(sys.argv[1]) +except: + print("Usage: start CamillaDSP with the socketserver enabled:") + print("> camilladsp -p4321 yourconfig.yml") + print("Then read the signal level") + print("> python read_rms.py 4321") + sys.exit() + +cdsp = CamillaConnection("127.0.0.1", port) +cdsp.connect() + +print("Reading playback signal RMS, press Ctrl+c to stop") +while True: + print(cdsp.get_playback_signal_rms()) + time.sleep(1) + diff --git a/examples/set_volume/set_volume.py b/examples/set_volume/set_volume.py new file mode 100644 index 0000000..4e39e95 --- /dev/null +++ b/examples/set_volume/set_volume.py @@ -0,0 +1,24 @@ +# play wav +from camilladsp import CamillaConnection +import sys +import time + +try: + port = int(sys.argv[1]) + new_vol = float(sys.argv[2]) +except: + print("Usage: Make sure that your pipeline includes Volume filters for each channel.") + print("Then start CamillaDSP with the websocket server enabled:") + print("> camilladsp -p4321 yourconfig.yml") + print("Then set the volume") + print("> python read_rms.py 4321 -12.3") + sys.exit() + +cdsp = CamillaConnection("127.0.0.1", port) +cdsp.connect() + +current_vol = cdsp.get_volume() +print(f"Current volume: {current_vol} dB") +print(f"Changing volume to: {new_vol} dB") +cdsp.set_volume(new_vol) + diff --git a/setup.py b/setup.py index 80c9ba2..3118dad 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="camilladsp", - version="0.4.1", + version="0.5.0", author="Henrik Enquist", author_email="henrik.enquist@gmail.com", description="A library for comminucating with CamillaDSP", diff --git a/tests/test_camillaws.py b/tests/test_camillaws.py index b5b819b..1c0abb6 100644 --- a/tests/test_camillaws.py +++ b/tests/test_camillaws.py @@ -13,6 +13,7 @@ def __init__(self): '"GetState"': json.dumps({"GetState": {"result": "Ok", "value": "IDLE"}}), '"GetVersion"': json.dumps({"GetVersion": {"result": "Ok", "value": "0.3.2"}}), '"GetSignalRange"': json.dumps({"GetSignalRange": {"result": "Ok", "value": "0.2"}}), + '"GetCaptureSignalRms"': json.dumps({"GetCaptureSignalRms": {"result": "Ok", "value": [0.1, 0.2]}}), '"GetCaptureRate"': json.dumps({"GetCaptureRate": {"result": "Ok", "value": "88250"}}), '"GetErrorValue"': json.dumps({"GetErrorValue": {"result": "Error", "value": "badstuff"}}), '"GetError"': json.dumps({"GetError": {"result": "Error"}}), @@ -94,6 +95,10 @@ def test_signal_range(camilla_mockws): camilla_mockws.connect() assert camilla_mockws.get_signal_range() == 0.2 +def test_signal_rms(camilla_mockws): + camilla_mockws.connect() + assert camilla_mockws.get_capture_signal_rms() == [0.1, 0.2] + def test_signal_range_dB(camilla_mockws): camilla_mockws.connect() assert camilla_mockws.get_signal_range_dB() == -20 @@ -168,6 +173,19 @@ def test_queries(camilla_mockquery): camilla_mockquery._query.assert_called_with('GetBufferLevel') camilla_mockquery.get_clipped_samples() camilla_mockquery._query.assert_called_with('GetClippedSamples') + camilla_mockquery.get_volume() + camilla_mockquery._query.assert_called_with('GetVolume') + camilla_mockquery.set_volume(-25.0) + camilla_mockquery._query.assert_called_with('SetVolume', arg=-25.0) + camilla_mockquery.get_capture_signal_rms() + camilla_mockquery._query.assert_called_with('GetCaptureSignalRms') + camilla_mockquery.get_capture_signal_peak() + camilla_mockquery._query.assert_called_with('GetCaptureSignalPeak') + camilla_mockquery.get_playback_signal_rms() + camilla_mockquery._query.assert_called_with('GetPlaybackSignalRms') + camilla_mockquery.get_playback_signal_peak() + camilla_mockquery._query.assert_called_with('GetPlaybackSignalPeak') + def test_queries_adv(camilla_mockquery_yaml): camilla_mockquery_yaml.read_config_file("some/path")