sonusai 0.16.0__tar.gz → 0.16.1__tar.gz

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 (115) hide show
  1. {sonusai-0.16.0 → sonusai-0.16.1}/PKG-INFO +1 -1
  2. {sonusai-0.16.0 → sonusai-0.16.1}/pyproject.toml +4 -1
  3. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/__init__.py +1 -0
  4. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/audiofe.py +108 -47
  5. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/calc_metric_spenh.py +14 -7
  6. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/genft.py +15 -6
  7. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/genmix.py +14 -6
  8. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/genmixdb.py +14 -6
  9. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/gentcst.py +13 -6
  10. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/lsdb.py +15 -5
  11. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mkmanifest.py +14 -6
  12. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mkwav.py +15 -6
  13. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/onnx_predict.py +16 -6
  14. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/plot.py +16 -6
  15. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/post_spenh_targetf.py +13 -6
  16. sonusai-0.16.1/sonusai/summarize_metric_spenh.py +71 -0
  17. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/tplot.py +14 -6
  18. {sonusai-0.16.0 → sonusai-0.16.1}/README.rst +0 -0
  19. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/aawscd_probwrite.py +0 -0
  20. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/data/__init__.py +0 -0
  21. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/data/genmixdb.yml +0 -0
  22. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/data/speech_ma01_01.wav +0 -0
  23. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/data/whitenoise.wav +0 -0
  24. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/doc/__init__.py +0 -0
  25. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/doc/doc.py +0 -0
  26. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/doc.py +0 -0
  27. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/main.py +0 -0
  28. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/__init__.py +0 -0
  29. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_class_weights.py +0 -0
  30. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_optimal_thresholds.py +0 -0
  31. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_pcm.py +0 -0
  32. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_pesq.py +0 -0
  33. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_sa_sdr.py +0 -0
  34. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_sample_weights.py +0 -0
  35. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_wer.py +0 -0
  36. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/calc_wsdr.py +0 -0
  37. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/class_summary.py +0 -0
  38. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/confusion_matrix_summary.py +0 -0
  39. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/one_hot.py +0 -0
  40. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/metrics/snr_summary.py +0 -0
  41. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/__init__.py +0 -0
  42. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/audio.py +0 -0
  43. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/augmentation.py +0 -0
  44. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/class_count.py +0 -0
  45. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/config.py +0 -0
  46. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/constants.py +0 -0
  47. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/datatypes.py +0 -0
  48. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/eq_rule_is_valid.py +0 -0
  49. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/feature.py +0 -0
  50. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/generation.py +0 -0
  51. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/helpers.py +0 -0
  52. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/log_duration_and_sizes.py +0 -0
  53. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/mapped_snr_f.py +0 -0
  54. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/mixdb.py +0 -0
  55. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/soundfile_audio.py +0 -0
  56. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/sox_audio.py +0 -0
  57. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/sox_augmentation.py +0 -0
  58. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/spectral_mask.py +0 -0
  59. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/target_class_balancing.py +0 -0
  60. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/targets.py +0 -0
  61. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/tokenized_shell_vars.py +0 -0
  62. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/torchaudio_audio.py +0 -0
  63. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/torchaudio_augmentation.py +0 -0
  64. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth.py +0 -0
  65. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/__init__.py +0 -0
  66. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/crm.py +0 -0
  67. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/data.py +0 -0
  68. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/energy.py +0 -0
  69. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/file.py +0 -0
  70. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/phoneme.py +0 -0
  71. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/sed.py +0 -0
  72. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/mixture/truth_functions/target.py +0 -0
  73. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/queries/__init__.py +0 -0
  74. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/queries/queries.py +0 -0
  75. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/__init__.py +0 -0
  76. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asl_p56.py +0 -0
  77. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr.py +0 -0
  78. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr_functions/__init__.py +0 -0
  79. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr_functions/aaware_whisper.py +0 -0
  80. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr_manifest_functions/__init__.py +0 -0
  81. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr_manifest_functions/data.py +0 -0
  82. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr_manifest_functions/librispeech.py +0 -0
  83. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr_manifest_functions/mcgill_speech.py +0 -0
  84. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/asr_manifest_functions/vctk_noisy_speech.py +0 -0
  85. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/audio_devices.py +0 -0
  86. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/braced_glob.py +0 -0
  87. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/calculate_input_shape.py +0 -0
  88. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/convert_string_to_number.py +0 -0
  89. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/create_timestamp.py +0 -0
  90. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/create_ts_name.py +0 -0
  91. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/dataclass_from_dict.py +0 -0
  92. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/db.py +0 -0
  93. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/docstring.py +0 -0
  94. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/energy_f.py +0 -0
  95. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/engineering_number.py +0 -0
  96. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/get_frames_per_batch.py +0 -0
  97. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/get_label_names.py +0 -0
  98. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/grouper.py +0 -0
  99. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/human_readable_size.py +0 -0
  100. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/max_text_width.py +0 -0
  101. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/model_utils.py +0 -0
  102. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/numeric_conversion.py +0 -0
  103. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/onnx_utils.py +0 -0
  104. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/parallel.py +0 -0
  105. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/print_mixture_details.py +0 -0
  106. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/ranges.py +0 -0
  107. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/read_mixture_data.py +0 -0
  108. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/read_predict_data.py +0 -0
  109. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/reshape.py +0 -0
  110. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/seconds_to_hms.py +0 -0
  111. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/stacked_complex.py +0 -0
  112. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/stratified_shuffle_split.py +0 -0
  113. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/wave.py +0 -0
  114. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/utils/yes_or_no.py +0 -0
  115. {sonusai-0.16.0 → sonusai-0.16.1}/sonusai/vars.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sonusai
