audio-spectrogram 0.1.0a0__py3-none-any.whl

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.
@@ -0,0 +1,44 @@
1
+ # Copyright 2026 - 2026, Artur Drogunow and the Audio-Spectrogram contributors
2
+ # SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ import sys
5
+
6
+ from PySide6.QtWidgets import QMainWindow, QVBoxLayout, QWidget
7
+
8
+ from audio_spectrogram import APP_TITLE, __version__
9
+
10
+ from .control_panel_widget import ControlPanelWidget
11
+ from .plot_widget import PlotWidget
12
+
13
+
14
+ class MainWindow(QMainWindow):
15
+ def __init__(self) -> None:
16
+ super().__init__()
17
+
18
+ # variables
19
+
20
+ # widgets
21
+ self.control_panel_widget = ControlPanelWidget()
22
+ self.plot_widget = PlotWidget()
23
+
24
+ # setup
25
+ self._setup_widgets()
26
+ self._setup_layout()
27
+ self._connect_signals()
28
+
29
+ def _setup_widgets(self) -> None:
30
+ title = (
31
+ f"{APP_TITLE} {__version__} "
32
+ f"(Python {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]})"
33
+ )
34
+ self.setWindowTitle(title)
35
+
36
+ def _setup_layout(self) -> None:
37
+ central_widget = QWidget()
38
+ self.setCentralWidget(central_widget)
39
+ vbox = QVBoxLayout(central_widget)
40
+ vbox.addWidget(self.control_panel_widget, 0)
41
+ vbox.addWidget(self.plot_widget, 1)
42
+
43
+ def _connect_signals(self) -> None:
44
+ pass
@@ -0,0 +1,58 @@
1
+ # Copyright 2026 - 2026, Artur Drogunow and the Audio-Spectrogram contributors
2
+ # SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ import pyqtgraph as pg
5
+ from PySide6.QtWidgets import QGroupBox, QVBoxLayout
6
+
7
+ pg.setConfigOption(opt="useNumba", value=True)
8
+
9
+
10
+ class PlotWidget(QGroupBox):
11
+ def __init__(self) -> None:
12
+ super().__init__("Signal Viewer")
13
+
14
+ # variables
15
+
16
+ # widgets
17
+ self.glw = pg.GraphicsLayoutWidget()
18
+ self.time_plot = self.glw.addPlot(row=0, col=0)
19
+ self.time_plot_item = pg.PlotCurveItem()
20
+ self.spec_plot = self.glw.addPlot(row=1, col=0)
21
+ self.spec_plot_item = pg.ImageItem(axisOrder="row-major", levels=[-90, 0])
22
+
23
+ # setup
24
+ self._setup_widgets()
25
+ self._setup_layout()
26
+ self._connect_signals()
27
+
28
+ def _setup_widgets(self) -> None:
29
+ # set line properties
30
+ self.time_plot_item.setClickable(False)
31
+ self.time_plot_item.setPen(pg.mkPen("coral", width=0.5))
32
+ self.time_plot_item.setSkipFiniteCheck(True)
33
+ self.time_plot_item.setSegmentedLineMode("on")
34
+
35
+ # horizontally align left axis
36
+ self.time_plot.getAxis("left").setWidth(40)
37
+ self.spec_plot.getAxis("left").setWidth(40)
38
+
39
+ # setup time plot
40
+ self.time_plot.setLabel("left", "Amplitude")
41
+ self.time_plot.setLabel("bottom", "Time", units="s")
42
+ self.time_plot.showGrid(x=True, y=True)
43
+ self.time_plot.addItem(self.time_plot_item)
44
+
45
+ # setup spectrum plot
46
+ self.spec_plot.setYRange(-100, 7100)
47
+ self.spec_plot.setLabel("left", "Frequency", units="Hz")
48
+ self.spec_plot.setLabel("bottom", "Time", units="s")
49
+ self.spec_plot.showGrid(x=False, y=False)
50
+ self.spec_plot_item.setColorMap(pg.colormap.get("magma"))
51
+ self.spec_plot.addItem(self.spec_plot_item)
52
+
53
+ def _setup_layout(self) -> None:
54
+ layout = QVBoxLayout(self)
55
+ layout.addWidget(self.glw)
56
+
57
+ def _connect_signals(self) -> None:
58
+ pass
@@ -0,0 +1,42 @@
1
+ # Copyright 2026 - 2026, Artur Drogunow and the Audio-Spectrogram contributors
2
+ # SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ import typing
5
+
6
+ from PySide6.QtWidgets import (
7
+ QSpinBox,
8
+ QWidget,
9
+ )
10
+
11
+ DEFAULT_VALUE: typing.Final = 1024
12
+ MIN_VALUE: typing.Final = 64
13
+
14
+
15
+ class PowerOfTwoSpinBox(QSpinBox):
16
+ def __init__(self, parent: QWidget | None = None) -> None:
17
+ super().__init__(parent)
18
+
19
+ self.setReadOnly(True)
20
+ self.setRange(MIN_VALUE, 2**30)
21
+ self.setValue(1024) # default value
22
+
23
+ @typing.override
24
+ def stepBy(self, steps: int, /) -> None:
25
+ value: int = self.value()
26
+
27
+ for _ in range(abs(steps)):
28
+ if steps > 0:
29
+ value *= 2
30
+ else:
31
+ value = max(MIN_VALUE, value // 2)
32
+
33
+ self.setValue(value)
34
+
35
+ @typing.override
36
+ def stepEnabled(self, /) -> QSpinBox.StepEnabledFlag:
37
+ flags = QSpinBox.StepEnabledFlag.StepUpEnabled
38
+
39
+ if self.value() > MIN_VALUE:
40
+ flags |= QSpinBox.StepEnabledFlag.StepDownEnabled
41
+
42
+ return flags
@@ -0,0 +1,63 @@
1
+ # Copyright 2026 - 2026, Artur Drogunow and the Audio-Spectrogram contributors
2
+ # SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ import datetime
5
+ import logging
6
+ from typing import Final
7
+
8
+ from platformdirs import user_log_path
9
+
10
+ from audio_spectrogram import APP_TITLE, LOGGER, PACKAGE_NAME
11
+
12
+ VERBOSITY_LEVEL_APP_DEBUG: Final = 1
13
+ VERBOSITY_LEVEL_ROOT_WARNING: Final = 1
14
+ VERBOSITY_LEVEL_ROOT_INFO: Final = 2
15
+ VERBOSITY_LEVEL_ROOT_DEBUG: Final = 3
16
+
17
+
18
+ def setup_logging(verbosity: int) -> None:
19
+ iso_date = datetime.datetime.now(tz=datetime.UTC).strftime("%Y-%m-%d")
20
+ logfile_path = user_log_path(PACKAGE_NAME, ensure_exists=True) / f"{iso_date}.log"
21
+
22
+ with logfile_path.open(mode="at") as file:
23
+ if file.tell() > 0:
24
+ file.write("\n\n")
25
+ file.writelines(
26
+ [
27
+ "*" * 80 + "\n",
28
+ f"Start {APP_TITLE}".center(80) + "\n",
29
+ "*" * 80 + "\n",
30
+ ]
31
+ )
32
+
33
+ # instantiate logging handlers
34
+ file_handler = logging.FileHandler(logfile_path)
35
+ stream_handler = logging.StreamHandler()
36
+
37
+ # configure formatting
38
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
39
+ file_handler.setFormatter(formatter)
40
+ stream_handler.setFormatter(formatter)
41
+
42
+ # determine log levels for app (package_level) and dependencies (root_level)
43
+ package_level = logging.DEBUG if verbosity >= VERBOSITY_LEVEL_APP_DEBUG else logging.INFO
44
+ if verbosity >= VERBOSITY_LEVEL_ROOT_DEBUG:
45
+ root_level = logging.DEBUG
46
+ elif verbosity >= VERBOSITY_LEVEL_ROOT_INFO:
47
+ root_level = logging.INFO
48
+ elif verbosity >= VERBOSITY_LEVEL_ROOT_WARNING:
49
+ root_level = logging.WARNING
50
+ else:
51
+ root_level = logging.ERROR
52
+
53
+ # configure root logger
54
+ root_logger = logging.getLogger()
55
+ root_logger.handlers.clear()
56
+ root_logger.setLevel(root_level)
57
+ root_logger.addHandler(file_handler)
58
+ root_logger.addHandler(stream_handler)
59
+
60
+ # configure package logger
61
+ LOGGER.setLevel(package_level)
62
+ LOGGER.info("Root log level: %s", logging.getLevelName(root_level))
63
+ LOGGER.info("Package log level: %s", logging.getLevelName(package_level))
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: audio-spectrogram
3
+ Version: 0.1.0a0
4
+ Summary: Audio spectrogram app based on PySide6
5
+ Author-email: Artur Drogunow <Artur.Drogunow@zf.com>
6
+ License: GPL-3.0-or-later
7
+ Keywords: Audio,Microphone,FFT,STFT,Spectrogram,Sonogram
8
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Programming Language :: Python :: Implementation :: CPython
14
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
15
+ Requires-Python: >=3.12
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: numba==0.65.*
19
+ Requires-Dist: numpy==2.4.*
20
+ Requires-Dist: platformdirs==4.9.*
21
+ Requires-Dist: pyqtgraph==0.14.*
22
+ Requires-Dist: pyside6==6.11.*
23
+ Requires-Dist: rocket-fft==0.3.*
24
+ Dynamic: license-file
25
+
26
+ # Audio Spectrogram
27
+
28
+ [![PyPI - Version](https://img.shields.io/pypi/v/audio-spectrogram.svg)](https://pypi.org/project/audio-spectrogram)
29
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/audio-spectrogram.svg)](https://pypi.org/project/audio-spectrogram)
30
+
31
+ ## Introduction
32
+
33
+ *Audio Spectrogram* is a small python GUI application to analyze the frequency content of your microphone input.
34
+
35
+ <img src="doc/GUI.png" width="683" alt="GUI Screenshot" />
36
+
37
+ ## Usage
38
+
39
+ You can run it directly from your command line:
40
+ ```bash
41
+ uvx audio-spectrogram
42
+ ```
43
+ or
44
+ ```bash
45
+ pipx audio-spectrogram
46
+ ```
@@ -0,0 +1,21 @@
1
+ audio_spectrogram/__init__.py,sha256=5EDkWGwK2wElA1YUBkPjBbDX6MHrcKcLYSAUIxT6PhE,370
2
+ audio_spectrogram/__main__.py,sha256=Ss1Tm75zZmuX_pQqJuLa76nPwhUj7gBe-Mz5ObDssvs,910
3
+ audio_spectrogram/util.py,sha256=VuKBtd6rgnKkaDZx6t0wh1Ff-ZQywBLgkMqNMOzP4NE,2185
4
+ audio_spectrogram/app/__init__.py,sha256=-Og5GFBNZ-JabE4MKs8oKmad2KLKLljI_L8a_m_8CPY,123
5
+ audio_spectrogram/app/application.py,sha256=GuZSet7Im-bn_EWOQUXd9qzgrIwZbkkvhTNQYqtzYkQ,2818
6
+ audio_spectrogram/app/control_panel_handler.py,sha256=R1RpaZcrf_4VwOaXB4ouYnEGqbqYuiGeNaJAvH0bF00,6271
7
+ audio_spectrogram/app/plot_handler.py,sha256=HBYyzF_eF2PFSvQQOKuadFaOQtMROYwd1XOZRhkBDR0,3824
8
+ audio_spectrogram/app/qapplication.py,sha256=QO9oYPxgxZbdLS13qXS9VCuFr7gPbp0cAo4UyvAlLnc,606
9
+ audio_spectrogram/app/spectrogram.py,sha256=YBJMjsmU72UugLNRvXbdliqviJR4b7ivWyVJJwCQ6xM,2387
10
+ audio_spectrogram/app/widgets/__init__.py,sha256=-Og5GFBNZ-JabE4MKs8oKmad2KLKLljI_L8a_m_8CPY,123
11
+ audio_spectrogram/app/widgets/combobox.py,sha256=bOdtX3y8_oLMdlBMHKK19rKhwMmGe_4zQreDyY4E-b0,1246
12
+ audio_spectrogram/app/widgets/control_panel_widget.py,sha256=zCGpE-Qb57v5fvq9gDQftyRKJgHUAGNg35JCXSq-79I,4410
13
+ audio_spectrogram/app/widgets/main_window.py,sha256=AxlhEqKGiXXgUClBv77vVICb-o9_jJw0JRmyYY_j4lY,1228
14
+ audio_spectrogram/app/widgets/plot_widget.py,sha256=aQkKOEXKdfrW1wLKBN8qh3GTL7h11IpeP8ljxnvtVXI,1997
15
+ audio_spectrogram/app/widgets/power_of_two_spinbox.py,sha256=h97FCkDcCk_jXOk07o2138QQpQQNLAer_3RgL92qP30,1062
16
+ audio_spectrogram-0.1.0a0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
17
+ audio_spectrogram-0.1.0a0.dist-info/METADATA,sha256=PwYynoDRiFn3QNyiow-dv4CdTBRNWjhkVvf12sVObnQ,1556
18
+ audio_spectrogram-0.1.0a0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
19
+ audio_spectrogram-0.1.0a0.dist-info/entry_points.txt,sha256=oxX9sLt6MdCumXmxR4xZn7iVaKSDUMETA_LiRN7hw0M,139
20
+ audio_spectrogram-0.1.0a0.dist-info/top_level.txt,sha256=HcjNccVeBlauPVpuVzz1qMRDiYT3YKpyHMJH2s6_f1A,18
21
+ audio_spectrogram-0.1.0a0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ audio_spectrogram_c = audio_spectrogram.__main__:main
3
+
4
+ [gui_scripts]
5
+ audio_spectrogram = audio_spectrogram.__main__:main