sonusai 0.20.3__py3-none-any.whl → 1.0.2__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 (97) hide show
  1. sonusai/__init__.py +16 -3
  2. sonusai/audiofe.py +241 -77
  3. sonusai/calc_metric_spenh.py +71 -73
  4. sonusai/config/__init__.py +3 -0
  5. sonusai/config/config.py +61 -0
  6. sonusai/config/config.yml +20 -0
  7. sonusai/config/constants.py +8 -0
  8. sonusai/constants.py +11 -0
  9. sonusai/data/genmixdb.yml +21 -36
  10. sonusai/{mixture/datatypes.py → datatypes.py} +91 -130
  11. sonusai/deprecated/plot.py +4 -5
  12. sonusai/doc/doc.py +4 -4
  13. sonusai/doc.py +11 -4
  14. sonusai/genft.py +43 -45
  15. sonusai/genmetrics.py +25 -19
  16. sonusai/genmix.py +54 -82
  17. sonusai/genmixdb.py +88 -264
  18. sonusai/ir_metric.py +30 -34
  19. sonusai/lsdb.py +41 -48
  20. sonusai/main.py +15 -22
  21. sonusai/metrics/calc_audio_stats.py +4 -293
  22. sonusai/metrics/calc_class_weights.py +4 -4
  23. sonusai/metrics/calc_optimal_thresholds.py +8 -5
  24. sonusai/metrics/calc_pesq.py +2 -2
  25. sonusai/metrics/calc_segsnr_f.py +4 -4
  26. sonusai/metrics/calc_speech.py +25 -13
  27. sonusai/metrics/class_summary.py +7 -7
  28. sonusai/metrics/confusion_matrix_summary.py +5 -5
  29. sonusai/metrics/one_hot.py +4 -4
  30. sonusai/metrics/snr_summary.py +7 -7
  31. sonusai/metrics_summary.py +38 -45
  32. sonusai/mixture/__init__.py +4 -104
  33. sonusai/mixture/audio.py +10 -39
  34. sonusai/mixture/class_balancing.py +103 -0
  35. sonusai/mixture/config.py +251 -271
  36. sonusai/mixture/constants.py +35 -39
  37. sonusai/mixture/data_io.py +25 -36
  38. sonusai/mixture/db_datatypes.py +58 -22
  39. sonusai/mixture/effects.py +386 -0
  40. sonusai/mixture/feature.py +7 -11
  41. sonusai/mixture/generation.py +478 -628
  42. sonusai/mixture/helpers.py +82 -184
  43. sonusai/mixture/ir_delay.py +3 -4
  44. sonusai/mixture/ir_effects.py +77 -0
  45. sonusai/mixture/log_duration_and_sizes.py +6 -12
  46. sonusai/mixture/mixdb.py +910 -729
  47. sonusai/mixture/pad_audio.py +35 -0
  48. sonusai/mixture/resample.py +7 -0
  49. sonusai/mixture/sox_effects.py +195 -0
  50. sonusai/mixture/sox_help.py +650 -0
  51. sonusai/mixture/spectral_mask.py +2 -2
  52. sonusai/mixture/truth.py +17 -15
  53. sonusai/mixture/truth_functions/crm.py +12 -12
  54. sonusai/mixture/truth_functions/energy.py +22 -22
  55. sonusai/mixture/truth_functions/file.py +5 -5
  56. sonusai/mixture/truth_functions/metadata.py +4 -4
  57. sonusai/mixture/truth_functions/metrics.py +4 -4
  58. sonusai/mixture/truth_functions/phoneme.py +3 -3
  59. sonusai/mixture/truth_functions/sed.py +11 -13
  60. sonusai/mixture/truth_functions/target.py +10 -10
  61. sonusai/mkwav.py +26 -29
  62. sonusai/onnx_predict.py +240 -88
  63. sonusai/queries/__init__.py +2 -2
  64. sonusai/queries/queries.py +38 -34
  65. sonusai/speech/librispeech.py +1 -1
  66. sonusai/speech/mcgill.py +1 -1
  67. sonusai/speech/timit.py +2 -2
  68. sonusai/summarize_metric_spenh.py +10 -17
  69. sonusai/utils/__init__.py +7 -1
  70. sonusai/utils/asl_p56.py +2 -2
  71. sonusai/utils/asr.py +2 -2
  72. sonusai/utils/asr_functions/aaware_whisper.py +4 -5
  73. sonusai/utils/choice.py +31 -0
  74. sonusai/utils/compress.py +1 -1
  75. sonusai/utils/dataclass_from_dict.py +19 -1
  76. sonusai/utils/energy_f.py +3 -3
  77. sonusai/utils/evaluate_random_rule.py +15 -0
  78. sonusai/utils/keyboard_interrupt.py +12 -0
  79. sonusai/utils/onnx_utils.py +3 -17
  80. sonusai/utils/print_mixture_details.py +21 -19
  81. sonusai/utils/{temp_seed.py → rand.py} +3 -3
  82. sonusai/utils/read_predict_data.py +2 -2
  83. sonusai/utils/reshape.py +3 -3
  84. sonusai/utils/stratified_shuffle_split.py +3 -3
  85. sonusai/{mixture → utils}/tokenized_shell_vars.py +1 -1
  86. sonusai/utils/write_audio.py +2 -2
  87. sonusai/vars.py +11 -4
  88. {sonusai-0.20.3.dist-info → sonusai-1.0.2.dist-info}/METADATA +4 -2
  89. sonusai-1.0.2.dist-info/RECORD +138 -0
  90. sonusai/mixture/augmentation.py +0 -444
  91. sonusai/mixture/class_count.py +0 -15
  92. sonusai/mixture/eq_rule_is_valid.py +0 -45
  93. sonusai/mixture/target_class_balancing.py +0 -107
  94. sonusai/mixture/targets.py +0 -175
  95. sonusai-0.20.3.dist-info/RECORD +0 -128
  96. {sonusai-0.20.3.dist-info → sonusai-1.0.2.dist-info}/WHEEL +0 -0
  97. {sonusai-0.20.3.dist-info → sonusai-1.0.2.dist-info}/entry_points.txt +0 -0