3
- Version: 0.16.0
3
+ Version: 0.16.1
4
4
  Summary: Framework for building deep neural network models for sound, speech, and voice AI
5
5
  Home-page: https://aaware.com
6
6
  License: GPL-3.0-only
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "sonusai"
3
- version = "0.16.0"
3
+ version = "0.16.1"
4
4
  description = "Framework for building deep neural network models for sound, speech, and voice AI"
5
5
  authors = ["Chris Eddington <chris@aaware.com>", "Jason Calderwood <jason@aaware.com>"]
6
6
  maintainers = ["Chris Eddington <chris@aaware.com>", "Jason Calderwood <jason@aaware.com>"]
@@ -40,10 +40,13 @@ torchaudio = "~2.2"
40
40
  tqdm = "^4.66.1"
41
41
 
42
42
  [tool.poetry.group.dev.dependencies]
43
+ einops = "^0.8.0"
43
44
  icecream = "^2.1.3"
44
45
  mypy = "^1.6.0"
45
46
  mypy-extensions = "^1.0.0"
46
47
  pytest = "^8.1.1"
48
+ sonusai-asr-cloud = "^0.1.0"
49
+ sonusai-torchl = "^0.1.0"
47
50
  types-pyyaml = "^6.0.12.12"
48
51
  types-requests = "^2.31.0.8"
49
52
 
@@ -19,6 +19,7 @@ commands_doc = """
19
19
  onnx_predict Run ONNX predict on a trained model
20
20
  plot Plot mixture data
21
21
  post_spenh_targetf Run post-processing for speech enhancement targetf data
22
+ summarize_metric_spenh Summarize speech enhancement and analysis results
22
23
  tplot Plot truth data
23
24
  vars List custom SonusAI variables
24
25
  """
@@ -24,6 +24,10 @@ audiofe_capture_<TIMESTAMP>.wav.
24
24
  If a model is specified, run prediction on audio data from this model. Then compute the inverse transform of the
25
25
  prediction result and save to audiofe_predict_<TIMESTAMP>.wav.
26
26
 
27
+ Also, if a model is specified, save plots of the capture data (time-domain signal and feature) to
28
+ audiofe_capture_<TIMESTAMP>.png and predict data (time-domain signal and feature) to
29
+ audiofe_predict_<TIMESTAMP>.png.
30
+
27
31
  If an ASR is specified, run ASR on the captured audio and print the results. In addition, if a model was also specified,
28
32
  run ASR on the predict audio and print the results.
29
33
 
@@ -31,40 +35,32 @@ If the debug option is enabled, write capture audio, feature, reconstruct audio,
31
35
  audiofe_<TIMESTAMP>.h5.
32
36
 
