modusa 0.3.41__py3-none-any.whl → 0.3.42__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.
modusa/__init__.py CHANGED
@@ -4,6 +4,6 @@ from modusa.utils import excp, config
4
4
  from modusa.tools import plot1d, plot2d, plot_dist
5
5
  #=====
6
6
 
7
- from modusa.tools import play, convert
7
+ from modusa.tools import play, convert, record
8
8
  from modusa.tools import download
9
9
  from modusa.tools import load, load_ann
modusa/tools/__init__.py CHANGED
@@ -5,4 +5,5 @@ from .audio_player import play
5
5
  from .audio_converter import convert
6
6
  from .youtube_downloader import download
7
7
  from .audio_loader import load
8
- from .ann_loader import load_ann
8
+ from .ann_loader import load_ann
9
+ from .audio_recorder import record
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env python3
2
+
3
+ #---------------------------------
4
+ # Author: Ankit Anand
5
+ # Date: 22/08/25
6
+ # Email: ankit0.anand0@gmail.com
7
+ #---------------------------------
8
+
9
+
10
+ import sounddevice as sd
11
+ import numpy as np
12
+ import ipywidgets as widgets
13
+ from IPython.display import display, clear_output, Audio
14
+
15
+ def record():
16
+ """
17
+ Create a UI to record audio in jupyter notebook, the
18
+ recorded signal is available as array.
19
+
20
+ .. code-block:: python
21
+
22
+ import modusa as ms
23
+ result = ms.record()
24
+ y, sr, title = result() # Keep it in the next cell
25
+
26
+ Returns
27
+ -------
28
+ Callable
29
+ A lambda function that returns y(audio signal), sr(sampling rate), title(title set in the UI)
30
+ """
31
+ devices = sd.query_devices()
32
+ device_options = [(d['name'][:30], i) for i, d in enumerate(devices) if d['max_input_channels'] > 0]
33
+
34
+ # Controls
35
+ device_dropdown = widgets.Dropdown(
36
+ options=device_options,
37
+ description="Microphone:",
38
+ layout=widgets.Layout(width="300px")
39
+ )
40
+
41
+ sr_dropdown = widgets.Dropdown(
42
+ options=[('16 Khz', 16000), ('22.05 Khz', 22050), ('44.1 Khz', 44100)],
43
+ value=22050,
44
+ description="Sample Rate:",
45
+ layout=widgets.Layout(width="300px")
46
+ )
47
+
48
+ title_box = widgets.Text(
49
+ placeholder="Title",
50
+ description="Title:",
51
+ layout=widgets.Layout(width="300px")
52
+ )
53
+
54
+ toggle_button = widgets.Button(
55
+ description="Record",
56
+ button_style="",
57
+ )
58
+
59
+ status = widgets.HTML(value="")
60
+ out = widgets.Output()
61
+
62
+ # State
63
+ recording = {"data": None, "sr": None, "title": None}
64
+ stream = {"obj": None, "frames": [], "recording": False}
65
+
66
+ def callback(indata, frames, time, status):
67
+ if not status:
68
+ stream["frames"].append(indata.copy())
69
+
70
+ def on_toggle(b):
71
+ if not stream["recording"]:
72
+ stream["frames"].clear()
73
+ sr = sr_dropdown.value
74
+ device_id = device_dropdown.value
75
+
76
+ stream["obj"] = sd.InputStream(callback=callback, channels=1, samplerate=sr, device=device_id)
77
+ stream["obj"].start()
78
+ stream["recording"] = True
79
+
80
+ toggle_button.description = "Stop"
81
+ toggle_button.button_style = "danger"
82
+ status.value = "Recording..."
83
+ else:
84
+ stream["obj"].stop()
85
+ stream["obj"].close()
86
+
87
+ sr = sr_dropdown.value
88
+ y = np.concatenate(stream["frames"], axis=0).flatten()
89
+ title = title_box.value.strip() or "Recording"
90
+
91
+ recording["data"], recording["sr"], recording["title"] = y, sr, title
92
+ record.result = (y, sr, title)
93
+ stream["recording"] = False
94
+
95
+ toggle_button.description = "Record"
96
+ toggle_button.button_style = "success"
97
+
98
+ with out:
99
+ clear_output()
100
+ display(Audio(y, rate=sr))
101
+
102
+ toggle_button.on_click(on_toggle)
103
+
104
+ # Layout
105
+ ui = widgets.VBox([
106
+ device_dropdown,
107
+ sr_dropdown,
108
+ title_box,
109
+ widgets.HBox([toggle_button]),
110
+ out
111
+ ])
112
+
113
+ display(ui)
114
+ record.result = None
115
+ return lambda: record.result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modusa
3
- Version: 0.3.41
3
+ Version: 0.3.42
4
4
  Summary: A modular signal analysis python library.
5
5
  Author-Email: Ankit Anand <ankit0.anand0@gmail.com>
6
6
  License: MIT
@@ -10,6 +10,7 @@ Requires-Dist: matplotlib>=3.10.3
10
10
  Requires-Dist: yt-dlp>=2025.6.30
11
11
  Requires-Dist: librosa==0.11.0
12
12
  Requires-Dist: IPython>=8.0.0
13
+ Requires-Dist: sounddevice>=0.5.2
13
14
  Description-Content-Type: text/markdown
14
15
 
15
16
  # modusa