@@ -1,56 +1,52 @@
1
- import re
2
1
  from importlib.resources import as_file
3
2
  from importlib.resources import files
4
3
 
5
- REQUIRED_CONFIGS = [
4
+ REQUIRED_CONFIGS: tuple[str, ...] = (
6
5
  "asr_configs",
7
6
  "class_balancing",
8
- "class_balancing_augmentation",
7
+ "class_balancing_effect",
9
8
  "class_indices",
10
9
  "class_labels",
11
10
  "class_weights_threshold",
12
11
  "feature",
13
12
  "impulse_responses",
14
- "noise_augmentations",
15
- "noise_mix_mode",
16
- "noises",
13
+ "level_type",
14
+ "mixture_effects",
17
15
  "num_classes",
18
- "random_snrs",
19
16
  "seed",
20
- "snrs",
17
+ "sources",
21
18
  "spectral_masks",
22
- "target_augmentations",
23
- "target_level_type",
24
- "targets",
25
- "truth_configs",
26
- ]
27
- OPTIONAL_CONFIGS: list[str] = []
28
- VALID_CONFIGS = REQUIRED_CONFIGS + OPTIONAL_CONFIGS
29
- REQUIRED_TRUTH_CONFIGS = ["function", "stride_reduction"]
30
- REQUIRED_ASR_CONFIGS = ["engine"]
31
- VALID_AUGMENTATIONS = [
32
- "normalize",
33
- "gain",
34
- "pitch",
35
- "tempo",
36
- "eq1",
37
- "eq2",
38
- "eq3",
39
- "lpf",
40
- "ir",
41
- ]
42
- VALID_NOISE_MIX_MODES = ["exhaustive", "non-exhaustive", "non-combinatorial"]
43
- RAND_PATTERN = re.compile(r"rand\(([-+]?(\d+(\.\d*)?|\.\d+)),\s*([-+]?(\d+(\.\d*)?|\.\d+))\)")
44
- SAMPLE_RATE = 16000
45
- BIT_DEPTH = 32
46
- ENCODING = "floating-point"
47
- CHANNEL_COUNT = 1
48
- SAMPLE_BYTES = BIT_DEPTH // 8
49
- FLOAT_BYTES = 4
50
- MIXDB_VERSION = 2
19
+ "summed_source_effects",
20
+ )
21
+ OPTIONAL_CONFIGS: tuple[str, ...] = ()
22
+ VALID_CONFIGS: tuple[str, ...] = REQUIRED_CONFIGS + OPTIONAL_CONFIGS
23
+
24
+ REQUIRED_SOURCES_CATEGORIES: tuple[str, ...] = (
25
+ "primary",
26
+ "noise",
27
+ )
28
+
29
+ REQUIRED_SOURCE_CONFIGS: tuple[str, ...] = (
30
+ "effects",
31
+ "files",
32
+ )
33
+ OPTIONAL_SOURCE_CONFIGS: tuple[str, ...] = ("truth_configs",)
34
+ REQUIRED_NON_PRIMARY_SOURCE_CONFIGS: tuple[str, ...] = (
35
+ "mix_rules",
36
+ "snrs",
37
+ )
38
+ VALID_PRIMARY_SOURCE_CONFIGS: tuple[str, ...] = REQUIRED_SOURCE_CONFIGS + OPTIONAL_SOURCE_CONFIGS
39
+ VALID_NON_PRIMARY_SOURCE_CONFIGS: tuple[str, ...] = VALID_PRIMARY_SOURCE_CONFIGS + REQUIRED_NON_PRIMARY_SOURCE_CONFIGS
40
+
41
+ REQUIRED_TRUTH_CONFIGS: tuple[str, ...] = (
42
+ "function",
43
+ "stride_reduction",
44
+ )
45
+ REQUIRED_ASR_CONFIGS: tuple[str, ...] = ("engine",)
51
46
 