33
37
  """
34
- from os.path import exists
35
- from select import select
36
- from sys import stdin
38
+ import signal
37
39
 
38
- import h5py
39
40
  import numpy as np
40
- import pyaudio
41
- import torch
42
- from docopt import docopt
43
- from docopt import printable_usage
44
-
45
- import sonusai
46
- from sonusai import create_file_handler
47
- from sonusai import initial_log_messages
48
- from sonusai import logger
49
- from sonusai import update_console_handler
41
+
50
42
  from sonusai.mixture import AudioT
51
- from sonusai.mixture import CHANNEL_COUNT
52
- from sonusai.mixture import SAMPLE_RATE
53
- from sonusai.mixture import get_audio_from_feature
54
- from sonusai.mixture import get_feature_from_audio
55
- from sonusai.mixture import read_audio
56
- from sonusai.utils import calc_asr
57
- from sonusai.utils import create_timestamp
58
- from sonusai.utils import get_input_device_index_by_name
59
- from sonusai.utils import get_input_devices
60
- from sonusai.utils import load_torchl_ckpt_model
61
- from sonusai.utils import trim_docstring
62
- from sonusai.utils import write_wav
43
+
44
+
45
+ def signal_handler(_sig, _frame):
46
+ import sys
47
+
48
+ from sonusai import logger
49
+
50
+ logger.info('Canceled due to keyboard interrupt')
51
+ sys.exit(1)
52
+
53
+
54
+ signal.signal(signal.SIGINT, signal_handler)
63
55
 
64
56
 
65
57
  def main() -> None:
58
+ from docopt import docopt
59
+
60
+ import sonusai
61
+ from sonusai.utils import trim_docstring
62
+
66
63
  args = docopt(trim_docstring(__doc__), version=sonusai.__version__, options_first=True)
67
- ts = create_timestamp()
68
64
 
69
65
  verbose = args['--verbose']
70
66
  length = float(args['--length'])
@@ -76,8 +72,34 @@ def main() -> None:
76
72
  debug = args['--debug']
77
73
  show = args['--show']
78
74
 
79
- capture_name = f'audiofe_capture_{ts}.wav'
80
- predict_name = f'audiofe_predict_{ts}.wav'
75
+ from os.path import exists
76
+
77
+ import h5py
78
+ import pyaudio
79
+ import torch
80
+ from docopt import printable_usage
81
+ from sonusai_torchl.utils import load_torchl_ckpt_model
82
+
83
+ from sonusai import create_file_handler
84
+ from sonusai import initial_log_messages
85
+ from sonusai import logger
86
+ from sonusai import update_console_handler
87
+ from sonusai.mixture import SAMPLE_RATE
88
+ from sonusai.mixture import get_audio_from_feature
89
+ from sonusai.mixture import get_feature_from_audio
90
+ from sonusai.utils import calc_asr
91
+ from sonusai.utils import create_timestamp
92
+ from sonusai.utils import get_input_devices
93
+ from sonusai.utils import trim_docstring
94
+ from sonusai.utils import write_wav
95
+
96
+ ts = create_timestamp()
97
+ capture_name = f'audiofe_capture_{ts}'
98
+ capture_wav = capture_name + '.wav'
99
+ capture_png = capture_name + '.png'
100
+ predict_name = f'audiofe_predict_{ts}'
101
+ predict_wav = predict_name + '.wav'
102
+ predict_png = predict_name + '.png'
81
103
  h5_name = f'audiofe_{ts}.h5'
82
104
 
83
105
  if model_name is not None and ckpt_name is None:
@@ -108,9 +130,9 @@ def main() -> None:
108
130
  logger.exception(e)
109
131
  return
110
132
 
111
- write_wav(capture_name, capture_audio, SAMPLE_RATE)
133
+ write_wav(capture_wav, capture_audio, SAMPLE_RATE)
112
134
  logger.info('')
113
- logger.info(f'Wrote capture audio with shape {capture_audio.shape} to {capture_name}')
135
+ logger.info(f'Wrote capture audio with shape {capture_audio.shape} to {capture_wav}')
114
136
  if debug:
115
137
  with h5py.File(h5_name, 'a') as f:
116
138
  if 'capture_audio' in f:
@@ -127,6 +149,9 @@ def main() -> None:
127
149
  model.eval()
128
150
 
129
151
  feature = get_feature_from_audio(audio=capture_audio, feature_mode=model.hparams.feature)
152
+ save_figure(capture_png, capture_audio, feature)
153
+ logger.info(f'Wrote capture plots to {capture_png}')
154
+
130
155
  if debug:
131
156
  with h5py.File(h5_name, 'a') as f:
132
157
  if 'feature' in f:
@@ -134,20 +159,6 @@ def main() -> None:
134
159
  f.create_dataset('feature', data=feature)
135
160
  logger.info(f'Wrote feature with shape {feature.shape} to {h5_name}')
136
161
 
137
- # if debug:
138
- # reconstruct_name = f'audiofe_reconstruct_{ts}.wav'
139
- # reconstruct_audio = get_audio_from_feature(feature=feature, feature_mode=model.hparams.feature)
140
- # samples = min(len(capture_audio), len(reconstruct_audio))
141
- # max_err = np.max(np.abs(capture_audio[:samples] - reconstruct_audio[:samples]))
142
- # logger.info(f'Maximum error between capture and reconstruct: {max_err}')
143
- # write_wav(reconstruct_name, reconstruct_audio, SAMPLE_RATE)
144
- # logger.info(f'Wrote reconstruct audio with shape {reconstruct_audio.shape} to {reconstruct_name}')
145
- # with h5py.File(h5_name, 'a') as f:
146
- # if 'reconstruct_audio' in f:
147
- # del f['reconstruct_audio']
148
- # f.create_dataset('reconstruct_audio', data=reconstruct_audio)
149
- # logger.info(f'Wrote reconstruct audio with shape {reconstruct_audio.shape} to {h5_name}')
150
-
151
162
  with torch.no_grad():
152
163
  # model wants batch x timesteps x feature_parameters
153
164
  predict = model(torch.tensor(feature).permute((1, 0, 2))).permute(1, 0, 2).numpy()
@@ -159,8 +170,8 @@ def main() -> None:
159
170
  logger.info(f'Wrote predict with shape {predict.shape} to {h5_name}')
160
171
 
161
172
  predict_audio = get_audio_from_feature(feature=predict, feature_mode=model.hparams.feature)
162
- write_wav(predict_name, predict_audio, SAMPLE_RATE)
163
- logger.info(f'Wrote predict audio with shape {predict_audio.shape} to {predict_name}')
173
+ write_wav(predict_wav, predict_audio, SAMPLE_RATE)
174
+ logger.info(f'Wrote predict audio with shape {predict_audio.shape} to {predict_wav}')
164
175
  if debug:
165
176
  with h5py.File(h5_name, 'a') as f:
166
177
  if 'predict_audio' in f:
@@ -168,12 +179,26 @@ def main() -> None:
168
179
  f.create_dataset('predict_audio', data=predict_audio)
169
180
  logger.info(f'Wrote predict audio with shape {predict_audio.shape} to {h5_name}')
170
181
 
182
+ save_figure(predict_png, predict_audio, predict)
183
+ logger.info(f'Wrote predict plots to {predict_png}')
184
+
171
185
  if asr_name is not None:
172
186
  predict_asr = calc_asr(predict_audio, engine=asr_name, whisper_model_name=whisper_name).text
173
187
  logger.info(f'Predict audio ASR: {predict_asr}')
174
188
 
175
189
 
176
190
  def get_frames_from_device(input_name: str | None, length: float, chunk: int = 1024) -> AudioT:
191
+ from select import select
192
+ from sys import stdin
193
+
194
+ import pyaudio
195
+
196
+ from sonusai import logger
197
+ from sonusai.mixture import CHANNEL_COUNT
198
+ from sonusai.mixture import SAMPLE_RATE
199
+ from sonusai.utils import get_input_device_index_by_name
200
+ from sonusai.utils import get_input_devices
201
+
177
202
  p = pyaudio.PyAudio()
178
203
 
179
204
  input_devices = get_input_devices(p)
@@ -224,6 +249,10 @@ def get_frames_from_device(input_name: str | None, length: float, chunk: int = 1
224
249
 
225
250
 
226
251
  def get_frames_from_file(input_name: str, length: float) -> AudioT:
252
+ from sonusai import logger
253
+ from sonusai.mixture import SAMPLE_RATE
254
+ from sonusai.mixture import read_audio
255
+
227
256
  logger.info(f'Capturing from {input_name}')
228
257
  frames = read_audio(input_name)
229
258
  if length != -1:
@@ -233,5 +262,37 @@ def get_frames_from_file(input_name: str, length: float) -> AudioT:
233
262
  return frames
234
263
 
235
264
 
265
+ def save_figure(name: str, audio: np.ndarray, feature: np.ndarray) -> None:
266
+ import matplotlib.pyplot as plt
267
+ from scipy.interpolate import CubicSpline
268
+
269
+ from sonusai.mixture import SAMPLE_RATE
270
+ from sonusai.utils import unstack_complex
271
+
272
+ spectrum = 20 * np.log(np.abs(np.squeeze(unstack_complex(feature)).transpose()))
273
+ frames = spectrum.shape[1]
274
+ samples = (len(audio) // frames) * frames
275
+ length_in_s = samples / SAMPLE_RATE
276
+ interp = samples // frames
277
+
278
+ ts = np.arange(0.0, length_in_s, interp / SAMPLE_RATE)
279
+ t = np.arange(0.0, length_in_s, 1 / SAMPLE_RATE)
280
+
281
+ spectrum = CubicSpline(ts, spectrum, axis=-1)(t)
282
+
283
+ fig, (ax1, ax2) = plt.subplots(nrows=2)
284
+ ax1.set_title(name)
285
+ ax1.plot(t, audio[:samples])
286
+ ax1.set_ylabel('Signal')
287
+ ax1.set_xlim(0, length_in_s)
288
+ ax1.set_ylim(-1, 1)
289
+
290
+ ax2.imshow(spectrum, origin='lower', aspect='auto')
291
+ ax2.set_xticks([])
292
+ ax2.set_ylabel('Feature')
293
+
294
+ plt.savefig(name, dpi=300)
295
+
296
+
236
297
  if __name__ == '__main__':
237
298
  main()
@@ -60,6 +60,7 @@ Metric and extraction data are written into prediction location PLOC as separate
60
60
  Inputs:
61
61
 
62
62
  """
