diff --git a/examples_py/test_aps.ipynb b/examples_py/test_aps.ipynb index b8a636b..e723322 100644 --- a/examples_py/test_aps.ipynb +++ b/examples_py/test_aps.ipynb @@ -10,85 +10,27 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "6c06a0c3-dcf7-4d21-b1f3-eced84e31218", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "🍹 Building a mixed python/rust project\n", - "🔗 Found pyo3 bindings\n", - "🐍 Found CPython 3.10 at /home/anne/.pyenv/versions/lasprs/bin/python\n", - "Requirement already satisfied: numpy in /home/anne/.pyenv/versions/lasprs/lib/python3.10/site-packages (1.26.4)\n", - "\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-build-config v0.21.2\n", - "\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-macros-backend v0.21.2 178/189: pyo3-build-config \n", - "\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-ffi v0.21.2=======> ] 178/189: pyo3-macros-backend, pyo3...\n", - "\u001b[1m\u001b[32m Compiling\u001b[0m pyo3 v0.21.2\n", - "\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m pyo3-macros v0.21.2=====> ] 183/189: pyo3-macros-backend, pyo3...\n", - "\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m numpy v0.21.0===========> ] 186/189: pyo3 \n", - "\u001b[K\u001b[1m\u001b[32m Compiling\u001b[0m lasprs v0.6.1 (/home/anne/wip/mycode/lasprs) \n", - "\u001b[K\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: type alias `Vc` is never used\u001b[0m \n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/config.rs:63:10\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m63\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub type Vc = Vec;\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m= \u001b[0m\u001b[0m\u001b[1mnote\u001b[0m\u001b[0m: `#[warn(dead_code)]` on by default\u001b[0m\n", - "\n", - "\u001b[K\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: type alias `Cmat` is never used\u001b[0m \n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/config.rs:75:10\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m75\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub type Cmat = Array2;\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^\u001b[0m\n", - "\n", - "\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: methods `ninchannels` and `noutchannels` are never used\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/daq/api/mod.rs:25:8\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m20\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mpub trait Stream {\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m------\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mmethods in this trait\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m...\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m25\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m fn ninchannels(&self) -> usize;\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m...\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m28\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m fn noutchannels(&self) -> usize;\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n", - "\n", - "\u001b[K\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: method `setPreFilter` is never used\u001b[0m \n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/siggen.rs:320:12\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m318\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mimpl SiggenChannelConfig {\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m------------------------\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mmethod in this implementation\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m319\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m /// Set new pre-filter that filters the source signal\u001b[0m\n", - "\u001b[0m\u001b[1m\u001b[38;5;12m320\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m pub fn setPreFilter(&mut self, pref: Option>) {\u001b[0m\n", - "\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n", - "\n", - "\u001b[K\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m:\u001b[0m `lasprs` (lib) generated 4 warningssprs \n", - "\u001b[1m\u001b[32m Finished\u001b[0m \u001b]8;;https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles\u001b\\`dev` profile [unoptimized + debuginfo]\u001b]8;;\u001b\\ target(s) in 6.04s\n", - "📦 Built wheel for CPython 3.10 to /tmp/.tmp03vGw7/lasprs-0.6.1-cp310-cp310-linux_x86_64.whl\n", - "✏️ Setting installed package as editable\n", - "🛠 Installed lasprs-0.6.1\n" - ] - } - ], + "outputs": [], "source": [ "!cd .. && maturin develop -F python-bindings" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "3e651371-e7a5-4013-a265-ab80f8b1eb41", "metadata": {}, "outputs": [], "source": [ - "from lasprs import WindowType" + "from lasprs import WindowType, ApsSettings, AvPowerSpectra, ApsMode, Overlap, FreqWeighting" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "9d6bdf3b-40f8-4c3b-85ac-4ff8b8c7dcae", "metadata": {}, "outputs": [], @@ -98,27 +40,46 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "3a31899d-37de-4653-9b6e-61dcf7c683f4", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[WindowType.Hann,\n", - " WindowType.Hamming,\n", - " WindowType.Rect,\n", - " WindowType.Bartlett,\n", - " WindowType.Blackman]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "w" + "settings = ApsSettings(ApsMode.AllAveraging(), Overlap.NoOverlap(), WindowType.Hann, FreqWeighting.A, 2048, 48000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4771bde-f3f3-4639-bbe6-96f49e004b3d", + "metadata": {}, + "outputs": [], + "source": [ + "aps = AvPowerSpectra(settings)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86cac094-5969-4a75-83c3-49b486687bb1", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "signal = np.zeros(48000)\n", + "signal[200] = 1\n", + "import matplotlib.pyplot as plt\n", + "plt.plot(aps.compute(signal[:,None])[:,0,0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d72aa7b-0cff-463c-be57-666cf74f6793", + "metadata": {}, + "outputs": [], + "source": [ + "#!pip install matplotlib" ] } ], @@ -138,7 +99,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/examples_py/test_filterbank.ipynb b/examples_py/test_filterbank.ipynb index 06f3e44..1c49984 100644 --- a/examples_py/test_filterbank.ipynb +++ b/examples_py/test_filterbank.ipynb @@ -127,7 +127,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/examples_py/test_freqweighting.ipynb b/examples_py/test_freqweighting.ipynb index cbc8ef2..d15f5db 100644 --- a/examples_py/test_freqweighting.ipynb +++ b/examples_py/test_freqweighting.ipynb @@ -102,7 +102,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/examples_py/test_ppm.ipynb b/examples_py/test_ppm.ipynb new file mode 100644 index 0000000..51ecf96 --- /dev/null +++ b/examples_py/test_ppm.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "ec44a8b1-7508-470b-bb2e-f26c7ad8e851", + "metadata": {}, + "outputs": [], + "source": [ + "!cd .. && maturin develop -F python-bindings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29b4422e-844b-4944-a391-313ef0ed26e4", + "metadata": {}, + "outputs": [], + "source": [ + "from lasprs import StreamMgr, ClipState, PPM" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a12659c7-5ec9-4011-accc-423c4c660701", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "smgr = StreamMgr()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "709aa842-0c47-422c-806b-edf2bf97df4b", + "metadata": {}, + "outputs": [], + "source": [ + "smgr.startDefaultInputStream()\n", + "ppm = PPM(smgr)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2eb1bf1a-8133-421a-ac3e-d609e83ad763", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "N = 0\n", + "while N < 60:\n", + " try:\n", + " print(ppm.getState(), end='\\r')\n", + " except KeyboardInterrupt:\n", + " break\n", + " time.sleep(0.1)\n", + " N += 1\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d94d2fb-c03e-415e-b58b-86dc70865c2e", + "metadata": {}, + "outputs": [], + "source": [ + "del ppm" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples_py/test_rtaps.ipynb b/examples_py/test_rtaps.ipynb new file mode 100644 index 0000000..caedd9e --- /dev/null +++ b/examples_py/test_rtaps.ipynb @@ -0,0 +1,95 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "7ad7512c-d605-4c9f-acd5-5f6a1c22cc1a", + "metadata": {}, + "outputs": [], + "source": [ + "!cd .. && maturin develop -F python-bindings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92d7023d-3168-4d55-841a-01d8f6d03bab", + "metadata": {}, + "outputs": [], + "source": [ + "from lasprs import WindowType, ApsSettings, AvPowerSpectra, ApsMode, Overlap, FreqWeighting, StreamMgr, RtAps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "faf909e7-5c45-43c4-9687-0d33eb939e5f", + "metadata": {}, + "outputs": [], + "source": [ + "settings = ApsSettings(ApsMode.AllAveraging(), Overlap.NoOverlap(), WindowType.Hann, FreqWeighting.A, 2048, 48000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "814dafd3-4e84-4e62-8d30-6d07d4bf75ae", + "metadata": {}, + "outputs": [], + "source": [ + "smgr = StreamMgr()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ba155e1-7481-4f77-bc6b-e3096be539ce", + "metadata": {}, + "outputs": [], + "source": [ + "smgr.startDefaultInputStream()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7edbd928-b0e7-4b22-afaf-96e247d2672c", + "metadata": {}, + "outputs": [], + "source": [ + "rt = RtAps(smgr,settings)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ef4f826-aa05-4d71-a866-29c9491b478b", + "metadata": {}, + "outputs": [], + "source": [ + "rt.get_last()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples_py/test_rtviewer.ipynb b/examples_py/test_rtviewer.ipynb new file mode 100644 index 0000000..5b92873 --- /dev/null +++ b/examples_py/test_rtviewer.ipynb @@ -0,0 +1,89 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "7ad7512c-d605-4c9f-acd5-5f6a1c22cc1a", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "!cd .. && maturin develop -F python-bindings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92d7023d-3168-4d55-841a-01d8f6d03bab", + "metadata": {}, + "outputs": [], + "source": [ + "from lasprs import StreamMgr, RtViewer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "814dafd3-4e84-4e62-8d30-6d07d4bf75ae", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "smgr = StreamMgr()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ba155e1-7481-4f77-bc6b-e3096be539ce", + "metadata": {}, + "outputs": [], + "source": [ + "smgr.startDefaultInputStream()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7edbd928-b0e7-4b22-afaf-96e247d2672c", + "metadata": {}, + "outputs": [], + "source": [ + "rt = RtViewer(smgr, 2, 600, 0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ef4f826-aa05-4d71-a866-29c9491b478b", + "metadata": {}, + "outputs": [], + "source": [ + "rt.get_last()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples_py/test_slm1.ipynb b/examples_py/test_slm1.ipynb index 5ec2b6b..be3d4bc 100644 --- a/examples_py/test_slm1.ipynb +++ b/examples_py/test_slm1.ipynb @@ -140,7 +140,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/examples_py/test_streammgr.ipynb b/examples_py/test_streammgr.ipynb new file mode 100644 index 0000000..b4285c2 --- /dev/null +++ b/examples_py/test_streammgr.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "afa2bdda-0748-4a76-ad5c-d19859f833f6", + "metadata": {}, + "outputs": [], + "source": [ + "from lasprs import DaqConfig, StreamMgr" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2b47552e-823e-48ba-8853-7f58fc1f90de", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "Cannot connect to server socket err = No such file or directory\n", + "Cannot connect to server request channel\n", + "jack server is not running or cannot be started\n", + "JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n", + "JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n", + "Cannot connect to server socket err = No such file or directory\n", + "Cannot connect to server request channel\n", + "jack server is not running or cannot be started\n", + "JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n", + "JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock\n", + "ALSA lib pcm_oss.c:397:(_snd_pcm_oss_open) Cannot open device /dev/dsp\n", + "ALSA lib pcm_oss.c:397:(_snd_pcm_oss_open) Cannot open device /dev/dsp\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib confmisc.c:165:(snd_config_get_card) Cannot get card index for 1\n", + "ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n", + "ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n", + "ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n", + "ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n", + "ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n", + "ALSA lib pcm_route.c:878:(find_matching_chmap) Found no matching channel map\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dmix.c:973:(snd_pcm_dmix_open) The dmix plugin supports only playback stream\n", + "ALSA lib pcm_dsnoop.c:541:(snd_pcm_dsnoop_open) The dsnoop plugin supports only capture stream\n", + "ALSA lib pcm_dsnoop.c:541:(snd_pcm_dsnoop_open) The dsnoop plugin supports only capture stream\n" + ] + } + ], + "source": [ + "s = StreamMgr()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "39d4c156-8304-4ed6-b9da-1d8a14d3bbe8", + "metadata": {}, + "outputs": [], + "source": [ + "ds = s.getDeviceInfo()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a6f28472-a52c-4ccf-b65f-2a44b2eb59e1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[DeviceInfo { api: Cpal, device_name: \"pipewire\", avDataTypes: [I16, I32, F32, I16, I32, F32], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [1000.0, 2000.0, 4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"pulse\", avDataTypes: [I16, I32, F32, I16, I32, F32], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [1000.0, 2000.0, 4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"default\", avDataTypes: [I16, I32, F32, I16, I32, F32], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [1000.0, 2000.0, 4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=3\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=7\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=8\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hw:CARD=PCH,DEV=9\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=0\", avDataTypes: [I8, I16, I32, F32, F64, I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=3\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=7\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=8\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"plughw:CARD=PCH,DEV=9\", avDataTypes: [I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 0, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"sysdefault:CARD=PCH\", avDataTypes: [I8, I16, I32, F32, F64, I8, I16, I32, F32, F64], prefDataType: F32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [4000.0, 8000.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, 384000.0], prefSampleRate: 384000.0, iChannelCount: 32, oChannelCount: 32, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"front:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"surround40:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"surround51:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"surround71:CARD=PCH,DEV=0\", avDataTypes: [I16, I32, I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=0\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=1\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=2\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"hdmi:CARD=PCH,DEV=3\", avDataTypes: [I16, I32], prefDataType: I32, avFramesPerBlock: [256, 512, 1024, 2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 8, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=0\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=3\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=7\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=8\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"dmix:CARD=PCH,DEV=9\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 0, oChannelCount: 2, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number },\n", + " DeviceInfo { api: Cpal, device_name: \"dsnoop:CARD=PCH,DEV=0\", avDataTypes: [I32], prefDataType: I32, avFramesPerBlock: [2048, 8192], prefFramesPerBlock: 2048, avSampleRates: [48000.0], prefSampleRate: 48000.0, iChannelCount: 2, oChannelCount: 0, hasInputIEPE: false, hasInputACCouplingSwitch: false, hasInputTrigger: false, hasInternalOutputMonitor: false, duplexModeForced: false, physicalIOQty: Number }]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00635264-6cbc-4391-b207-308e859fd109", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples_py/test_zpkmodel.ipynb b/examples_py/test_zpkmodel.ipynb index c5b5668..54254f2 100644 --- a/examples_py/test_zpkmodel.ipynb +++ b/examples_py/test_zpkmodel.ipynb @@ -140,7 +140,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.4" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/src/lib.rs b/src/lib.rs index 8854c35..e01f3b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,7 @@ fn lasprs(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; Ok(()) } diff --git a/src/math/mod.rs b/src/math/mod.rs index 0a7c5f2..f0c36ab 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -5,7 +5,10 @@ use crate::config::*; use ndarray::ArrayView1; /// Compute maximum value of an array of float values -pub fn max(arr: ArrayView1) -> Flt { +pub fn max(arr: ArrayView) -> Flt +where + T: ndarray::Dimension, +{ arr.fold( -Flt::INFINITY, |acc, new| if *new > acc { *new } else { acc }, @@ -13,7 +16,10 @@ pub fn max(arr: ArrayView1) -> Flt { } /// Compute minimum value of an array of float values -pub fn min(arr: ArrayView1) -> Flt { +pub fn min(arr: ArrayView) -> Flt +where + T: ndarray::Dimension, +{ arr.fold( Flt::INFINITY, |acc, new| if *new < acc { *new } else { acc }, @@ -21,6 +27,9 @@ pub fn min(arr: ArrayView1) -> Flt { } /// Compute maximum absolute value of an array of float values -pub fn maxabs(arr: ArrayView1) -> Flt { +pub fn maxabs(arr: ArrayView) -> Flt +where + T: ndarray::Dimension, +{ arr.fold(0., |acc, new| if new.abs() > acc { new.abs() } else { acc }) } diff --git a/src/ps/mod.rs b/src/ps/mod.rs index 3d05bff..334779b 100644 --- a/src/ps/mod.rs +++ b/src/ps/mod.rs @@ -7,7 +7,7 @@ mod aps; mod fft; mod ps; -mod timebuffer; +pub mod timebuffer; mod window; mod freqweighting; mod apssettings; diff --git a/src/rt/mod.rs b/src/rt/mod.rs index 7d82469..fb97e3e 100644 --- a/src/rt/mod.rs +++ b/src/rt/mod.rs @@ -3,5 +3,7 @@ //! (Spectrograms, Auto powers, ..., or ) mod ppm; mod rtaps; +mod rtview; pub use ppm::{PPM, ClipState}; pub use rtaps::{RtAps, RtApsResult}; +pub use rtview::RtViewer; diff --git a/src/rt/rtaps.rs b/src/rt/rtaps.rs index 95a1b7a..4956af8 100644 --- a/src/rt/rtaps.rs +++ b/src/rt/rtaps.rs @@ -9,7 +9,6 @@ use parking_lot::Mutex; use rayon::ThreadPool; use std::ops::Deref; use std::sync::Arc; -use std::thread::{self, JoinHandle}; use std::time::Duration; type SharedRtApsStatus = Arc>>; @@ -92,7 +91,7 @@ impl RtAps { } // Check for messages and act accordingly - if let Some(msg) = rxmsg.recv_timeout(Duration::from_millis(10)).ok() { + if let Some(msg) = rxmsg.recv_timeout(Duration::from_millis(1)).ok() { match msg { RtApsMessage::StopThread => { let mut status = status.lock(); @@ -169,6 +168,7 @@ mod test { use super::*; use crate::{daq::StreamMgr, ps::ApsSettingsBuilder}; + use std::thread; #[test] fn test_rtaps1() -> Result<(), anyhow::Error> { { diff --git a/src/rt/rtview.rs b/src/rt/rtview.rs new file mode 100644 index 0000000..a05823f --- /dev/null +++ b/src/rt/rtview.rs @@ -0,0 +1,217 @@ +use crate::config::*; +use crate::daq::{InStreamMsg, StreamHandler, StreamMetaData, StreamMgr}; +use crate::math::{max, min}; +use crate::ps::timebuffer::TimeBuffer; +use anyhow::{anyhow, bail, Result}; +use crossbeam::channel::{unbounded, Receiver, Sender}; +use parking_lot::Mutex; +use std::sync::Arc; +use std::time::Duration; + +type RtViewUpdate = Array2; +type SharedRtViewerStatus = Arc>>>; + +/// Real time viewer that tracks the signal and the envelope of the signal, in +#[cfg_attr(feature = "python-bindings", pyclass)] +#[derive(Debug)] +pub struct RtViewer { + /// The computed time step per output (inverse of 'sampling frequency') in \[s\] + pub T: Flt, + /// The number of samples in the time buffer + pub N: usize, + + sender: Sender, + + status: SharedRtViewerStatus, +} +impl RtViewer { + /// Create new real time signal viewer. Outputs buffers of the signal envelopOutputs buffers of the signal envelope as a function of time. + /// + /// # Args + /// + /// - `t_hist` - The time history to show in \[s\]. + /// - `resolution` - The number of samples within this history. This should + /// correspond more / less to the amount of pixels used in the viewer. + /// + pub fn new( + smgr: &mut StreamMgr, + t_hist: Flt, + resolution: usize, + channel: usize, + ) -> Result { + if t_hist <= 0. { + bail!("The time history to show in [s] should be > 0.") + } + if resolution <= 1 { + bail!("Invalid resolution. Please use value > 1"); + } + + let status = Arc::new(Mutex::new(None)); + + let (sender, rxmsg) = unbounded(); + Self::startThread(smgr, rxmsg, t_hist, resolution, channel, status.clone()); + + Ok(RtViewer { + T: t_hist, + N: resolution, + sender, + status, + }) + } + fn startThread( + smgr: &mut StreamMgr, + rxmsg: Receiver, + t_hist: Flt, + N: usize, + channel: usize, + status: SharedRtViewerStatus, + ) { + let (tx, rxstream) = unbounded(); + smgr.addInQueue(tx); + rayon::spawn(move || { + let mut buf = Array2::zeros((N, 2).f()); + + let zero_out = |mut arr: ArrayViewMut2| { + arr.mapv_inplace(|_| 0.); + }; + + let mut circbuf = TimeBuffer::new(); + // Placeholder value, should be updated when stream is started. + let mut nsamples_per_output = 1; + let T = t_hist / N as Flt; + + 'mainloop: loop { + if let Some(msg) = rxstream.recv_timeout(Duration::from_millis(10)).ok() { + match msg { + InStreamMsg::StreamStarted(new_meta) => { + if channel >= new_meta.nchannels() { + // The chosen channel is too high. We stop and + // kill here. + *status.lock() = Some(Err(anyhow!("Invalid channel. Chosen channel is higher than maximum amount of channels in stream, which is {}", new_meta.nchannels()))); + return; + } + + // Calculate the number of samples per timestamp of + // output + let T_ac = 1. / new_meta.samplerate; + nsamples_per_output = std::cmp::max((T / T_ac) as usize, 1); + } + InStreamMsg::StreamStopped | InStreamMsg::StreamError(_) => { + circbuf = TimeBuffer::new(); + zero_out(buf.view_mut()); + *status.lock() = None; + } + InStreamMsg::InStreamData(id) => { + // Push data on circular buffer + let fd = id.getFloatData(); + let dat = fd.column(channel); + circbuf.push(dat.slice(s![.., NewAxis])); + } + } + } + + // See if we can update the time buffer + let mut nnew = circbuf.nsamples() / nsamples_per_output; + if nnew > 0 { + // Rotate back samples, and add new. + buf.column_mut(0).as_slice_mut().unwrap().rotate_left(nnew); + buf.column_mut(1).as_slice_mut().unwrap().rotate_left(nnew); + + while let Some(samples) = circbuf.pop(nsamples_per_output, 0) { + let max = max(samples.view()); + let min = min(samples.view()); + buf[[N - nnew, 0]] = min; + buf[[N - nnew, 1]] = max; + nnew -= 1; + } + let new = Ok(buf.clone()); + *status.lock() = Some(new); + } + + // Check for messages and act accordingly + if let Some(msg) = rxmsg.recv_timeout(Duration::from_millis(1)).ok() { + match msg { + RtMsg::StopThread => { + let mut status = status.lock(); + *status = None; + break 'mainloop; + } + } + } + } + }); + } + + /// Returns an array of time instances corresponding to the output data. + pub fn getTimeArray(&self) -> Dcol { + Dcol::linspace(-self.T * ((self.N - 1) as Flt) / self.N as Flt, 0., self.N) + } + + /// Get the last updated value of the array of mins / max, or an error from + /// the system. + pub fn get_last(&self) -> Option> { + if let Some(x) = self.status.lock().take() { + Some(x) + } else { + None + } + } +} + +#[cfg(feature = "python-bindings")] +#[cfg_attr(feature = "python-bindings", pymethods)] +impl RtViewer { + #[new] + fn new_py( + smgr: &mut StreamMgr, + t_hist: Flt, + resolution: usize, + channel: usize, + ) -> Result { + RtViewer::new(smgr, t_hist, resolution, channel) + } + + #[pyo3(name = "getTimeArray")] + fn getTimeArray_py<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray1> { + self.getTimeArray().to_pyarray_bound(py) + } + #[pyo3(name = "get_last")] + fn get_last_py<'py>(&self, py: Python<'py>) -> PyResult>>> { + if let Some(res) = self.get_last() { + let res = res?; + return Ok(Some(res.to_pyarray_bound(py))); + } + + Ok(None) + } +} +impl Drop for RtViewer { + fn drop(&mut self) { + self.sender.send(RtMsg::StopThread).unwrap(); + } +} + +enum RtMsg { + StopThread, +} + +#[cfg(test)] +mod test { + use crate::daq::StreamMgr; + + use super::RtViewer; + + #[test] + fn test_rtviewer1() { + let mut smgr = StreamMgr::new(); + let t_hist = 10.; + let resolution = 10; + let channel = 0; + let a = RtViewer::new(&mut smgr, t_hist, resolution, channel) + .unwrap() + .getTimeArray(); + dbg!(&a); + assert_eq!(a.last(), Some(&0.)); + assert_eq!(a.first(), Some(&-9.)); + } +}