52
- with as_file(files("sonusai.data").joinpath("whitenoise.wav")) as path:
53
- DEFAULT_NOISE = str(path)
47
+ MIXDB_VERSION = 3
48
+ MIXDB_NAME = "mixdb.db"
49
+ TEST_MIXDB_NAME = "mixdb_test.db"
54
50
 
55
51
  with as_file(files("sonusai.data").joinpath("genmixdb.yml")) as path:
56
52
  DEFAULT_CONFIG = str(path)
@@ -13,13 +13,13 @@ def _get_pickle_name(location: str, index: str, item: str) -> str:
13
13
  return join(location, index, item + ".pkl")
14
14
 
15
15
 
16
- def read_hdf5_data(location: str, index: str, items: list[str] | str) -> Any:
16
+ def read_hdf5_data(location: str, index: str, items: list[str] | str) -> dict[str, Any]:
17
17
  """Read mixture, target, or noise data from an HDF5 file
18
18
 
19
19
  :param location: Location of the file
20
20
  :param index: Mixture, target, or noise index
21
21
  :param items: String(s) of data to retrieve
22
- :return: Data (or tuple of data)
22
+ :return: Dictionary of name: data
23
23
  """
24
24
  from os.path import exists
25
25
  from typing import Any
@@ -45,45 +45,39 @@ def read_hdf5_data(location: str, index: str, items: list[str] | str) -> Any:
45
45
  if exists(h5_name):
46
46
  try:
47
47
  with h5py.File(h5_name, "r") as f:
48
- result = [_get_dataset(f, item) for item in items]
48
+ result = {item: _get_dataset(f, item) for item in items}
49
49
  except Exception as e:
50
50
  raise OSError(f"Error reading {h5_name}: {e}") from e
51
51
  else:
52
- result = [None for _ in items]
53
-
54
- if len(items) == 1:
55
- result = result[0]
52
+ result = {item: None for item in items}
56
53
 
57
54
  return result
58
55
 
59
56
 