63
+ import signal
63
64
  from dataclasses import dataclass
64
65
  from typing import Optional
65
66
 
@@ -67,14 +68,24 @@ import matplotlib
67
68
  import matplotlib.pyplot as plt
68
69
  import numpy as np
69
70
  import pandas as pd
70
-
71
- from sonusai import logger
72
71
  from sonusai.mixture import AudioF
73
72
  from sonusai.mixture import AudioT
74
73
  from sonusai.mixture import Feature
75
74
  from sonusai.mixture import MixtureDatabase
76
75
  from sonusai.mixture import Predict
77
76
 
77
+
78
+ def signal_handler(_sig, _frame):
79
+ import sys
80
+
81
+ from sonusai import logger
82
+
83
+ logger.info('Canceled due to keyboard interrupt')
84
+ sys.exit(1)
85
+
86
+
87
+ signal.signal(signal.SIGINT, signal_handler)
88
+
78
89
  matplotlib.use('SVG')
79
90
 
80
91
 
@@ -1326,8 +1337,4 @@ def main():
1326
1337
 
1327
1338
 
1328
1339
  if __name__ == '__main__':
1329
- try:
1330
- main()
1331
- except KeyboardInterrupt:
1332
- logger.info('Canceled due to keyboard interrupt')
1333
- exit()
1340
+ main()
@@ -23,14 +23,26 @@ Outputs the following to the mixture database directory:
23
23
  genft.log
