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
sonusai/__init__.py ADDED
@@ -0,0 +1,170 @@
1
+ import atexit
2
+ import logging
3
+ from os.path import dirname
4
+
5
+ from rich.logging import RichHandler
6
+
7
+ from sonusai.rs import __version__ as rs_version
8
+
9
+ __version__ = rs_version
10
+
11
+ BASEDIR = dirname(__file__)
12
+
13
+ commands_doc = """
14
+ audiofe Audio front end
15
+ calc_metric_spenh Run speech enhancement and analysis
16
+ doc Documentation
17
+ genft Generate feature and truth data
18
+ genmetrics Generate mixture metrics data
19
+ genmix Generate mixture and truth data
20
+ genmixdb Generate a mixture database
21
+ lsdb List information about a mixture database
22
+ metrics_summary Summarize generated metrics in a mixture database
23
+ mkwav Make WAV files from a mixture database
24
+ onnx_predict Run ONNX predict on a trained model
25
+ vars List custom SonusAI variables
26
+ """
27
+
28
+ # Global handler registry to prevent duplicates
29
+ _file_handlers = []
30
+
31
+
32
+ def _cleanup_handlers():
33
+ """Clean up file handlers on exit"""
34
+ for handler in _file_handlers:
35
+ handler.close()
36
+
37
+
38
+ atexit.register(_cleanup_handlers)
39
+
40
+
41
+ def setup_logger(name: str = "sonusai") -> logging.Logger:
42
+ """Setup and return configured logger"""
43
+ _logger = logging.getLogger(name)
44
+
45
+ # Avoid duplicate configuration
46
+ if _logger.handlers:
47
+ return _logger
48
+
49
+ _logger.setLevel(logging.DEBUG)
50
+
51
+ # Setup console handler
52
+ formatter = logging.Formatter("%(message)s")
53
+
54
+ console_handler = RichHandler(show_level=False, show_path=False, show_time=False)
55
+
56
+ console_handler.setLevel(logging.DEBUG)
57
+ console_handler.setFormatter(formatter)
58
+ _logger.addHandler(console_handler)
59
+
60
+ return _logger
61
+
62
+
63
+ # Initialize loggers
64
+ logger = setup_logger("sonusai")
65
+ logger_db = setup_logger("sonusai_db")
66
+
67
+
68
+ def create_file_handler(filename: str, verbose: bool = False) -> None:
69
+ """Create a file handler with error handling"""
70
+ from pathlib import Path
71
+
72
+ try:
73
+ # Ensure directory exists
74
+ Path(filename).parent.mkdir(parents=True, exist_ok=True)
75
+
76
+ formatter = logging.Formatter("%(message)s")
77
+ formatter_db = logging.Formatter("%(asctime)s %(message)s")
78
+
79
+ fh = logging.FileHandler(filename=filename, mode="w")
80
+ fh.setLevel(logging.DEBUG)
81
+ fh.setFormatter(formatter)
82
+ logger.addHandler(fh)
83
+ _file_handlers.append(fh)
84
+
85
+ if verbose:
86
+ filename_db = Path(filename)
87
+ filename_db = filename_db.parent / (filename_db.stem + "_dbtrace" + filename_db.suffix)
88
+ fh_db = logging.FileHandler(filename=filename_db, mode="w")
89
+ fh_db.setLevel(logging.DEBUG)
90
+ fh_db.setFormatter(formatter_db)
91
+ logger_db.addHandler(fh_db)
92
+ _file_handlers.append(fh_db)
93
+
94
+ except (PermissionError, OSError) as e:
95
+ logger.warning(f"Could not create log file {filename}: {e}")
96
+
97
+
98
+ def update_console_handler(verbose: bool) -> None:
99
+ """Update console handler verbosity"""
100
+ console_handlers = [h for h in logger.handlers if isinstance(h, logging.StreamHandler | RichHandler)]
101
+
102
+ if not console_handlers:
103
+ return
104
+
105
+ handler = console_handlers[0]
106
+ if not verbose:
107
+ handler.setLevel(logging.INFO)
108
+ else:
109
+ handler.setLevel(logging.DEBUG)
110
+
111
+
112
+ def initial_log_messages(name: str, subprocess: str | None = None) -> None:
113
+ """Write initial log messages with error handling"""
114
+ from datetime import datetime
115
+ from getpass import getuser
116
+ from os import getcwd
117
+ from socket import gethostname
118
+ from sys import argv
119
+
120
+ try:
121
+ if subprocess is None:
122
+ logger.info(f"SonusAI {__version__}")
123
+ else:
124
+ logger.info(f"SonusAI {subprocess}")
125
+ logger.info(f"{name}")
126
+ logger.info("")
127
+ logger.debug(f"Host: {gethostname()}")
128
+ logger.debug(f"User: {getuser()}")
129
+ logger.debug(f"Directory: {getcwd()}")
130
+ logger.debug(f"Date: {datetime.now()}")
131
+ logger.debug(f"Command: {' '.join(argv)}")
132
+ logger.debug("")
133
+ except Exception as e:
134
+ logger.warning(f"Could not write initial log messages: {e}")
135
+
136
+
137
+ def commands_list(doc: str = commands_doc) -> list[str]:
138
+ """Parse commands from a documentation string"""
139
+ commands = []
140
+ for line in doc.strip().split("\n"):
141
+ line = line.strip()
142
+ if line:
143
+ # Get the first word that's not empty
144
+ parts = line.split()
145
+ if parts:
146
+ commands.append(parts[0])
147
+ return commands
148
+
149
+
150
+ def exception_handler(e: Exception) -> None:
151
+ """Handle exceptions with proper logging"""
152
+ import sys
153
+
154
+ logger.error(f"{type(e).__name__}: {e}")
155
+
156
+ # Find file handlers for detailed logs
157
+ file_handlers = [handler for handler in logger.handlers if isinstance(handler, logging.FileHandler)]
158
+
159
+ if file_handlers:
160
+ filenames = [handler.baseFilename for handler in file_handlers]
161
+ logger.error(f"See {', '.join(filenames)} for details")
162
+
163
+ from rich.console import Console
164
+
165
+ console = Console(color_system=None)
166
+ with console.capture() as capture:
167
+ console.print_exception(show_locals=False)
168
+ logger.debug(capture.get())
169
+
170
+ sys.exit(1)
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env python3
2
+ """aawscd_probwrite
3
+
4
+ usage: aawscd_probwrite [-h] [-m MACHINE] [-f FRAMES] FILE
5
+
6
+ options:
7
+ -h, --help
8
+ -m MACHINE, --machine MACHINE IP address of aawscd platform. [default: localhost].
9
+ -f FRAMES, --frames FRAMES Number of frames to capture. [default: 10].
10
+
11
+ aawscd_probwrite connects to an Aaware platform running aawscd and writes the sound classification
12
+ probability output to an HDF5 file.
13
+
14
+ """
15
+
16
+ from threading import Condition
17
+
18
+ import numpy as np
19
+
20
+ from sonusai.utils.parallel import track
21
+
22
+ CLIENT: str = "aawscd_probwrite"
23
+ TOPIC: str = "aawscd/sc/prob"
24
+ DONE: Condition = Condition()
25
+ FRAMES: int = 10
26
+ FRAME_COUNT: int = 0
27
+ DATA: np.ndarray | None = None
28
+ PROGRESS: track | None = None
29
+
30
+
31
+ def shutdown(_signum, _frame) -> None:
32
+ global DONE
33
+ with DONE:
34
+ DONE.notify()
35
+
36
+
37
+ def unpack_prob_entry(entry: int) -> tuple[int, int, int]:
38
+ """Decode the packed probability data: [ 16-bit label | 8-bit zone | 8-bit probability ]."""
39
+ data = np.array(entry, dtype=np.uint32)
40
+ label = np.right_shift(data, 16)
41
+ zone = np.bitwise_and(np.right_shift(data, 8), 0xFF)
42
+ value = np.bitwise_and(entry, 0xFF)
43
+ return int(zone), int(label), int(value)
44
+
45
+
46
+ def parse_prob(payload: list) -> np.ndarray:
47
+ """Parse MQTT probability payload from aawscd.
48
+
49
+ The 'aawscd/sc/prob' payload is a list of uint32. Each item contains packed data and is
50
+ unpacked/decoded and inserted into an array.
51
+ """
52
+
53
+ # First pass: get the zones and labels to determine the size of the array
54
+ zones = set()
55
+ labels = set()
56
+ for entry in payload:
57
+ zone, label, _ = unpack_prob_entry(entry)
58
+ zones.add(zone)
59
+ labels.add(label)
60
+
61
+ # Create the array
62
+ prob = np.zeros((len(list(labels)), len(list(zones))), dtype=np.uint8)
63
+
64
+ # Second pass: fill in the array probability values.
65
+ for entry in payload:
66
+ zone, label, value = unpack_prob_entry(entry)
67
+ prob[label, zone] = value
68
+
69
+ # Return the array
70
+ return prob
71
+
72
+
73
+ def on_message(_client, _userdata, message):
74
+ import paho.mqtt.client as mqtt
75
+ import yaml
76
+
77
+ global TOPIC
78
+ if mqtt.topic_matches_sub(TOPIC, message.topic):
79
+ payload = yaml.safe_load(str(message.payload.decode("utf-8")))
80
+ prob = parse_prob(payload["prob"])
81
+
82
+ global DATA
83
+ global FRAMES
84
+ if DATA is None:
85
+ DATA = np.zeros((FRAMES, prob.shape[0], prob.shape[1]), dtype=prob.dtype)
86
+
87
+ global FRAME_COUNT
88
+ DATA[FRAME_COUNT] = prob
89
+ FRAME_COUNT += 1
90
+
91
+ global PROGRESS
92
+ PROGRESS.update() # pyright: ignore [reportOptionalMemberAccess]
93
+
94
+ if FRAME_COUNT == FRAMES:
95
+ global DONE
96
+ with DONE:
97
+ DONE.notify()
98
+
99
+
100
+ def main() -> None:
101
+ from docopt import docopt
102
+
103
+ args = docopt(__doc__, version="1.0.0", options_first=True)
104
+
105
+ import signal
106
+
107
+ import h5py
108
+ import paho.mqtt.client as mqtt
109
+
110
+ machine = args["--machine"]
111
+
112
+ global FRAMES
113
+ FRAMES = int(args["--frames"])
114
+
115
+ file = args["FILE"]
116
+
117
+ signal.signal(signal.SIGINT, shutdown)
118
+ signal.signal(signal.SIGTERM, shutdown)
119
+
120
+ global CLIENT
121
+ client = mqtt.Client(client_id=CLIENT)
122
+ client.on_message = on_message
123
+ client.connect(host=machine)
124
+ client.loop_start()
125
+ global TOPIC
126
+ client.subscribe(topic=TOPIC)
127
+
128
+ global PROGRESS
129
+ PROGRESS = track(total=FRAMES, desc=file)
130
+
131
+ with DONE:
132
+ DONE.wait()
133
+
134
+ PROGRESS.close()
135
+
136
+ client.unsubscribe(topic=TOPIC)
137
+ client.loop_stop()
138
+ client.disconnect()
139
+
140
+ global DATA
141
+ with h5py.File(file, "w") as f:
142
+ f.create_dataset(name="prob", data=DATA)
143
+
144
+ print(f"Wrote {file}")
145
+
146
+
147
+ if __name__ == "__main__":
148
+ main()