modusa 0.4.29__py3-none-any.whl → 0.4.31__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.
Files changed (58) hide show
  1. modusa/__init__.py +12 -8
  2. modusa/tools/__init__.py +11 -3
  3. modusa/tools/ann_saver.py +30 -0
  4. modusa/tools/audio_recorder.py +0 -1
  5. modusa/tools/audio_stft.py +72 -0
  6. modusa/tools/youtube_downloader.py +1 -4
  7. {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/METADATA +2 -2
  8. modusa-0.4.31.dist-info/RECORD +22 -0
  9. pyproject.toml +2 -2
  10. modusa/config.py +0 -18
  11. modusa/decorators.py +0 -176
  12. modusa/devtools/generate_docs_source.py +0 -92
  13. modusa/devtools/generate_template.py +0 -144
  14. modusa/devtools/list_authors.py +0 -2
  15. modusa/devtools/list_plugins.py +0 -60
  16. modusa/devtools/main.py +0 -45
  17. modusa/devtools/templates/generator.py +0 -24
  18. modusa/devtools/templates/io.py +0 -24
  19. modusa/devtools/templates/model.py +0 -47
  20. modusa/devtools/templates/plugin.py +0 -41
  21. modusa/devtools/templates/test.py +0 -10
  22. modusa/devtools/templates/tool.py +0 -24
  23. modusa/generators/__init__.py +0 -13
  24. modusa/generators/audio.py +0 -188
  25. modusa/generators/audio_waveforms.py +0 -236
  26. modusa/generators/base.py +0 -29
  27. modusa/generators/ftds.py +0 -298
  28. modusa/generators/s1d.py +0 -270
  29. modusa/generators/s2d.py +0 -300
  30. modusa/generators/s_ax.py +0 -102
  31. modusa/generators/t_ax.py +0 -64
  32. modusa/generators/tds.py +0 -267
  33. modusa/models/__init__.py +0 -14
  34. modusa/models/audio.py +0 -90
  35. modusa/models/base.py +0 -70
  36. modusa/models/data.py +0 -457
  37. modusa/models/ftds.py +0 -584
  38. modusa/models/s1d.py +0 -578
  39. modusa/models/s2d.py +0 -619
  40. modusa/models/s_ax.py +0 -448
  41. modusa/models/t_ax.py +0 -335
  42. modusa/models/tds.py +0 -465
  43. modusa/plugins/__init__.py +0 -3
  44. modusa/plugins/base.py +0 -100
  45. modusa/tools/_plotter_old.py +0 -629
  46. modusa/tools/audio_saver.py +0 -30
  47. modusa/tools/base.py +0 -43
  48. modusa/tools/math_ops.py +0 -335
  49. modusa/utils/__init__.py +0 -1
  50. modusa/utils/config.py +0 -25
  51. modusa/utils/excp.py +0 -49
  52. modusa/utils/logger.py +0 -18
  53. modusa/utils/np_func_cat.py +0 -44
  54. modusa/utils/plot.py +0 -142
  55. modusa-0.4.29.dist-info/RECORD +0 -65
  56. {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/WHEEL +0 -0
  57. {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/entry_points.txt +0 -0
  58. {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/licenses/LICENSE.md +0 -0
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- import inspect
4
- from pathlib import Path
5
-
6
- PLUGIN_PATH = Path(__file__).parent.parent / "plugins" # This directory contains all the plugins
7
-
8
- def find_plugin_files():
9
- return [
10
- path for path in PLUGIN_PATH.rglob("*.py")
11
- if path.name not in {"__init__.py", "base.py"} # We do not want to show base plugins
12
- ]
13
-
14
- def load_plugin_class_from_file(file_path):
15
- import importlib.util
16
- from modusa.plugins.base import ModusaPlugin
17
-
18
- spec = importlib.util.spec_from_file_location(file_path.stem, file_path)
19
- module = importlib.util.module_from_spec(spec)
20
- try:
21
- spec.loader.exec_module(module)
22
- except Exception as e:
23
- print(f"❌ Error loading {file_path}: {e}")
24
- return []
25
-
26
- plugin_classes = []
27
- for _, obj in inspect.getmembers(module, inspect.isclass):
28
- if issubclass(obj, ModusaPlugin) and obj is not ModusaPlugin:
29
- plugin_classes.append(obj)
30
-
31
- return plugin_classes
32
-
33
- def list_plugins():
34
- from rich.console import Console
35
- from rich.table import Table
36
- from modusa.plugins.base import ModusaPlugin
37
-
38
- console = Console()
39
- table = Table(title="🔌 Available Modusa Plugins")
40
-
41
- table.add_column("Plugin", style="bold green")
42
- table.add_column("Module", style="dim")
43
- table.add_column("Description", style="white")
44
-
45
- all_plugins = []
46
-
47
- for file_path in find_plugin_files():
48
- plugin_classes = load_plugin_class_from_file(file_path)
49
- for cls in plugin_classes:
50
- name = cls.__name__
51
- module = file_path.relative_to(PLUGIN_PATH.parent)
52
- author = getattr(cls, "author_name", "—")
53
- email = getattr(cls, "author_email", "—")
54
- desc = getattr(cls, "description", "—")
55
- table.add_row(name, str(module), desc)
56
- table.add_row("")
57
- all_plugins.append(cls)
58
-
59
- console.print(table)
60
-
modusa/devtools/main.py DELETED
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from .generate_template import TemplateGenerator
5
- from .generate_docs_source import generate_docs_source
6
- from .list_plugins import list_plugins
7
- from . import list_authors
8
-
9
- import argparse
10
- import sys
11
-
12
- def main():
13
- try:
14
- parser = argparse.ArgumentParser(
15
- prog="modusa-dev",
16
- description="Modusa CLI Tools"
17
- )
18
- subparsers = parser.add_subparsers(dest="group", required=True)
19
-
20
- # --- CREATE group ---
21
- create_parser = subparsers.add_parser("create", help="Create new Modusa components")
22
- create_subparsers = create_parser.add_subparsers(dest="what", required=True)
23
-
24
- create_subparsers.add_parser("tool", help="Create a new tool class").set_defaults(func=lambda:TemplateGenerator.create_template("tool"))
25
- create_subparsers.add_parser("plugin", help="Create a new plugin class").set_defaults(func=lambda:TemplateGenerator.create_template("plugin"))
26
- create_subparsers.add_parser("model", help="Create a new model class").set_defaults(func=lambda:TemplateGenerator.create_template("model"))
27
- create_subparsers.add_parser("generator", help="Create a new signal generator class").set_defaults(func=lambda:TemplateGenerator.create_template("generator"))
28
- create_subparsers.add_parser("io", help="Create a new IO class").set_defaults(func=lambda:TemplateGenerator.create_template("io"))
29
- create_subparsers.add_parser("docs", help="Generate the docs").set_defaults(func=lambda:generate_docs_source())
30
-
31
- # --- LIST group ---
32
- list_parser = subparsers.add_parser("list", help="List information about Modusa components")
33
- list_subparsers = list_parser.add_subparsers(dest="what", required=True)
34
-
35
- list_subparsers.add_parser("plugins", help="List available plugins").set_defaults(func=list_plugins)
36
- list_subparsers.add_parser("authors", help="List plugin authors").set_defaults(func=list_authors)
37
-
38
- # --- Parse and execute ---
39
- args = parser.parse_args()
40
- args.func()
41
-
42
- except KeyboardInterrupt:
43
- print("\n❌ Aborted by user.")
44
- sys.exit(1)
45
-
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import validate_args_type
6
- from modusa.generators.base import ModusaGenerator
7
-
8
-
9
- class {class_name}(ModusaGenerator):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
- def __init__(self):
23
- super().__init__()
24
-
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import validate_args_type
6
- from modusa.io.base import ModusaIO
7
-
8
-
9
- class {class_name}(ModusaIO):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
-
23
-
24
-
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import immutable_property, validate_args_type
6
- from modusa.signals.base import ?
7
- from typing import Self, Any
8
- import numpy as np
9
-
10
- class {class_name}():
11
- """
12
-
13
- """
14
-
15
- #--------Meta Information----------
16
- _name = ""
17
- _nickname = "" # This is to be used in repr/str methods
18
- _description = ""
19
- _author_name = "{author_name}"
20
- _author_email = "{author_email}"
21
- _created_at = "{date_created}"
22
- #----------------------------------
23
-
24
- @validate_args_type()
25
- def __init__(self):
26
- super().__init__() # Instantiating `ModusaSignal` class
27
-
28
- self.title = "" # This title will be used as plot title by default
29
-
30
- #-----------------------------------
31
- # Properties
32
- #-----------------------------------
33
-
34
-
35
- #===================================
36
-
37
-
38
-
39
-
40
-
41
-
42
- #-----------------------------------
43
- # Tools
44
- #-----------------------------------
45
-
46
-
47
- #===================================
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import immutable_property, validate_args_type, plugin_safety_check
6
- from modusa.plugins.base import ModusaPlugin
7
-
8
-
9
- class {class_name}(ModusaPlugin):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
- def __init__(self):
23
- super().__init__()
24
-
25
- @immutable_property(error_msg="Mutation not allowed.")
26
- def allowed_input_signal_types(self) -> tuple[type, ...]:
27
- return ()
28
-
29
-
30
- @immutable_property(error_msg="Mutation not allowed.")
31
- def allowed_output_signal_types(self) -> tuple[type, ...]:
32
- return ()
33
-
34
-
35
- @plugin_safety_check()
36
- @validate_args_type()
37
- def apply(self, signal: "") -> "":
38
-
39
- # Run the engine here
40
-
41
- return
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- from modusa import excp
4
-
5
- #--------Meta Information----------
6
- _class_name = "{class_name}"
7
- _author_name = "{author_name}"
8
- _author_email = "{author_email}"
9
- _created_at = "{date_created}"
10
- #----------------------------------
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import validate_args_type
6
- from modusa.tools.base import ModusaTool
7
-
8
-
9
- class {class_name}(ModusaTool):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
- def __init__(self):
23
- super().__init__()
24
-
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- from .base import ModusaGenerator
4
-
5
- from .s_ax import SAxGen
6
- from .t_ax import TAxGen
7
-
8
- from .s1d import S1DGen
9
- from .tds import TDSGen
10
- from .audio import AudioGen
11
-
12
- from .s2d import S2DGen
13
- from .ftds import FTDSGen
@@ -1,188 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import validate_args_type
6
- from .base import ModusaGenerator
7
- from modusa.models.t_ax import TAx
8
- from modusa.models.audio import Audio
9
- from modusa.models.data import Data
10
- import numpy as np
11
- from pathlib import Path
12
-
13
- class AudioGen(ModusaGenerator):
14
- """
15
- Provides user friendly APIs to generate instances of different
16
- `AudioSignal` instances.
17
- """
18
-
19
- #--------Meta Information----------
20
- _name = ""
21
- _description = ""
22
- _author_name = "Ankit Anand"
23
- _author_email = "ankit0.anand0@gmail.com"
24
- _created_at = "2025-07-27"
25
- #----------------------------------
26
-
27
- @staticmethod
28
- def from_array(
29
- y: np.ndarray,
30
- sr: float | int = 1.0,
31
- t0: float | int = 0.0,
32
- y_label: str = "Amplitude",
33
- t_label: str = "Time (sec)",
34
- title: str = "Audio Signal"
35
- ) -> Audio:
36
- """
37
- Create `AudioSignal` instance from basic data structures.
38
-
39
- .. code-block:: python
40
-
41
- import modusa as ms
42
- t = ms.tds.from_array([1, 2, 3])
43
- print(t)
44
- t.print_info()
45
-
46
- Parameters
47
- ----------
48
- y: np.ndarray
49
- - Audio data array.
50
- sr: float | int
51
- - Sampling rate.
52
- t0: float | int
53
- - Start timestamp.
54
- y_label: str
55
- - Y label for the signal.
56
- - Default: "Y"
57
- t_label: str
58
- - T label for the signal.
59
- - Default: "Time (sec)"
60
- title: str
61
- - Title for the signal.
62
- - Default: "1D Signal"
63
- Returns
64
- -------
65
- Audio
66
- An instance of Audio.
67
- """
68
- assert isinstance(y, np.ndarray)
69
- assert isinstance(sr, (int, float)) and isinstance(t0, (int, float))
70
- assert isinstance(y_label, str) and isinstance(t_label, str) and isinstance(title, str)
71
-
72
- assert y.ndim == 1
73
-
74
- sr = float(sr)
75
- t0 = float(t0)
76
-
77
- t = TAx(n_points=y.shape[0], sr=sr, t0=t0, label=t_label) # Creating a signal axis instance
78
- y = Data(values=y, label=y_label)
79
-
80
- return Audio(y=y, t=t, title=title)
81
-
82
- @classmethod
83
- def from_youtube(cls, url: str, sr: int | float = None):
84
- """
85
- Loads audio from youtube at a given sr.
86
- The audio is deleted from the device
87
- after loading.
88
-
89
- .. code-block:: python
90
-
91
- import modusa as ms
92
- audio = ms.audio.from_youtube(
93
- url="https://www.youtube.com/watch?v=lIpw9-Y_N0g",
94
- sr=None
95
- )
96
-
97
- PARAMETERS
98
- ----------
99
- url: str
100
- Link to the YouTube video.
101
- sr: int
102
- Sampling rate to load the audio in.
103
-
104
- Returns
105
- -------
106
- Audio:
107
- An `Audio` instance with loaded audio content from YouTube.
108
- """
109
-
110
- from modusa.tools.youtube_downloader import YoutubeDownloader
111
- from modusa import convert
112
- import soundfile as sf
113
- from scipy.signal import resample
114
- import tempfile
115
-
116
- # Download the audio in temp directory using tempfile module
117
- with tempfile.TemporaryDirectory() as tmpdir:
118
- audio_fp: Path = YoutubeDownloader.download(url=url, content_type="audio", output_dir=Path(tmpdir))
119
-
120
- # Convert the audio to ".wav" form for loading
121
- wav_audio_fp: Path = convert(inp_audio_fp=audio_fp, output_audio_fp=audio_fp.with_suffix(".wav"))
122
-
123
- # Load the audio in memory
124
- audio_data, audio_sr = sf.read(wav_audio_fp)
125
-
126
- # Convert to mono if it's multi-channel
127
- if audio_data.ndim > 1:
128
- audio_data = audio_data.mean(axis=1)
129
-
130
- # Resample if needed
131
- if sr is not None:
132
- if audio_sr != sr:
133
- n_samples = int(len(audio_data) * sr / audio_sr)
134
- audio_data = resample(audio_data, n_samples)
135
- audio_sr = sr
136
-
137
- audio = cls.from_array(y=audio_data, sr=audio_sr, title=audio_fp.stem)
138
-
139
- return audio
140
-
141
- @classmethod
142
- def from_filepath(cls, fp: str | Path, sr: int | float = None):
143
- """
144
- Loads audio from filepath at a given sr.
145
-
146
- .. code-block:: python
147
-
148
- import modusa as ms
149
- audio = ms.audio.from_filepath(
150
- fp="path/to/audio.wav",
151
- sr=None
152
- )
153
-
154
- PARAMETERS
155
- ----------
156
- fp: str | Path
157
- Audio file path.
158
- sr: int
159
- Sampling rate to load the audio in.
160
-
161
- Returns
162
- -------
163
- Audio:
164
- An `Audio` instance with loaded audio content.
165
- """
166
- import soundfile as sf
167
- from scipy.signal import resample
168
- from pathlib import Path
169
-
170
- fp = Path(fp)
171
- # Load the audio in memory
172
- audio_data, audio_sr = sf.read(fp)
173
-
174
- # Convert to mono if it's multi-channel
175
- if audio_data.ndim > 1:
176
- audio_data = audio_data.mean(axis=1)
177
-
178
- # Resample if needed
179
- if sr is not None:
180
- if audio_sr != sr:
181
- n_samples = int(len(audio_data) * sr / audio_sr)
182
- audio_data = resample(audio_data, n_samples)
183
- audio_sr = sr
184
-
185
- audio = cls.from_array(y=audio_data, sr=audio_sr, title=fp.stem)
186
-
187
- return audio
188
-