24
24
 
25
25
  """
26
+ import signal
26
27
  from dataclasses import dataclass
27
28
 
28
- from sonusai import logger
29
29
  from sonusai.mixture import GenFTData
30
30
  from sonusai.mixture import GeneralizedIDs
31
31
  from sonusai.mixture import MixtureDatabase
32
32
 
33
33
 
34
+ def signal_handler(_sig, _frame):
35
+ import sys
36
+
37
+ from sonusai import logger
38
+
39
+ logger.info('Canceled due to keyboard interrupt')
40
+ sys.exit(1)
41
+
42
+
43
+ signal.signal(signal.SIGINT, signal_handler)
44
+
45
+
34
46
  @dataclass
35
47
  class MPGlobal:
36
48
  mixdb: MixtureDatabase = None
@@ -123,6 +135,7 @@ def main() -> None:
123
135
 
124
136
  from sonusai import create_file_handler
125
137
  from sonusai import initial_log_messages
138
+ from sonusai import logger
126
139
  from sonusai import update_console_handler
127
140
  from sonusai.mixture import check_audio_files_exist
128
141
  from sonusai.utils import human_readable_size
@@ -177,8 +190,4 @@ def main() -> None:
177
190
 
178
191
 
179
192
  if __name__ == '__main__':
180
- try:
181
- main()
182
- except KeyboardInterrupt:
183
- logger.info('Canceled due to keyboard interrupt')
184
- raise SystemExit(0)
193
+ main()
@@ -27,14 +27,26 @@ Outputs the following to the mixture database directory:
27
27
  <id>.txt
28
28
  genmix.log
29
29
  """
30
+ import signal
30
31
  from dataclasses import dataclass
31
32
 
32
- from sonusai import logger
33
33
  from sonusai.mixture import GenMixData
34
34
  from sonusai.mixture import GeneralizedIDs
35
35
  from sonusai.mixture import MixtureDatabase
36
36
 
37
37
 
38
+ def signal_handler(_sig, _frame):
39
+ import sys
40
+
41
+ from sonusai import logger
42
+
43
+ logger.info('Canceled due to keyboard interrupt')
44
+ sys.exit(1)
45
+
46
+
47
+ signal.signal(signal.SIGINT, signal_handler)
48
+
49
+
38
50
  @dataclass
39
51
  class MPGlobal:
40
52
  mixdb: MixtureDatabase = None
@@ -210,8 +222,4 @@ def main() -> None:
210
222
 
211
223
 
