sonusai 1.0.16__cp311-abi3-macosx_10_12_x86_64.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 (150) hide show
  1. sonusai/__init__.py +170 -0
  2. sonusai/aawscd_probwrite.py +148 -0
  3. sonusai/audiofe.py +481 -0
  4. sonusai/calc_metric_spenh.py +1136 -0
  5. sonusai/config/__init__.py +0 -0
  6. sonusai/config/asr.py +21 -0
  7. sonusai/config/config.py +65 -0
  8. sonusai/config/config.yml +49 -0
  9. sonusai/config/constants.py +53 -0
  10. sonusai/config/ir.py +124 -0
  11. sonusai/config/ir_delay.py +62 -0
  12. sonusai/config/source.py +275 -0
  13. sonusai/config/spectral_masks.py +15 -0
  14. sonusai/config/truth.py +64 -0
  15. sonusai/constants.py +14 -0
  16. sonusai/data/__init__.py +0 -0
  17. sonusai/data/silero_vad_v5.1.jit +0 -0
  18. sonusai/data/silero_vad_v5.1.onnx +0 -0
  19. sonusai/data/speech_ma01_01.wav +0 -0
  20. sonusai/data/whitenoise.wav +0 -0
  21. sonusai/datatypes.py +383 -0
  22. sonusai/deprecated/gentcst.py +632 -0
  23. sonusai/deprecated/plot.py +519 -0
  24. sonusai/deprecated/tplot.py +365 -0
  25. sonusai/doc.py +52 -0
  26. sonusai/doc_strings/__init__.py +1 -0
  27. sonusai/doc_strings/doc_strings.py +531 -0
  28. sonusai/genft.py +196 -0
  29. sonusai/genmetrics.py +183 -0
  30. sonusai/genmix.py +199 -0
  31. sonusai/genmixdb.py +235 -0
  32. sonusai/ir_metric.py +551 -0
  33. sonusai/lsdb.py +141 -0
  34. sonusai/main.py +134 -0
  35. sonusai/metrics/__init__.py +43 -0
  36. sonusai/metrics/calc_audio_stats.py +42 -0
  37. sonusai/metrics/calc_class_weights.py +90 -0
  38. sonusai/metrics/calc_optimal_thresholds.py +73 -0
  39. sonusai/metrics/calc_pcm.py +45 -0
  40. sonusai/metrics/calc_pesq.py +36 -0
  41. sonusai/metrics/calc_phase_distance.py +43 -0
  42. sonusai/metrics/calc_sa_sdr.py +64 -0
  43. sonusai/metrics/calc_sample_weights.py +25 -0
  44. sonusai/metrics/calc_segsnr_f.py +82 -0
  45. sonusai/metrics/calc_speech.py +382 -0
  46. sonusai/metrics/calc_wer.py +71 -0
  47. sonusai/metrics/calc_wsdr.py +57 -0
  48. sonusai/metrics/calculate_metrics.py +395 -0
  49. sonusai/metrics/class_summary.py +74 -0
  50. sonusai/metrics/confusion_matrix_summary.py +75 -0
  51. sonusai/metrics/one_hot.py +283 -0
  52. sonusai/metrics/snr_summary.py +128 -0
  53. sonusai/metrics_summary.py +314 -0
  54. sonusai/mixture/__init__.py +15 -0
  55. sonusai/mixture/audio.py +187 -0
  56. sonusai/mixture/class_balancing.py +103 -0
  57. sonusai/mixture/constants.py +3 -0
  58. sonusai/mixture/data_io.py +173 -0
  59. sonusai/mixture/db.py +169 -0
  60. sonusai/mixture/db_datatypes.py +92 -0
  61. sonusai/mixture/effects.py +344 -0
  62. sonusai/mixture/feature.py +78 -0
  63. sonusai/mixture/generation.py +1116 -0
  64. sonusai/mixture/helpers.py +351 -0
  65. sonusai/mixture/ir_effects.py +77 -0
  66. sonusai/mixture/log_duration_and_sizes.py +23 -0
  67. sonusai/mixture/mixdb.py +1857 -0
  68. sonusai/mixture/pad_audio.py +35 -0
  69. sonusai/mixture/resample.py +7 -0
  70. sonusai/mixture/sox_effects.py +195 -0
  71. sonusai/mixture/sox_help.py +650 -0
  72. sonusai/mixture/spectral_mask.py +51 -0
  73. sonusai/mixture/truth.py +61 -0
  74. sonusai/mixture/truth_functions/__init__.py +45 -0
  75. sonusai/mixture/truth_functions/crm.py +105 -0
  76. sonusai/mixture/truth_functions/energy.py +222 -0
  77. sonusai/mixture/truth_functions/file.py +48 -0
  78. sonusai/mixture/truth_functions/metadata.py +24 -0
  79. sonusai/mixture/truth_functions/metrics.py +28 -0
  80. sonusai/mixture/truth_functions/phoneme.py +18 -0
  81. sonusai/mixture/truth_functions/sed.py +98 -0
  82. sonusai/mixture/truth_functions/target.py +142 -0
  83. sonusai/mkwav.py +135 -0
  84. sonusai/onnx_predict.py +363 -0
  85. sonusai/parse/__init__.py +0 -0
  86. sonusai/parse/expand.py +156 -0
  87. sonusai/parse/parse_source_directive.py +129 -0
  88. sonusai/parse/rand.py +214 -0
  89. sonusai/py.typed +0 -0
  90. sonusai/queries/__init__.py +0 -0
  91. sonusai/queries/queries.py +239 -0
  92. sonusai/rs.abi3.so +0 -0
  93. sonusai/rs.pyi +1 -0
  94. sonusai/rust/__init__.py +0 -0
  95. sonusai/speech/__init__.py +0 -0
  96. sonusai/speech/l2arctic.py +121 -0
  97. sonusai/speech/librispeech.py +102 -0
  98. sonusai/speech/mcgill.py +71 -0
  99. sonusai/speech/textgrid.py +89 -0
  100. sonusai/speech/timit.py +138 -0
  101. sonusai/speech/types.py +12 -0
  102. sonusai/speech/vctk.py +53 -0
  103. sonusai/speech/voxceleb.py +108 -0
  104. sonusai/utils/__init__.py +3 -0
  105. sonusai/utils/asl_p56.py +130 -0
  106. sonusai/utils/asr.py +91 -0
  107. sonusai/utils/asr_functions/__init__.py +3 -0
  108. sonusai/utils/asr_functions/aaware_whisper.py +69 -0
  109. sonusai/utils/audio_devices.py +50 -0
  110. sonusai/utils/braced_glob.py +50 -0
  111. sonusai/utils/calculate_input_shape.py +26 -0
  112. sonusai/utils/choice.py +51 -0
  113. sonusai/utils/compress.py +25 -0
  114. sonusai/utils/convert_string_to_number.py +6 -0
  115. sonusai/utils/create_timestamp.py +5 -0
  116. sonusai/utils/create_ts_name.py +14 -0
  117. sonusai/utils/dataclass_from_dict.py +27 -0
  118. sonusai/utils/db.py +16 -0
  119. sonusai/utils/docstring.py +53 -0
  120. sonusai/utils/energy_f.py +44 -0
  121. sonusai/utils/engineering_number.py +166 -0
  122. sonusai/utils/evaluate_random_rule.py +15 -0
  123. sonusai/utils/get_frames_per_batch.py +2 -0
  124. sonusai/utils/get_label_names.py +20 -0
  125. sonusai/utils/grouper.py +6 -0
  126. sonusai/utils/human_readable_size.py +7 -0
  127. sonusai/utils/keyboard_interrupt.py +12 -0
  128. sonusai/utils/load_object.py +21 -0
  129. sonusai/utils/max_text_width.py +9 -0
  130. sonusai/utils/model_utils.py +28 -0
  131. sonusai/utils/numeric_conversion.py +11 -0
  132. sonusai/utils/onnx_utils.py +155 -0
  133. sonusai/utils/parallel.py +162 -0
  134. sonusai/utils/path_info.py +7 -0
  135. sonusai/utils/print_mixture_details.py +60 -0
  136. sonusai/utils/rand.py +13 -0
  137. sonusai/utils/ranges.py +43 -0
  138. sonusai/utils/read_predict_data.py +32 -0
  139. sonusai/utils/reshape.py +154 -0
  140. sonusai/utils/seconds_to_hms.py +7 -0
  141. sonusai/utils/stacked_complex.py +82 -0
  142. sonusai/utils/stratified_shuffle_split.py +170 -0
  143. sonusai/utils/tokenized_shell_vars.py +143 -0
  144. sonusai/utils/write_audio.py +26 -0
  145. sonusai/utils/yes_or_no.py +8 -0
  146. sonusai/vars.py +47 -0
  147. sonusai-1.0.16.dist-info/METADATA +56 -0
  148. sonusai-1.0.16.dist-info/RECORD +150 -0
  149. sonusai-1.0.16.dist-info/WHEEL +4 -0
  150. sonusai-1.0.16.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,173 @@