60
- def write_hdf5_data(location: str, index: str, items: list[tuple[str, Any]] | tuple[str, Any]) -> None:
57
+ def write_hdf5_data(location: str, index: str, items: dict[str, Any]) -> None:
61
58
  """Write mixture, target, or noise data to an HDF5 file
62
59
 
63
60
  :param location: Location of the file
64
61
  :param index: Mixture, target, or noise index
65
- :param items: Tuple(s) of (name, data)
62
+ :param items: Dictionary of name: data
66
63
  """
67
64
  import h5py
68
65
 
69
- if not isinstance(items, list):
70
- items = [items]
71
-
72
66
  h5_name = _get_hdf5_name(location, index)
73
67
  with h5py.File(h5_name, "a") as f:
74
- for item in items:
75
- if item[0] in f:
76
- del f[item[0]]
77
- f.create_dataset(name=item[0], data=item[1])
68
+ for name, data in items.items():
69
+ if name in f:
70
+ del f[name]
71
+ f.create_dataset(name=name, data=data)
78
72
 
79
73
 
80
- def read_pickle_data(location: str, index: str, items: list[str] | str) -> Any:
74
+ def read_pickle_data(location: str, index: str, items: list[str] | str) -> dict[str, Any]:
81
75
  """Read mixture, target, or noise data from a pickle file
82
76
 
83
77
  :param location: Location of the file
84
78
  :param index: Mixture, target, or noise index
85
79
  :param items: String(s) of data to retrieve
86
- :return: Data (or tuple of data)
80
+ :return: Dictionary of name: data
87
81
  """
88
82
  import pickle
89
83
  from os.path import exists
@@ -92,40 +86,35 @@ def read_pickle_data(location: str, index: str, items: list[str] | str) -> Any:
92
86
  if not isinstance(items, list):
93
87
  items = [items]
94
88
 
95
- result: list[Any] = []
89
+ result: dict[str, Any] = {}
96
90
  for item in items:
97
91
  pkl_name = _get_pickle_name(location, index, item)
98
92
  if exists(pkl_name):
99
93
  with open(pkl_name, "rb") as f:
100
- result.append(pickle.load(f)) # noqa: S301
94
+ result[item] = pickle.load(f) # noqa: S301
101
95
  else:
102
- result.append(None)
103
-
104
- if len(items) == 1:
105
- result = result[0]
96
+ result[item] = None
106
97
 
107
98
  return result
108
99
 
109
100
 
110
- def write_pickle_data(location: str, index: str, items: list[tuple[str, Any]] | tuple[str, Any]) -> None:
101
+ def write_pickle_data(location: str, index: str, items: dict[str, Any]) -> None:
111
102
  """Write mixture, target, or noise data to a pickle file
112
103
 
113
104
  :param location: Location of the file
114
105
  :param index: Mixture, target, or noise index
115
- :param items: Tuple(s) of (name, data)
106
+ :param items: Dictionary of name: data
116
107
  """
117
108
  import pickle
118
109
  from os import makedirs
119
110
  from os.path import join
120
111
 
121
- if not isinstance(items, list):
122
- items = [items]
123
-
124
- makedirs(join(location, index), exist_ok=True)
125
- for item in items:
126
- pkl_name = _get_pickle_name(location, index, item[0])
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)
127
116
  with open(pkl_name, "wb") as f:
128
- f.write(pickle.dumps(item[1]))
117
+ f.write(pickle.dumps(data))
129
118
 
130
119
 
131
120
  def clear_pickle_data(location: str, index: str, items: list[str] | str) -> None:
@@ -144,7 +133,7 @@ def clear_pickle_data(location: str, index: str, items: list[str] | str) -> None
144
133
  Path(_get_pickle_name(location, index, item)).unlink(missing_ok=True)
145
134
 
146
135
 