212
224
  if __name__ == '__main__':
213
- try:
214
- main()
215
- except KeyboardInterrupt:
216
- logger.info('Canceled due to keyboard interrupt')
217
- raise SystemExit(0)
225
+ main()
@@ -112,13 +112,25 @@ targets:
112
112
  will find all .wav files in the specified directories and process them as targets.
113
113
 
114
114
  """
115
+ import signal
115
116
  from dataclasses import dataclass
116
117
 
117
- from sonusai import logger
118
118
  from sonusai.mixture import Mixture
119
119
  from sonusai.mixture import MixtureDatabase
120
120
 
121
121
 
122
+ def signal_handler(_sig, _frame):
123
+ import sys
124
+
125
+ from sonusai import logger
126
+
127
+ logger.info('Canceled due to keyboard interrupt')
128
+ sys.exit(1)
129
+
130
+
131
+ signal.signal(signal.SIGINT, signal_handler)
132
+
133
+
122
134
  @dataclass
123
135
  class MPGlobal:
124
136
  mixdb: MixtureDatabase = None
@@ -509,8 +521,4 @@ def main() -> None:
509
521
 
510
522
 
511
523
  if __name__ == '__main__':
512
- try:
513
- main()
514
- except KeyboardInterrupt:
515
- logger.info('Canceled due to keyboard interrupt')
516
- raise SystemExit(0)
524
+ main()
@@ -44,10 +44,21 @@ Outputs:
44
44
  gentcst.log
45
45
 
46
46
  """
47
+ import signal
47
48
  from dataclasses import dataclass
48
49
  from typing import Optional
49
50
 
50
- from sonusai import logger
51
+
52
+ def signal_handler(_sig, _frame):
53
+ import sys
54
+
55
+ from sonusai import logger
56
+
57
+ logger.info('Canceled due to keyboard interrupt')
58
+ sys.exit(1)
59
+
60
+
61
+ signal.signal(signal.SIGINT, signal_handler)
51
62
 
52
63
  CONFIG_FILE = 'config.yml'
53
64
 
@@ -621,8 +632,4 @@ def main() -> None:
621
632
 
622
633
 
623
634
  if __name__ == '__main__':
624
- try:
625
- main()
626
- except KeyboardInterrupt:
627
- logger.info('Canceled due to keyboard interrupt')
628
- raise SystemExit(0)
635
+ main()
@@ -15,11 +15,25 @@ Inputs:
15
15
  LOC A SonusAI mixture database directory.
16
16
 
17
17
  """
18
+ import signal
19
+
18
20
  from sonusai import logger
19
21
  from sonusai.mixture import GeneralizedIDs
20
22
  from sonusai.mixture import MixtureDatabase
21
23
 
22
24
 
25
+ def signal_handler(_sig, _frame):
26
+ import sys
27
+
28
+ from sonusai import logger
29
+
30
+ logger.info('Canceled due to keyboard interrupt')
31
+ sys.exit(1)
32
+
33
+
34
+ signal.signal(signal.SIGINT, signal_handler)
35
+
36
+
23
37
  def lsdb(mixdb: MixtureDatabase,
24
38
  mixids: GeneralizedIDs = None,
25
39
  truth_index: int = None,
@@ -142,8 +156,4 @@ def main() -> None:
142
156
 
143
157
 
144
158
  if __name__ == '__main__':
145
- try:
146
- main()
147
- except KeyboardInterrupt:
148
- logger.info('Canceled due to keyboard interrupt')
149
- raise SystemExit(0)
159
+ main()
@@ -46,7 +46,19 @@ Example usage for LibriSpeech:
46
46
  sonusai mkmanifest -mlibrispeech -eADAT -oasr_manifest.json --include='*.flac' train-clean-100
47
47
  sonusai mkmanifest -m mcgill-speech -e ADAT -o asr_manifest_16k.json 16k-LP7/
48
48
  """
49
- from sonusai import logger
49
+ import signal
50
+
51
+
52
+ def signal_handler(_sig, _frame):
53
+ import sys
54
+
55
+ from sonusai import logger
56
+
57
+ logger.info('Canceled due to keyboard interrupt')
58
+ sys.exit(1)
59
+
60
+
61
+ signal.signal(signal.SIGINT, signal_handler)
50
62
 
51
63
  VALID_METHOD = ['librispeech', 'vctk_noisy_speech', 'mcgill-speech']
52
64
 
@@ -194,8 +206,4 @@ def main() -> None:
194
206
 
195
207
 
196
208
  if __name__ == '__main__':