1
+ from typing import Any
2
+
3
+
4
+ def _get_hdf5_name(location: str, index: str) -> str:
5
+ from os.path import join
6
+
7
+ return join(location, index + ".h5")
8
+
9
+
10
+ def _get_pickle_name(location: str, index: str, item: str) -> str:
11
+ from os.path import join
12
+
13
+ return join(location, index, item + ".pkl")
14
+
15
+
16
+ def read_hdf5_data(location: str, index: str, items: list[str] | str) -> dict[str, Any]:
17
+ """Read mixture, target, or noise data from an HDF5 file
18
+
19
+ :param location: Location of the file
20
+ :param index: Mixture, target, or noise index
21
+ :param items: String(s) of data to retrieve
22
+ :return: Dictionary of name: data
23
+ """
24
+ from os.path import exists
25
+ from typing import Any
26
+
27
+ import h5py
28
+ import numpy as np
29
+
30
+ def _get_dataset(file: h5py.File, d_name: str) -> Any:
31
+ if d_name in file:
32
+ data = np.array(file[d_name])
33
+ if data.size == 1:
34
+ item = data.item()
35
+ if isinstance(item, bytes):
36
+ return item.decode("utf-8")
37
+ return item
38
+ return data
39
+ return None
40
+
41
+ if not isinstance(items, list):
42
+ items = [items]
43
+
44
+ h5_name = _get_hdf5_name(location, index)
45
+ if exists(h5_name):
46
+ try:
47
+ with h5py.File(h5_name, "r") as f:
48
+ result = {item: _get_dataset(f, item) for item in items}
49
+ except Exception as e:
50
+ raise OSError(f"Error reading {h5_name}: {e}") from e
51
+ else:
52
+ result = {item: None for item in items}
53
+
54
+ return result
55
+
56
+
57
+ def write_hdf5_data(location: str, index: str, items: dict[str, Any]) -> None:
58
+ """Write mixture, target, or noise data to an HDF5 file
59
+
60
+ :param location: Location of the file
61
+ :param index: Mixture, target, or noise index
62
+ :param items: Dictionary of name: data
63
+ """
64
+ import h5py
65
+
66
+ h5_name = _get_hdf5_name(location, index)
67
+ with h5py.File(h5_name, "a") as f:
68
+ for name, data in items.items():
69
+ if name in f:
70
+ del f[name]
71
+ f.create_dataset(name=name, data=data)
72
+
73
+
74
+ def read_pickle_data(location: str, index: str, items: list[str] | str) -> dict[str, Any]:
75
+ """Read mixture, target, or noise data from a pickle file
76
+
77
+ :param location: Location of the file
78
+ :param index: Mixture, target, or noise index
79
+ :param items: String(s) of data to retrieve
80
+ :return: Dictionary of name: data
81
+ """
82
+ import pickle
83
+ from os.path import exists
84
+ from typing import Any
85
+
86
+ if not isinstance(items, list):
87
+ items = [items]
88
+
89
+ result: dict[str, Any] = {}
90
+ for item in items:
91
+ pkl_name = _get_pickle_name(location, index, item)
92
+ if exists(pkl_name):
93
+ with open(pkl_name, "rb") as f:
94
+ result[item] = pickle.load(f) # noqa: S301
95
+ else:
96
+ result[item] = None
97
+
98
+ return result
99
+
100
+
101
+ def write_pickle_data(location: str, index: str, items: dict[str, Any]) -> None:
102
+ """Write mixture, target, or noise data to a pickle file
103
+
104
+ :param location: Location of the file
105
+ :param index: Mixture, target, or noise index
106
+ :param items: Dictionary of name: data
107
+ """
108
+ import pickle
109
+ from os import makedirs
110
+ from os.path import join
111
+
112
+ directory = join(location, index)
113
+ makedirs(directory, exist_ok=True)
114
+ for name, data in items.items():
115
+ pkl_name = _get_pickle_name(location, index, name)
116
+ with open(pkl_name, "wb") as f:
117
+ f.write(pickle.dumps(data))
118
+
119
+
120
+ def clear_pickle_data(location: str, index: str, items: list[str] | str) -> None:
121
+ """Clear mixture, target, or noise data pickle file
122
+
123
+ :param location: Location of the file
124
+ :param index: Mixture, target, or noise index
125
+ :param items: String(s) of data to retrieve
126
+ """
127
+ from pathlib import Path
128
+
129
+ if not isinstance(items, list):
130
+ items = [items]
131
+
132
+ for item in items:
133
+ Path(_get_pickle_name(location, index, item)).unlink(missing_ok=True)
134
+
135
+
136
+ def read_cached_data(location: str, name: str, index: str, items: list[str] | str) -> dict[str, Any]:
137
+ """Read cached data from a file
138
+
139
+ :param location: Location of the mixture database
140
+ :param name: Data name ('mixture', 'target', or 'noise')
141
+ :param index: Data index (mixture, target, or noise ID)
142
+ :param items: String(s) of data to retrieve
143
+ :return: Data (or tuple of data)
144
+ """
145
+ from os.path import join
146
+
147
+ return read_pickle_data(join(location, name), index, items)
148
+
149
+
150
+ def write_cached_data(location: str, name: str, index: str, items: dict[str, Any]) -> None:
151
+ """Write data to a file
152
+
153
+ :param location: Location of the mixture database
154
+ :param name: Data name ('mixture', 'target', or 'noise')
155
+ :param index: Data index (mixture, target, or noise ID)
156
+ :param items: Dictionary of name: data
157
+ """
158
+ from os.path import join
159
+
160
+ write_pickle_data(join(location, name), index, items)
161
+
162
+
163
+ def clear_cached_data(location: str, name: str, index: str, items: list[str] | str) -> None:
164
+ """Remove cached data file(s)
165
+
166
+ :param location: Location of the mixture database
167
+ :param name: Data name ('mixture', 'target', or 'noise')
168
+ :param index: Data index (mixture, target, or noise ID)
169
+ :param items: String(s) of data to clear
170
+ """
171
+ from os.path import join
172
+
173
+ clear_pickle_data(join(location, name), index, items)
sonusai/mixture/db.py ADDED
@@ -0,0 +1,169 @@
1
+ import contextlib
2
+ import sqlite3
3
+ from os import remove
4
+ from os.path import exists
5
+ from os.path import join
6
+ from os.path import normpath
7
+ from sqlite3 import Connection
8
+ from sqlite3 import Cursor
9
+ from typing import Any
10
+
11
+ from sonusai import logger_db
12
+
13
+
14
+ def db_file(location: str, test: bool = False) -> str:
15
+ from .constants import MIXDB_NAME
16
+ from .constants import TEST_MIXDB_NAME
17
+
18
+ name = TEST_MIXDB_NAME if test else MIXDB_NAME
19
+ return normpath(join(location, name))
20
+
21
+
22
+ class SQLiteDatabase:
23
+ """A context manager for SQLite database connections with configurable behavior."""
24
+
25
+ # Constants for database configuration
26
+ READONLY_MODE = "?mode=ro"
27
+ CONNECTION_TIMEOUT = 20
28
+
29
+ def __init__(
30
+ self,
31
+ location: str,
32
+ create: bool = False,
33
+ readonly: bool = True,
34
+ test: bool = False,
35
+ verbose: bool = False,
36
+ ) -> None:
37
+ """Initialize SQLite database connection manager.
38
+
39
+ :param location: Path to the database file.
40
+ :param create: If True, create a new database file, overwriting any existing one.
41
+ :param readonly: If True, open the database in read-only mode.
42
+ :param test: If True, use the test database path.
43
+ :param verbose: If True, enable SQL statement logging.
44
+ """
45
+ self.location = location
46
+ self.create = create
47
+ self.readonly = readonly and not create
48
+ self.test = test
49
+ self.verbose = verbose
50
+ self.con: Connection | None = None
51
+ self.cur: Cursor | None = None
52
+ self.db_path = db_file(location, test)
53
+
54
+ def __enter__(self) -> Cursor:
55
+ """Enter the context manager, establishing the database connection.
56
+
57
+ :return: A database cursor for executing queries.
58
+ :raises sqlite3.Error: If the connection fails.
59
+ """
60
+ try:
61
+ self._establish_connection()
62
+ except Exception:
63
+ self._close_resources()
64
+ raise
65
+
66
+ if self.cur:
67
+ self.cur.execute("BEGIN TRANSACTION")
68
+ return self.cur
69
+ raise sqlite3.Error("Failed to connect to database")
70
+
71
+ def __exit__(
72
+ self,
73
+ exc_type: type[BaseException] | None,
74
+ exc_val: BaseException | None,
75
+ exc_tb: Any | None,
76
+ ) -> None:
77
+ """Exit the context manager, committing changes if appropriate and closing resources.
78
+
79
+ :param exc_type: The exception type, if any.
80
+ :param exc_val: The exception value, if any.
81
+ :param exc_tb: The exception traceback, if any.
82
+ """
83
+ if self.con:
84
+ if not self.readonly:
85
+ if exc_type is None:
86
+ # Commit only on successful exit
87
+ self.con.commit()
88
+ else:
89
+ # Rollback on exception
90
+ self.con.rollback()
91
+ self._close_resources()
92
+
93
+ def _close_resources(self) -> None:
94
+ """Safely close database cursor and connection resources."""
95
+ if self.cur:
96
+ with contextlib.suppress(sqlite3.Error):
97
+ self.cur.close()
98
+ self.cur = None
99
+
100
+ if self.con:
101
+ with contextlib.suppress(sqlite3.Error):
102
+ self.con.close()
103
+ self.con = None
104
+
105
+ def _establish_connection(self) -> None:
106
+ """Establish a connection to the SQLite database.
107
+
108
+ :raises OSError: If the database file doesn't exist and create=False.
109
+ :raises sqlite3.Error: If connection to the database fails.
110
+ """
111
+ self._prepare_db_file(self.db_path)
112
+ uri = self._build_connection_uri(self.db_path)
113
+
114
+ try:
115
+ self.con = sqlite3.connect(
116
+ f"file:{uri}",
117
+ uri=True,
118
+ timeout=self.CONNECTION_TIMEOUT,
119
+ isolation_level=None,
120
+ )
121
+
122
+ if self.verbose and self.con:
123
+ self.con.set_trace_callback(logger_db.debug)
124
+
125
+ if not self.readonly:
126
+ self.con.execute("PRAGMA journal_mode=wal")
127
+ self.con.execute("PRAGMA synchronous=off")
128
+ self.con.execute("PRAGMA locking_mode=exclusive")
129
+ self.con.execute("PRAGMA cache_size=10000")
130
+ self.con.execute("PRAGMA temp_store=memory")
131
+ self.con.execute("PRAGMA mmap_size=268435456") # 256MB
132
+ else:
133
+ self.con.execute("PRAGMA synchronous=normal")
134
+ self.con.execute("PRAGMA cache_size=10000")
135
+ self.con.execute("PRAGMA temp_store=memory")
136
+ self.con.execute("PRAGMA mmap_size=268435456") # 256MB
137
+
138
+ self.con.commit()
139
+
140
+ except sqlite3.Error as e:
141
+ raise sqlite3.Error(f"Failed to connect to database: {e}") from e
142
+
143
+ self.cur = self.con.cursor()
144
+
145
+ def _prepare_db_file(self, db_path: str) -> None:
146
+ """Prepare the database file based on creation settings.
147
+
148
+ :param db_path: Path to the database file.
149
+ :raises OSError: If the database file doesn't exist and create=False.
150
+ """
151
+ if self.create and exists(db_path):
152
+ remove(db_path)
153
+
154
+ if not self.create and not exists(db_path):
155
+ raise OSError(f"Could not find mixture database in {self.location}")
156
+
157
+ def _build_connection_uri(self, db_path: str) -> str:
158
+ """Build the SQLite connection URI with appropriate options.
159
+
160
+ :param db_path: Path to the database file.
161
+ :return: A properly formatted SQLite URI with appropriate options.
162
+ """
163
+ uri = db_path
164
+
165
+ # Add readonly mode if needed
166
+ if self.readonly:
167
+ uri += self.READONLY_MODE
168
+
169
+ return uri
@@ -0,0 +1,92 @@
1
+ from collections import namedtuple
2
+
3
+ SourceFileRecord = namedtuple(
4
+ "SourceFileRecord",
5
+ [
6
+ "id",
7
+ "category",
8
+ "class_indices",
9
+ "level_type",
10
+ "name",
11
+ "samples",
12
+ "speaker_id",
13
+ ],
14
+ )
15
+
16
+ TopRecord = namedtuple(
17
+ "TopRecord",
18
+ [
19
+ "id",
20
+ "class_balancing",
21
+ "feature",
22
+ "mixid_width",
23
+ "num_classes",
24
+ "seed",
25
+ "speaker_metadata_tiers",
26
+ "textgrid_metadata_tiers",
27
+ "version",
28
+ ],
29
+ )
30
+
31
+ ClassLabelRecord = namedtuple(
32
+ "ClassLabelRecord",
33
+ [
34
+ "id",
35
+ "label",
36
+ ],
37
+ )
38
+
39
+ ClassWeightsThresholdRecord = namedtuple(
40
+ "ClassWeightsThresholdRecord",
41
+ [
42
+ "id",
43
+ "threshold",
44
+ ],
45
+ )
46
+
47
+ ImpulseResponseFileRecord = namedtuple(
48
+ "ImpulseResponseFileRecord",
49
+ [
50
+ "id",
51
+ "delay",
52
+ "name",
53
+ ],
54
+ )
55
+
56
+ SpectralMaskRecord = namedtuple(
57
+ "SpectralMaskRecord",
58
+ [
59
+ "id",
60
+ "f_max_width",
61
+ "f_num",
62
+ "t_max_percent",
63
+ "t_max_width",
64
+ "t_num",
65
+ ],
66
+ )
67
+
68
+ SourceRecord = namedtuple(
69
+ "SourceRecord",
70
+ [
71
+ "id",
72
+ "effects",
73
+ "file_id",
74
+ "pre_tempo",
75
+ "repeat",
76
+ "snr",
77
+ "snr_gain",
78
+ "snr_random",
79
+ "start",
80
+ ],
81
+ )
82
+
83
+ MixtureRecord = namedtuple(
84
+ "MixtureRecord",
85
+ [
86
+ "id",
87
+ "name",
88
+ "samples",
89
+ "spectral_mask_id",
90
+ "spectral_mask_seed",
91
+ ],
92
+ )