147
- def read_cached_data(location: str, name: str, index: str, items: list[str] | str) -> Any:
136
+ def read_cached_data(location: str, name: str, index: str, items: list[str] | str) -> dict[str, Any]:
148
137
  """Read cached data from a file
149
138
 
150
139
  :param location: Location of the mixture database
@@ -158,13 +147,13 @@ def read_cached_data(location: str, name: str, index: str, items: list[str] | st
158
147
  return read_pickle_data(join(location, name), index, items)
159
148
 
160
149
 
161
- def write_cached_data(location: str, name: str, index: str, items: list[tuple[str, Any]] | tuple[str, Any]) -> None:
150
+ def write_cached_data(location: str, name: str, index: str, items: dict[str, Any]) -> None:
162
151
  """Write data to a file
163
152
 
164
153
  :param location: Location of the mixture database
165
154
  :param name: Data name ('mixture', 'target', or 'noise')
166
155
  :param index: Data index (mixture, target, or noise ID)
167
- :param items: Tuple(s) of (name, data)
156
+ :param items: Dictionary of name: data
168
157
  """
169
158
  from os.path import join
170
159
 
@@ -1,56 +1,92 @@
1
1
  from collections import namedtuple
2
2
 
3
- TruthConfigRecord = namedtuple("TruthConfigRecord", ["id", "name", "function", "stride_reduction", "config"])
4
-
5
- TruthParametersRecord = namedtuple("TruthParametersRecord", ["id", "name", "parameters"])
6
-
7
- TargetFileRecord = namedtuple("TargetFileRecord", ["id", "name", "samples", "class_indices", "level_type", "speaker_id"])
8
-
9
- NoiseFileRecord = namedtuple("NoiseFileRecord", ["id", "name", "samples"])
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
+ )
10
15
 
11
16
  TopRecord = namedtuple(
12
17
  "TopRecord",
13
18
  [
14
19
  "id",
15
- "version",
16
20
  "class_balancing",
17
21
  "feature",
18
- "noise_mix_mode",
22
+ "mixid_width",
19
23
  "num_classes",
20
24
  "seed",
21
- "mixid_width",
22
25
  "speaker_metadata_tiers",
23
26
  "textgrid_metadata_tiers",
27
+ "version",
24
28
  ],
25
29
  )
26
30
 
27
- ClassLabelRecord = namedtuple("ClassLabelRecord", ["id", "label"])
31
+ ClassLabelRecord = namedtuple(
32
+ "ClassLabelRecord",
33
+ [
34
+ "id",
35
+ "label",
36
+ ],
37
+ )
28
38
 
29
- ClassWeightsThresholdRecord = namedtuple("ClassWeightsThresholdRecord", ["id", "threshold"])
39
+ ClassWeightsThresholdRecord = namedtuple(
40
+ "ClassWeightsThresholdRecord",
41
+ [
42
+ "id",
43
+ "threshold",
44
+ ],
45
+ )
30
46
 
31
- ImpulseResponseFileRecord = namedtuple("ImpulseResponseFileRecord", ["id", "file"])
47
+ ImpulseResponseFileRecord = namedtuple(
48
+ "ImpulseResponseFileRecord",
49
+ [
50
+ "id",
51
+ "delay",
52
+ "name",
53
+ ],
54
+ )
32
55
 
33
56
  SpectralMaskRecord = namedtuple(
34
57
  "SpectralMaskRecord",
35
- ["id", "f_max_width", "f_num", "t_max_width", "t_num", "t_max_percent"],
58
+ [
59
+ "id",
60
+ "f_max_width",
61
+ "f_num",
62
+ "t_max_percent",
63
+ "t_max_width",
64
+ "t_num",
65
+ ],
36
66
  )
37
67
 
38
- TargetRecord = namedtuple("TargetRecord", ["id", "file_id", "augmentation"])
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
+ )
39
82
 
40
83
  MixtureRecord = namedtuple(
41
84
  "MixtureRecord",
42
85
  [
43
86
  "id",
44
87
  "name",
45
- "noise_file_id",
46
- "noise_augmentation",
47
- "noise_offset",
48
- "noise_snr_gain",
49
- "random_snr",
50
- "snr",
51
88
  "samples",
52
89
  "spectral_mask_id",
53
90
  "spectral_mask_seed",
54
- "target_snr_gain",
55
91
  ],
56
92
  )