197
- try:
198
- main()
199
- except KeyboardInterrupt:
200
- logger.info('Canceled due to keyboard interrupt')
201
- raise SystemExit(0)
209
+ main()
@@ -23,13 +23,25 @@ Outputs the following to the mixture database directory:
23
23
  mkwav.log
24
24
 
25
25
  """
26
+ import signal
26
27
  from dataclasses import dataclass
27
28
 
28
- from sonusai import logger
29
29
  from sonusai.mixture import AudioT
30
30
  from sonusai.mixture import MixtureDatabase
31
31
 
32
32
 
33
+ def signal_handler(_sig, _frame):
34
+ import sys
35
+
36
+ from sonusai import logger
37
+
38
+ logger.info('Canceled due to keyboard interrupt')
39
+ sys.exit(1)
40
+
41
+
42
+ signal.signal(signal.SIGINT, signal_handler)
43
+
44
+
33
45
  @dataclass
34
46
  class MPGlobal:
35
47
  mixdb: MixtureDatabase = None
@@ -120,6 +132,7 @@ def main() -> None:
120
132
  import sonusai
121
133
  from sonusai import create_file_handler
122
134
  from sonusai import initial_log_messages
135
+ from sonusai import logger
123
136
  from sonusai import update_console_handler
124
137
  from sonusai.mixture import check_audio_files_exist
125
138
  from sonusai.utils import pp_tqdm_imap
@@ -164,8 +177,4 @@ def main() -> None:
164
177
 
165
178
 
166
179
  if __name__ == '__main__':
167
- try:
168
- main()
169
- except KeyboardInterrupt:
170
- logger.info('Canceled due to keyboard interrupt')
171
- raise SystemExit(0)
180
+ main()
@@ -29,12 +29,25 @@ Outputs the following to opredict-<TIMESTAMP> directory:
29
29
 
30
30
  """
31
31
 
32
- from sonusai import logger
32
+ import signal
33
+
33
34
  from sonusai.mixture import Feature
34
35
  from sonusai.mixture import Predict
35
36
  from sonusai.utils import SonusAIMetaData
36
37
 
37
38
 
39
+ def signal_handler(_sig, _frame):
40
+ import sys
41
+
42
+ from sonusai import logger
43
+
44
+ logger.info('Canceled due to keyboard interrupt')
45
+ sys.exit(1)
46
+
47
+
48
+ signal.signal(signal.SIGINT, signal_handler)
49
+
50
+
38
51
  def main() -> None:
39
52
  from docopt import docopt
40
53
 
@@ -60,6 +73,7 @@ def main() -> None:
60
73
 
61
74
  from sonusai import create_file_handler
62
75
  from sonusai import initial_log_messages
76
+ from sonusai import logger
63
77
  from sonusai import update_console_handler
64
78
  from sonusai.mixture import MixtureDatabase
65
79
  from sonusai.mixture import get_feature_from_audio
