slm-open-api-package 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/PKG-INFO +1 -1
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/pyproject.toml +1 -1
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/pyproject.toml.orig +1 -1
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/example_multi.py +1 -1
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/flac_example.py +0 -1
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/https_requests.py +10 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/measurment_handler.py +1 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/stream_handler.py +7 -2
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/stream_handlers.py +47 -2
- slm_open_api_package-0.2.4/src/slm_api/helpers/websocket_handler.py +12 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/webxi_helper_functions.py +5 -1
- slm_open_api_package-0.2.4/src/slm_api/multi_device_flac.py +155 -0
- slm_open_api_package-0.2.4/src/slm_api/multi_instrument_example.py +75 -0
- slm_open_api_package-0.2.2/src/slm_api/helpers/websocket_handler.py +0 -8
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/README.md +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/CPB_example.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/__init__.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/enums/fast_log_intervals_enum.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/enums/sequence_id_enum.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/fast_log_example.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/FigureHandler.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/Leq.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/__init__.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/buffer.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/data_handler.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/fft.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/flac_stream_2_samples.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/sequence_handler.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/tmpFileStateMachine.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/webxi_root.pem +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/mp3_example.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/screen_record_example.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/README.md +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/__init__.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/webxi-header.ksy +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/webxi-stream.ksy +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/webxi_header.py +0 -0
- {slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/webxi_stream.py +0 -0
|
@@ -22,7 +22,7 @@ from slm_api.helpers import stream_handlers as sh
|
|
|
22
22
|
from slm_api.helpers.data_handler import DataHandler
|
|
23
23
|
from slm_api.helpers.https_requests import UseHttps
|
|
24
24
|
|
|
25
|
-
UseHttps(use_https=False)
|
|
25
|
+
# UseHttps(use_https=False)
|
|
26
26
|
|
|
27
27
|
host, ip = webxi_helper.set_host_ip(__file__)
|
|
28
28
|
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/https_requests.py
RENAMED
|
@@ -18,6 +18,14 @@ class WebxiAdapter(HTTPAdapter):
|
|
|
18
18
|
kwargs["assert_hostname"] = False # urllib3 does its own SAN check independent of ssl_context.check_hostname
|
|
19
19
|
return super().init_poolmanager(*args, **kwargs)
|
|
20
20
|
|
|
21
|
+
def build_ssl_context():
|
|
22
|
+
"""SSLContext trusting only webxi_root.pem, with hostname checking disabled."""
|
|
23
|
+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
24
|
+
ctx.load_verify_locations(cafile=str(_CERT_FILE))
|
|
25
|
+
ctx.check_hostname = False
|
|
26
|
+
ctx.verify_mode = ssl.CERT_REQUIRED
|
|
27
|
+
return ctx
|
|
28
|
+
|
|
21
29
|
|
|
22
30
|
_session = requests.Session()
|
|
23
31
|
if _CERT_FILE.is_file():
|
|
@@ -26,6 +34,8 @@ if _CERT_FILE.is_file():
|
|
|
26
34
|
class UseHttps:
|
|
27
35
|
use_https = True # class attribute: shared, module-wide default
|
|
28
36
|
|
|
37
|
+
|
|
38
|
+
|
|
29
39
|
def __init__(self, use_https=None):
|
|
30
40
|
if use_https is not None:
|
|
31
41
|
UseHttps.use_https = use_https
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/stream_handler.py
RENAMED
|
@@ -20,8 +20,12 @@ def setup_stream(host,ip,sequenceID,StreamName):
|
|
|
20
20
|
if not (response.status_code == 201):
|
|
21
21
|
print(response.text)
|
|
22
22
|
raise Exception("Cannot start stream, could be bacause of to many streams open on the device")
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
https = https_requests.UseHttps.use_https
|
|
24
|
+
if https:
|
|
25
|
+
return 'wss://' + ip + response.json()["URI"][0]
|
|
26
|
+
else:
|
|
27
|
+
return 'ws://' + ip + response.json()["URI"][0]
|
|
28
|
+
|
|
25
29
|
def get_stream_ID(host, streamName):
|
|
26
30
|
"""This function shows how to find the ID of a specific stream with specific name"""
|
|
27
31
|
streams = https_requests.get(host, "/WebXi/Streams?recursive").json()
|
|
@@ -75,6 +79,7 @@ class StreamHandler:
|
|
|
75
79
|
self._stop_event = asyncio.Event()
|
|
76
80
|
self.loop = asyncio.get_running_loop()
|
|
77
81
|
task = self.loop.create_task(websocket_handler.next_async_websocket(self.uri, self.msg_func))
|
|
82
|
+
task.add_done_callback(lambda t: t.exception() and print(f"[{self.streamName}] Stream task failed: {t.exception()!r}"))
|
|
78
83
|
await self._stop_event.wait()
|
|
79
84
|
task.cancel()
|
|
80
85
|
measurment_handler.stop_measurement(self.host)
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/stream_handlers.py
RENAMED
|
@@ -9,6 +9,7 @@ from datetime import datetime
|
|
|
9
9
|
from timeit import default_timer as timer
|
|
10
10
|
import numpy as np
|
|
11
11
|
import miniaudio
|
|
12
|
+
import threading
|
|
12
13
|
|
|
13
14
|
from . import sequence_handler as seq
|
|
14
15
|
from . import stream_handler as stream
|
|
@@ -109,6 +110,44 @@ class _TimeStamps:
|
|
|
109
110
|
self._time_buffer = np.append(self._time_buffer[1:], new_value)
|
|
110
111
|
return self.lastTime
|
|
111
112
|
|
|
113
|
+
def start_all_synced(streams):
|
|
114
|
+
"""For handlers constructed with multi_device=True: open each device's stream/websocket,
|
|
115
|
+
then trigger start_pause_measurement on all of them at (nearly) the same instant."""
|
|
116
|
+
for s in streams:
|
|
117
|
+
s.uri = stream.setup_stream(s.host, s.ip, s.stream_ids, s.streamName)
|
|
118
|
+
threading.Thread(target=s.startStream, daemon=True).start()
|
|
119
|
+
|
|
120
|
+
barrier = threading.Barrier(len(streams))
|
|
121
|
+
|
|
122
|
+
def _start_one(s):
|
|
123
|
+
barrier.wait()
|
|
124
|
+
https_requests.put(s.host, "/WebXi/Applications/SLM?Action=StartPause")
|
|
125
|
+
|
|
126
|
+
start_threads = [threading.Thread(target=_start_one, args=(s,)) for s in streams]
|
|
127
|
+
for t in start_threads:
|
|
128
|
+
t.start()
|
|
129
|
+
for t in start_threads:
|
|
130
|
+
t.join()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def stop_all(streams):
|
|
134
|
+
"""Tear down every stream: stop all measurements at (nearly) the same instant
|
|
135
|
+
via a barrier (mirroring start_all_synced), then delete each device-side stream resource."""
|
|
136
|
+
barrier = threading.Barrier(len(streams))
|
|
137
|
+
|
|
138
|
+
def _stop_one(s):
|
|
139
|
+
barrier.wait()
|
|
140
|
+
meas.stop_measurement(s.host)
|
|
141
|
+
|
|
142
|
+
stop_threads = [threading.Thread(target=_stop_one, args=(s,)) for s in streams]
|
|
143
|
+
for t in stop_threads:
|
|
144
|
+
t.start()
|
|
145
|
+
for t in stop_threads:
|
|
146
|
+
t.join()
|
|
147
|
+
|
|
148
|
+
for s in streams:
|
|
149
|
+
stream.delete_stream(s.host, s.streamName)
|
|
150
|
+
|
|
112
151
|
|
|
113
152
|
class WebXiStreamHandler(stream.StreamHandler):
|
|
114
153
|
"""Configurable WebXi stream handler.
|
|
@@ -138,7 +177,7 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
138
177
|
|
|
139
178
|
def __init__(self, host, ip, sequenceID=None, sequenceNames=None,
|
|
140
179
|
streamName="Stream", cpb=False, multi=False, flac=False, mp3=False, fast_logging=False,
|
|
141
|
-
time=False, screen_record=False, leq_window_sec=10, windowSize=None, fast_logging_interval=None,
|
|
180
|
+
time=False, screen_record=False, multi_device=False,leq_window_sec=10, windowSize=None, fast_logging_interval=None,
|
|
142
181
|
saving=None, saving_path=None):
|
|
143
182
|
super().__init__(streamName)
|
|
144
183
|
self.host = host
|
|
@@ -149,6 +188,7 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
149
188
|
self.multi = multi
|
|
150
189
|
self.flac = flac
|
|
151
190
|
self.mp3 = mp3
|
|
191
|
+
self.multi_device = multi_device
|
|
152
192
|
self.fast_logging = fast_logging
|
|
153
193
|
self.time = time
|
|
154
194
|
self.screen_record = screen_record
|
|
@@ -231,6 +271,11 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
231
271
|
self.leq_mov = MovingLeq(self.leq_window_sec, storedata=True)
|
|
232
272
|
|
|
233
273
|
stream_ids = list(self.ID) if isinstance(self.ID, list) else [self.ID]
|
|
274
|
+
self.stream_ids = stream_ids # saved for start_all_synced() when multi_device=True
|
|
275
|
+
if self.multi_device:
|
|
276
|
+
return
|
|
277
|
+
|
|
278
|
+
return
|
|
234
279
|
if self.time:
|
|
235
280
|
utc_offset_seconds = _get_slm_utc_offset_seconds(self.host)
|
|
236
281
|
self._time_stamps = _TimeStamps(self.windowSize or (self.leq_window_sec * 10 + 1), utc_offset_seconds)
|
|
@@ -287,7 +332,7 @@ class WebXiStreamHandler(stream.StreamHandler):
|
|
|
287
332
|
value = package.content.sequence_blocks[0].values
|
|
288
333
|
self.CPB_values = np.array(stream.data_type_conv(self.sequence["DataType"], value, self.sequence["VectorLength"])) / 100
|
|
289
334
|
if self.data_handler:
|
|
290
|
-
self.data_handler.handle(timestamp=self._time_prefix(),
|
|
335
|
+
self.data_handler.handle(timestamp=self._time_prefix(), value=self.CPB_values)
|
|
291
336
|
|
|
292
337
|
def calcFreqBands(self):
|
|
293
338
|
"""Only meaningful when cpb=True."""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import websockets
|
|
2
|
+
import asyncio
|
|
3
|
+
from . import https_requests
|
|
4
|
+
|
|
5
|
+
async def next_async_websocket(uri, packetHandler):
|
|
6
|
+
ssl_context = https_requests.build_ssl_context() if uri.startswith("wss://") else None
|
|
7
|
+
async with websockets.connect(uri, ping_interval=None, ssl=ssl_context) as websocket:
|
|
8
|
+
async for message in websocket:
|
|
9
|
+
try:
|
|
10
|
+
packetHandler(message)
|
|
11
|
+
except Exception as exc:
|
|
12
|
+
print(f"Error handling message from {uri}: {exc!r}")
|
|
@@ -7,13 +7,17 @@ from slm_api.helpers.https_requests import get, put
|
|
|
7
7
|
|
|
8
8
|
# Functions to turn on/off BB freq weights and sequences. These are used in the examples to make sure the wanted sequences are enabled on the SLM.
|
|
9
9
|
def turn_off_bb_freq_weight(host):
|
|
10
|
+
|
|
10
11
|
for endpoint in (
|
|
11
12
|
"/webxi/Applications/SLM/Setup/BBFreqWeightB",
|
|
12
13
|
"/webxi/Applications/SLM/Setup/BBFreqWeightZ",
|
|
13
14
|
"/webxi/Applications/SLM/Setup/BBFreqWeightA",
|
|
14
15
|
"/webxi/Applications/SLM/Setup/BBFreqWeightC",
|
|
15
16
|
):
|
|
16
|
-
|
|
17
|
+
try:
|
|
18
|
+
put(host , endpoint, json=False, timeout=10)
|
|
19
|
+
except requests.exceptions.HTTPError as exc:
|
|
20
|
+
print(f"Skipping {endpoint}: {exc}")
|
|
17
21
|
|
|
18
22
|
def turn_on_bb_freq_weight(host, weights, fast=False):
|
|
19
23
|
weights = [weights] if isinstance(weights, str) else weights
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Multi-device FLAC/mp3 audio streaming
|
|
3
|
+
--------------------------------------
|
|
4
|
+
Streams FLAC- (or mp3-)encoded audio from several devices at once and plots
|
|
5
|
+
each device's waveform + spectrum, same as flac_example.py/mp3_example.py's
|
|
6
|
+
figureHandler, stacked in one window (one time/freq row pair per device).
|
|
7
|
+
|
|
8
|
+
Note: WebXiStreamHandler._msg_func_audio also appends decoded samples to the
|
|
9
|
+
module-level `DataBuffer` (helpers/buffer.py), which is a single shared buffer.
|
|
10
|
+
With multiple devices, samples from all of them interleave in that shared
|
|
11
|
+
buffer, so it isn't usable for per-device plotting here - each device instead
|
|
12
|
+
gets its own `buffer` instance (BufferDataHandler below).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import sys
|
|
16
|
+
import time
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
import pyqtgraph as pg
|
|
20
|
+
from PyQt5 import QtWidgets
|
|
21
|
+
|
|
22
|
+
from slm_api.helpers.buffer import buffer as Buffer
|
|
23
|
+
from slm_api.helpers.fft import dBfft
|
|
24
|
+
from slm_api.helpers.stream_handlers import WebXiStreamHandler, start_all_synced, stop_all
|
|
25
|
+
from slm_api.helpers.data_handler import DataHandler
|
|
26
|
+
from slm_api.enums.sequence_id_enum import SequenceIdEnums
|
|
27
|
+
|
|
28
|
+
USE_MP3 = True # False = FLAC (SequenceIdEnums.FLACSignal), True = mp3 (SequenceIdEnums.MP3Signal)
|
|
29
|
+
SEQUENCE_ID = SequenceIdEnums.MP3Signal.value if USE_MP3 else SequenceIdEnums.FLACSignal.value
|
|
30
|
+
SAMPLE_RATE = 32e3 if USE_MP3 else 2 ** 16 # matches mp3_example.py / flac_example.py dBfft() calls
|
|
31
|
+
|
|
32
|
+
CHUNK_TO_SHOW = 2 ** 15
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BufferDataHandler(DataHandler):
|
|
36
|
+
"""Per-device handler: appends decoded samples into its own buffer instead
|
|
37
|
+
of the shared DataBuffer singleton, so devices don't mix samples together."""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self.buffer = Buffer(2 ** 16)
|
|
41
|
+
|
|
42
|
+
def handle(self, samples, **data):
|
|
43
|
+
self.buffer.append(samples)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class MultiDeviceFigureHandler:
|
|
47
|
+
"""One time-domain + spectrum plot pair per device, stacked in one window."""
|
|
48
|
+
|
|
49
|
+
def __init__(self, labels_and_handlers):
|
|
50
|
+
self.labels_and_handlers = labels_and_handlers
|
|
51
|
+
self.fft_hamming = np.hamming(CHUNK_TO_SHOW)
|
|
52
|
+
self.axis = np.flip(np.arange(CHUNK_TO_SHOW) * -1 / CHUNK_TO_SHOW)
|
|
53
|
+
self.old = [0] * len(labels_and_handlers)
|
|
54
|
+
self.oldold = [0] * len(labels_and_handlers)
|
|
55
|
+
self.i = 0
|
|
56
|
+
|
|
57
|
+
self.app = QtWidgets.QApplication(sys.argv)
|
|
58
|
+
self.win = pg.GraphicsLayoutWidget(title="Multi-device streaming")
|
|
59
|
+
self.win.setBackground('w')
|
|
60
|
+
self.win.resize(1000, 300 * len(labels_and_handlers))
|
|
61
|
+
label_style = {'color': '#000', 'font-size': '13pt'}
|
|
62
|
+
|
|
63
|
+
self.plots_time, self.plots_freq, self.curves_time, self.curves_freq = [], [], [], []
|
|
64
|
+
freq = np.arange(CHUNK_TO_SHOW // 2 + 1) / (float(CHUNK_TO_SHOW) / SAMPLE_RATE)
|
|
65
|
+
for label, _ in labels_and_handlers:
|
|
66
|
+
plot_time = self.win.addPlot(title=label)
|
|
67
|
+
curve_time = plot_time.plot(self.axis, np.zeros(CHUNK_TO_SHOW))
|
|
68
|
+
curve_time.setPen(color='b', width=2, autoDownsample=True, clipToView=True)
|
|
69
|
+
plot_time.showGrid(x=True, y=True)
|
|
70
|
+
plot_time.setXRange(np.min(self.axis), np.max(self.axis))
|
|
71
|
+
plot_time.setYRange(-2, 2)
|
|
72
|
+
plot_time.getAxis('left').setLabel('Pressure', units='Pa', **label_style)
|
|
73
|
+
plot_time.getAxis('bottom').setLabel('Time', units='s', **label_style)
|
|
74
|
+
self.win.nextRow()
|
|
75
|
+
|
|
76
|
+
plot_freq = self.win.addPlot()
|
|
77
|
+
curve_freq = plot_freq.plot(freq, np.zeros(len(freq)))
|
|
78
|
+
curve_freq.setPen(color='b', width=2, autoDownsample=True, clipToView=True)
|
|
79
|
+
plot_freq.setXRange(0, np.max(freq))
|
|
80
|
+
plot_freq.setYRange(-20, 130)
|
|
81
|
+
plot_freq.getAxis('bottom').enableAutoSIPrefix(enable=False)
|
|
82
|
+
plot_freq.setLogMode(x=True, y=False)
|
|
83
|
+
plot_freq.showGrid(x=True, y=True)
|
|
84
|
+
plot_freq.getAxis('left').setLabel('dB SPL re 20 µPa', **label_style)
|
|
85
|
+
plot_freq.getAxis('bottom').setLabel('Frequency', units='Hz', **label_style)
|
|
86
|
+
self.win.nextRow()
|
|
87
|
+
|
|
88
|
+
self.plots_time.append(plot_time)
|
|
89
|
+
self.plots_freq.append(plot_freq)
|
|
90
|
+
self.curves_time.append(curve_time)
|
|
91
|
+
self.curves_freq.append(curve_freq)
|
|
92
|
+
|
|
93
|
+
self.win.show()
|
|
94
|
+
self.timer = pg.QtCore.QTimer()
|
|
95
|
+
self.timer.timeout.connect(self.update)
|
|
96
|
+
self.timer.start(int(0.1 * 1000))
|
|
97
|
+
|
|
98
|
+
def update(self):
|
|
99
|
+
# Recomputing dBfft (32768-sample FFT) for every device on every 100ms
|
|
100
|
+
# tick can hold the GIL long enough to stall the decode threads (seen as
|
|
101
|
+
# audio decode's own "TotalTime" warnings), so only do it every 5th tick.
|
|
102
|
+
if self.i % 5 != 0:
|
|
103
|
+
self.i += 1
|
|
104
|
+
return
|
|
105
|
+
for idx, (label, handler) in enumerate(self.labels_and_handlers):
|
|
106
|
+
signal = handler.buffer.getPart(CHUNK_TO_SHOW)
|
|
107
|
+
x = np.linspace(np.min(self.axis), np.max(self.axis), len(signal))
|
|
108
|
+
freq, s_dbfs = dBfft(signal, SAMPLE_RATE, self.fft_hamming, ref=20e-6) # Reference = 20µPa
|
|
109
|
+
avg = s_dbfs / 3 + self.old[idx] / 3 + self.oldold[idx] / 3
|
|
110
|
+
self.curves_time[idx].setData(x, signal)
|
|
111
|
+
self.curves_freq[idx].setData(freq, avg)
|
|
112
|
+
self.oldold[idx] = self.old[idx]
|
|
113
|
+
self.old[idx] = s_dbfs
|
|
114
|
+
min_Pa = np.round(min(signal), 2)
|
|
115
|
+
max_Pa = np.round(max(signal), 2)
|
|
116
|
+
fft_peak = np.round(max(avg), 2)
|
|
117
|
+
fft_min = np.round(min(avg), 2)
|
|
118
|
+
peak_freq = freq[np.argmax(avg)]
|
|
119
|
+
if min_Pa != max_Pa:
|
|
120
|
+
self.plots_time[idx].setYRange(min_Pa * 1.2, max_Pa * 1.2)
|
|
121
|
+
if not np.isinf(fft_peak):
|
|
122
|
+
self.plots_freq[idx].setYRange(fft_min, fft_peak * 1.2)
|
|
123
|
+
print(f"{label} Min: {min_Pa} Pa, Max: {max_Pa} Pa, Peak: {fft_peak} dB SPL, Peak freq: {peak_freq} Hz")
|
|
124
|
+
self.i += 1
|
|
125
|
+
|
|
126
|
+
def run(self):
|
|
127
|
+
QtWidgets.QApplication.instance().exec_()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
devices = [
|
|
132
|
+
("http://192.168.1.183", "192.168.1.183"),
|
|
133
|
+
("http://192.168.1.216", "192.168.1.216"),
|
|
134
|
+
("http://192.168.1.191", "192.168.1.191"),
|
|
135
|
+
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
streams = [
|
|
139
|
+
WebXiStreamHandler(
|
|
140
|
+
host=dev_host, ip=dev_ip, sequenceID=SEQUENCE_ID,
|
|
141
|
+
streamName=f"Stream_{dev_ip}", multi_device=True,
|
|
142
|
+
mp3=USE_MP3, flac=not USE_MP3,
|
|
143
|
+
)
|
|
144
|
+
for dev_host, dev_ip in devices
|
|
145
|
+
]
|
|
146
|
+
handlers = [BufferDataHandler() for _ in streams]
|
|
147
|
+
for s, h in zip(streams, handlers):
|
|
148
|
+
s.setDataHandler(h)
|
|
149
|
+
|
|
150
|
+
fig = MultiDeviceFigureHandler([(s.ip, h) for s, h in zip(streams, handlers)])
|
|
151
|
+
fig.app.aboutToQuit.connect(lambda: stop_all(streams))
|
|
152
|
+
|
|
153
|
+
time.sleep(1)
|
|
154
|
+
start_all_synced(streams)
|
|
155
|
+
fig.run()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
18. Stream FastLAF (Sequence 115)
|
|
3
|
+
-----------------------------------
|
|
4
|
+
Streams the FastLAF (LAeq) broadband Leq value from sequence 115
|
|
5
|
+
and pretty-prints each received value to the terminal.
|
|
6
|
+
|
|
7
|
+
Sequence 115 properties:
|
|
8
|
+
Name: FastLAF
|
|
9
|
+
LocalName: LAeq
|
|
10
|
+
FunctionType: BroadbandLeq
|
|
11
|
+
DataType: Int16
|
|
12
|
+
Scale: 0.01
|
|
13
|
+
Weighting: A
|
|
14
|
+
AveragingMode: Linear
|
|
15
|
+
Unit: dB re 20uPa
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
import time
|
|
21
|
+
import threading
|
|
22
|
+
from slm_api.helpers.stream_handlers import WebXiStreamHandler, start_all_synced, stop_all
|
|
23
|
+
from slm_api.helpers.data_handler import DataHandler
|
|
24
|
+
from slm_api.enums.sequence_id_enum import SequenceIdEnums
|
|
25
|
+
from slm_api.enums.fast_log_intervals_enum import FastLogInterval
|
|
26
|
+
from slm_api.helpers import webxi_helper_functions as webxi_helper
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
FAST_LOGGING_INTERVAL_MS = FastLogInterval.interval_1000ms.value
|
|
30
|
+
SEQUENCE_ID = SequenceIdEnums.LAeq.value
|
|
31
|
+
SEQUENCE_NAME = SequenceIdEnums.LAeq.name
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PrintDataHandler(DataHandler):
|
|
35
|
+
def __init__(self, label):
|
|
36
|
+
self.label = label
|
|
37
|
+
|
|
38
|
+
def handle(self, value, **data):
|
|
39
|
+
print(f"{self.label} {SEQUENCE_NAME}: {value}")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
devices = [
|
|
44
|
+
("http://192.168.1.183", "192.168.1.183"),
|
|
45
|
+
("http://192.168.1.216", "192.168.1.216"),
|
|
46
|
+
("http://192.168.1.191", "192.168.1.191")
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
# for dev_host, dev_ip in devices:
|
|
50
|
+
# # webxi_helper.turn_off_CPB_freq_weight(dev_host)
|
|
51
|
+
# # webxi_helper.turn_on_CPB_freq_weight(dev_host, "A")
|
|
52
|
+
# # webxi_helper.turn_on_cpb_leq(dev_host, SEQUENCE_NAME)
|
|
53
|
+
# webxi_helper.turn_off_bb_freq_weight(dev_host)
|
|
54
|
+
# webxi_helper.turn_on_bb_freq_weight(dev_host, "A")
|
|
55
|
+
# webxi_helper.turn_on_bb_leq(dev_host, 'LAF')
|
|
56
|
+
|
|
57
|
+
streams = [
|
|
58
|
+
WebXiStreamHandler(
|
|
59
|
+
host=dev_host, ip=dev_ip, sequenceID=SEQUENCE_ID,
|
|
60
|
+
streamName=f"Stream_{dev_ip}", multi_device=True
|
|
61
|
+
)
|
|
62
|
+
for dev_host, dev_ip in devices
|
|
63
|
+
]
|
|
64
|
+
for s in streams:
|
|
65
|
+
s.setDataHandler(PrintDataHandler(s.ip))
|
|
66
|
+
|
|
67
|
+
time.sleep(1)
|
|
68
|
+
start_all_synced(streams)
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
while True:
|
|
72
|
+
time.sleep(1)
|
|
73
|
+
except KeyboardInterrupt:
|
|
74
|
+
stop_all(streams)
|
|
75
|
+
print("\nStreams stopped by user.")
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import websockets
|
|
2
|
-
import asyncio
|
|
3
|
-
|
|
4
|
-
async def next_async_websocket(uri, packetHandler):
|
|
5
|
-
"""Function which awaits response from the websocket and calls the packetHandler"""
|
|
6
|
-
async with websockets.connect(uri, ping_interval = None) as websocket:
|
|
7
|
-
async for message in websocket:
|
|
8
|
-
packetHandler(message)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/enums/sequence_id_enum.py
RENAMED
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/FigureHandler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/data_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/sequence_handler.py
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/tmpFileStateMachine.py
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/helpers/webxi_root.pem
RENAMED
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/screen_record_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/webxi-header.ksy
RENAMED
|
File without changes
|
{slm_open_api_package-0.2.2 → slm_open_api_package-0.2.4}/src/slm_api/webxi/webxi-stream.ksy
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|