@@ -1,9 +1,9 @@
1
- modusa-0.3.41.dist-info/METADATA,sha256=h6zQe0lZ2sqn5JHLbqAw9wqexEXjWW28gNqmXV8OdCk,1369
2
- modusa-0.3.41.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- modusa-0.3.41.dist-info/entry_points.txt,sha256=fmKpleVXj6CdaBVL14WoEy6xx7JQCs85jvzwTi3lePM,73
4
- modusa-0.3.41.dist-info/licenses/LICENSE.md,sha256=JTaXAjx5awk76VArKCx5dUW8vmLEWsL_ZlR7-umaHbA,1078
1
+ modusa-0.3.42.dist-info/METADATA,sha256=T8MRyy7MBHjm6w1boi604AFhBgWq2zSqNYukSFB9gJw,1403
2
+ modusa-0.3.42.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ modusa-0.3.42.dist-info/entry_points.txt,sha256=fmKpleVXj6CdaBVL14WoEy6xx7JQCs85jvzwTi3lePM,73
4
+ modusa-0.3.42.dist-info/licenses/LICENSE.md,sha256=JTaXAjx5awk76VArKCx5dUW8vmLEWsL_ZlR7-umaHbA,1078
5
5
  modusa/.DS_Store,sha256=_gm6qJREwfMi8dE7n5S89_RG46u5t3xHyD-smNhtNoM,6148
6
- modusa/__init__.py,sha256=uq6kORFFAODiCMGmOLWO0shE8-dVFWf5gmV8wxekmnk,280
6
+ modusa/__init__.py,sha256=Vny15JTP5lDr_4VxA_zSqL8eARbQzqLj0dk1OBSpJmk,288
7
7
  modusa/config.py,sha256=bTqK4t00FZqERVITrxW_q284aDDJAa9aMSfFknfR-oU,280
8
8
  modusa/decorators.py,sha256=8zeNX_wE37O6Vp0ysR4-WCZaEL8mq8dyCF_I5DHOzks,5905
9
9
  modusa/devtools/generate_docs_source.py,sha256=UDflHsk-Yh9-3YJTVBzKL32y8hcxiRgAlFEBTMiDqwM,3301
@@ -41,11 +41,12 @@ modusa/models/t_ax.py,sha256=ZUhvZPUW1TkdZYuUd6Ucm-vsv0JqtZ9yEe3ab67Ma6w,8022
41
41
  modusa/models/tds.py,sha256=FAGfibjyyE_lkEuQp-vSCuqQnopOjmy_IXqUjRlg9kc,11677
42
42
  modusa/plugins/__init__.py,sha256=r1Bf5mnrVKRIwxboutY1iGzDy4EPQhqpk1kSW7iJj_Q,54
43
43
  modusa/plugins/base.py,sha256=Bh_1Bja7fOymFsCgwhXDbV6ys3D8muNrPwrfDrG_G_A,2382
44
- modusa/tools/__init__.py,sha256=ixqujVIJwU5TNX2j64lVajGtZlXTspcxN-30X54GgcM,243
44
+ modusa/tools/__init__.py,sha256=6EO3h7wMRW49ajo27BJprANPQMrOGWZudwYYRNKVISU,278
45
45
  modusa/tools/ann_loader.py,sha256=RePlwD4qG6gGrD4mOJ3RDR9q_gUscCY90_R9lgFU9lM,780
46
46
  modusa/tools/audio_converter.py,sha256=415qBoPm2sBIuBSI7m1XBKm0AbmVmPydIPPr-uO8D3c,1778
47
47
  modusa/tools/audio_loader.py,sha256=DrCzq0pdiQrUDIG-deLJGcu8EaylO5yRtwT4lr8WSf8,2166
48
48
  modusa/tools/audio_player.py,sha256=GP04TWW4jBwQBjANkfR_cJtEy7cIhvbu8RTwnf9hD6E,2817
49
+ modusa/tools/audio_recorder.py,sha256=d2fVt0Sd2tlBdb2WlUs60K4N23zuxM3KUpQqX0ifPi8,2769
49
50
  modusa/tools/base.py,sha256=C0ESJ0mIfjjRlAkRbSetNtMoOfS6IrHBjexRp3l_Mh4,1293
50
51
  modusa/tools/math_ops.py,sha256=ZZ7U4DgqT7cOeE7_Lzi_Qq-48WYfwR9_osbZwTmE9eg,8690
51
52
  modusa/tools/plotter.py,sha256=e1NKFTFm8tG7yd-9VLmxmI9h9mTcUl1vaK1XDMvyoOw,18917
@@ -57,4 +58,4 @@ modusa/utils/excp.py,sha256=L9vhaGjKpv9viJYdmC9n5ndmk2GVbUBuFyZyhAQZmWY,906
57
58
  modusa/utils/logger.py,sha256=K0rsnObeNKCxlNeSnVnJeRhgfmob6riB2uyU7h3dDmA,571
58
59
  modusa/utils/np_func_cat.py,sha256=TyIFgRc6bARRMDnZxlVURO5Z0I-GWhxRONYyIv-Vwxs,1007
59
60
  modusa/utils/plot.py,sha256=s_vNdxvKfwxEngvJPgrF1PcmxZNnNaaXPViHWjyjJ-c,5335
60
- modusa-0.3.41.dist-info/RECORD,,
61
+ modusa-0.3.42.dist-info/RECORD,,