@@ -233,8 +247,4 @@ def pad_and_predict(feature: Feature,
233
247
 
234
248
 
235
249
  if __name__ == '__main__':
236
- try:
237
- main()
238
- except KeyboardInterrupt:
239
- logger.info('Canceled due to keyboard interrupt')
240
- raise SystemExit(0)
250
+ main()
@@ -41,16 +41,29 @@ Outputs:
41
41
 
42
42
  """
43
43
 
44
+ import signal
45
+
44
46
  import numpy as np
45
47
  from matplotlib import pyplot as plt
46
48
 
47
- from sonusai import logger
48
49
  from sonusai.mixture import AudioT
49
50
  from sonusai.mixture import Feature
50
51
  from sonusai.mixture import Predict
51
52
  from sonusai.mixture import Truth
52
53
 
53
54
 
55
+ def signal_handler(_sig, _frame):
56
+ import sys
57
+
58
+ from sonusai import logger
59
+
60
+ logger.info('Canceled due to keyboard interrupt')
61
+ sys.exit(1)
62
+
63
+
64
+ signal.signal(signal.SIGINT, signal_handler)
65
+
66
+
54
67
  def spec_plot(mixture: AudioT,
55
68
  feature: Feature,
56
69
  predict: Predict = None,
@@ -264,6 +277,7 @@ def main() -> None:
264
277
  from sonusai import SonusAIError
265
278
  from sonusai import create_file_handler
266
279
  from sonusai import initial_log_messages
280
+ from sonusai import logger
267
281
  from sonusai import update_console_handler
268
282
  from sonusai.mixture import MixtureDatabase
269
283
  from sonusai.mixture import FeatureGeneratorConfig
@@ -457,8 +471,4 @@ def main() -> None:
457
471
 
458
472
 
459
473
  if __name__ == '__main__':
460
- try:
461
- main()
462
- except KeyboardInterrupt:
463
- logger.info('Canceled due to keyboard interrupt')
464
- raise SystemExit(0)
474
+ main()
@@ -20,9 +20,20 @@ Outputs the following to post_spenh_targetf-<TIMESTAMP> directory:
20
20
  post_spenh_targetf.log
21
21
 
22
22
  """
23
+ import signal
23
24
  from dataclasses import dataclass
24
25
 
25
- from sonusai import logger
26
+
27
+ def signal_handler(_sig, _frame):
28
+ import sys
29
+
30
+ from sonusai import logger
31
+
32
+ logger.info('Canceled due to keyboard interrupt')
33
+ sys.exit(1)
34
+
35
+
36
+ signal.signal(signal.SIGINT, signal_handler)
26
37
 
27
38
 
28
39
  @dataclass
@@ -146,8 +157,4 @@ def _process(file: str) -> None:
146
157
 
147
158
 
148
159
  if __name__ == '__main__':
149
- try:
150
- main()
151
- except KeyboardInterrupt:
152
- logger.info('Canceled due to keyboard interrupt')
153
- exit()
160
+ main()
@@ -0,0 +1,71 @@
1
+ """sonusai summarize_metric_spenh
2
+
3
+ usage: summarize_metric_spenh [-hr] [-s SORT] LOC
4
+
5
+ options:
6
+ -h, --help
7
+ -s SORT, --sort SORT Sort by SORT column. [default: MIXID]
8
+ -r, --reverse Reverse sort order.
9
+
10
+ Summarize speech enhancement metrics results using data generated by SonusAI calc_metric_spenh.
11
+
12
+ Inputs:
13
+ LOC A SonusAI calc_metric_spenh results directory.
14
+
15
+ """
16
+ import signal
17
+
18
+
19
+ def signal_handler(_sig, _frame):
20
+ import sys
21
+
22
+ from sonusai import logger
23
+
24
+ logger.info('Canceled due to keyboard interrupt')
25
+ sys.exit(1)
26
+
27
+
28
+ signal.signal(signal.SIGINT, signal_handler)
29
+
30
+
31
+ def summarize_metric_spenh(location: str, by: str = 'MIXID', reverse: bool = False) -> str:
32
+ import glob
33
+
34
+ import pandas as pd
35
+
36
+ files = sorted(glob.glob(location + '/*_metric_spenh.txt'))
37
+ need_header = True
38
+ header = ['MIXID']
39
+ data = []
40
+ for file in files:
41
+ with open(file, 'r') as f:
42
+ for i, line in enumerate(f):
43
+ if i == 1 and need_header:
44
+ need_header = False
45
+ header.extend(line.strip().split())
46
+ elif i == 2:
47
+ data.append(line.strip().split())
48
+ break
49
+
50
+ df = pd.DataFrame(data, columns=header)
51
+ df[header[0:-2]] = df[header[0:-2]].apply(pd.to_numeric, errors='coerce')
52
+ return df.sort_values(by=by, ascending=not reverse).to_string(index=False)
53
+
54
+
55
+ def main():
56
+ from docopt import docopt
57
+
58
+ import sonusai
59
+ from sonusai.utils import trim_docstring
60
+
61
+ args = docopt(trim_docstring(__doc__), version=sonusai.__version__, options_first=True)
62
+
63
+ by = args['--sort']
64
+ reverse = args['--reverse']
65
+ location = args['LOC']
66
+
67
+ print(summarize_metric_spenh(location, by, reverse))
68
+
69
+
70
+ if __name__ == '__main__':
71
+ main()
@@ -41,7 +41,19 @@ options:
41
41
  A multi-page plot TARGET-tplot.pdf or CONFIG-tplot.pdf is generated.
42
42
 
43
43
  """
44
- from sonusai import logger
44
+ import signal
45
+
46
+
47
+ def signal_handler(_sig, _frame):
48
+ import sys
49
+
50
+ from sonusai import logger
51
+
52
+ logger.info('Canceled due to keyboard interrupt')
53
+ sys.exit(1)
54
+
55
+
56
+ signal.signal(signal.SIGINT, signal_handler)
45
57
 
46
58
 
47
59
  # TODO: re-work for modern mixdb API
@@ -328,8 +340,4 @@ def main() -> None:
328
340
 
329
341
 
330
342
  if __name__ == '__main__':
331
- try:
332
- main()
333
- except KeyboardInterrupt:
334
- logger.info('Canceled due to keyboard interrupt')
335
- raise SystemExit(0)
343
+ main()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes