phonoscape 0.1.0__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 (42) hide show
  1. phonoscape/__init__.py +74 -0
  2. phonoscape/__main__.py +157 -0
  3. phonoscape/data/parse.py +500 -0
  4. phonoscape/data/process.py +324 -0
  5. phonoscape/data/spectra.py +390 -0
  6. phonoscape/lproc/lp_default.py +5 -0
  7. phonoscape/lproc/lp_export_vals.py +5 -0
  8. phonoscape/lproc/lp_extents.py +5 -0
  9. phonoscape/lproc/lp_find_gest.py +526 -0
  10. phonoscape/lproc/lp_peaks.py +5 -0
  11. phonoscape/lproc/lp_phase_ang.py +5 -0
  12. phonoscape/lproc/lp_snap_ex.py +5 -0
  13. phonoscape/lproc/protocol.py +204 -0
  14. phonoscape/menu/data_menu.py +103 -0
  15. phonoscape/menu/file_menu.py +266 -0
  16. phonoscape/menu/label_menu.py +235 -0
  17. phonoscape/menu/menu_bar.py +34 -0
  18. phonoscape/menu/movement_menu.py +190 -0
  19. phonoscape/menu/play_menu.py +44 -0
  20. phonoscape/menu/selection_menu.py +63 -0
  21. phonoscape/menu/view_menu.py +187 -0
  22. phonoscape/modals/common_scaling_modal.py +155 -0
  23. phonoscape/modals/edit_labels_modal.py +137 -0
  24. phonoscape/modals/label_modal.py +143 -0
  25. phonoscape/modals/movement_config_modal.py +87 -0
  26. phonoscape/modals/spatial_view_modal.py +109 -0
  27. phonoscape/modals/spectral_analysis_modal.py +285 -0
  28. phonoscape/modals/temporal_config_modal.py +600 -0
  29. phonoscape/state.py +201 -0
  30. phonoscape/views/cursor_spect_view.py +153 -0
  31. phonoscape/views/spatial_view_2d.py +224 -0
  32. phonoscape/views/spatial_view_3d.py +276 -0
  33. phonoscape/views/temporal_view.py +577 -0
  34. phonoscape/views/zoomed_audio_view.py +118 -0
  35. phonoscape/widgets/play_button.py +79 -0
  36. phonoscape/widgets/readout.py +58 -0
  37. phonoscape/window.py +305 -0
  38. phonoscape-0.1.0.dist-info/METADATA +15 -0
  39. phonoscape-0.1.0.dist-info/RECORD +42 -0
  40. phonoscape-0.1.0.dist-info/WHEEL +5 -0
  41. phonoscape-0.1.0.dist-info/licenses/LICENSE +21 -0
  42. phonoscape-0.1.0.dist-info/top_level.txt +1 -0
phonoscape/__init__.py ADDED
@@ -0,0 +1,74 @@
1
+ import sys
2
+ from pathlib import Path
3
+ from typing import Unpack
4
+ from PySide6.QtWidgets import QApplication
5
+ import matplotlib.pyplot as plt
6
+
7
+ from .data.parse import load_variables, normalize_args, import_proc_ctor, CmdArgs
8
+ from .window import VarWindow, WindowManager
9
+ from .lproc.protocol import LabelProcedure
10
+
11
+
12
+ def phonoscape(file: str, variables: str = "*", **kwargs: Unpack[CmdArgs]) -> None:
13
+ plt.style.use("dark_background")
14
+
15
+ path = Path(file)
16
+ data, other_data, dimensions = load_variables(
17
+ path, variables, comps=kwargs.get("comps")
18
+ )
19
+
20
+ if not data:
21
+ raise ValueError(f"No matching variables found for pattern {variables!r}")
22
+
23
+ app_config, temporal_disp_specs, colors = normalize_args(
24
+ path, kwargs, data, other_data, dimensions
25
+ )
26
+
27
+ selected_variable = next(iter(data.keys()))
28
+
29
+ head_s = (kwargs.get("head") or 0) / 1000
30
+ tail_s = (kwargs.get("tail") or data[selected_variable].duration_s * 1000) / 1000
31
+ tail_s = min(tail_s, data[selected_variable].duration_s)
32
+ if head_s < 0:
33
+ raise ValueError(
34
+ f"--head must be a non-negative number of milliseconds, but got {head_s * 1000}"
35
+ )
36
+ if tail_s < 0:
37
+ raise ValueError(
38
+ f"--tail must be a non-negative number of milliseconds, but got {tail_s * 1000}"
39
+ )
40
+ if head_s >= tail_s:
41
+ raise ValueError(
42
+ f"--head must be less than --tail, but got head={head_s * 1000} and tail={tail_s * 1000}"
43
+ )
44
+ elif tail_s - head_s < 0.025:
45
+ raise ValueError(
46
+ f"The duration of the selection (tail - head) must be at least 25 milliseconds, but got head={head_s * 1000} and tail={tail_s * 1000} ({(tail_s - head_s) * 1000:.1f} ms)"
47
+ )
48
+
49
+ lproc_ctor_path = kwargs.get("lproc") or "phonoscape.lproc.lp_default"
50
+ lproc_ctor: type[LabelProcedure] = import_proc_ctor(lproc_ctor_path, "lp")
51
+
52
+ app = QApplication.instance()
53
+ owns_app = app is None
54
+
55
+ if app is None:
56
+ app = QApplication(sys.argv)
57
+
58
+ window_manager = WindowManager(lproc_ctor=lproc_ctor)
59
+ window = VarWindow(
60
+ window_manager=window_manager,
61
+ selected_variable=selected_variable,
62
+ temporal_disp_specs=temporal_disp_specs,
63
+ lproc_ctor=lproc_ctor,
64
+ colors=colors,
65
+ app_config=app_config,
66
+ view=kwargs.get("view") or (0, -90, 0),
67
+ head_s=head_s,
68
+ tail_s=tail_s,
69
+ custom={},
70
+ )
71
+ window.show()
72
+
73
+ if owns_app:
74
+ sys.exit(app.exec())
phonoscape/__main__.py ADDED
@@ -0,0 +1,157 @@
1
+ from typing import cast
2
+ from . import phonoscape
3
+
4
+ if __name__ == "__main__":
5
+ import argparse
6
+
7
+ # [ ] CONFIG
8
+ # [ ] DPROC
9
+ # [x] FTRAJ
10
+ # [x] HEAD
11
+ # [ ] LABELS
12
+ # [ ] LPROC
13
+ # [x] IS3D
14
+ # [x] MAP / TEMPMAP
15
+ # [x] PALATE
16
+ # [x] PHARYNX
17
+ # [ ] PPROC
18
+ # [x] SEX
19
+ # [x] SPLINE
20
+ # [ ] SPREAD
21
+ # [x] TAIL
22
+ # [x] SPATEX
23
+ # [x] VIEW
24
+ # [x] NAME
25
+ # [x] VLIST
26
+ # [x] VLSEL
27
+ # [x] SPECLIM
28
+
29
+ parser = argparse.ArgumentParser(
30
+ description="PhonoScape: Visualize acoustics & articulatory data."
31
+ )
32
+ parser.add_argument("file", type=str, help="Path to the .mat file to visualize.")
33
+ parser.add_argument(
34
+ "variables",
35
+ type=str,
36
+ nargs="?",
37
+ default="*",
38
+ help="Glob pattern to filter variables (default: '*').",
39
+ )
40
+ parser.add_argument(
41
+ "--palate",
42
+ type=str,
43
+ metavar="VAR",
44
+ help="Variable name for palate trace (optional).",
45
+ )
46
+ parser.add_argument(
47
+ "--pharynx",
48
+ type=str,
49
+ metavar="VAR",
50
+ help="Variable name for pharynx trace (optional).",
51
+ )
52
+ parser.add_argument(
53
+ "--spline",
54
+ type=str,
55
+ nargs="+",
56
+ metavar="TRAJ",
57
+ help="List of trajectory names to apply spline interpolation (default: all spatial trajectories starting with 'T').",
58
+ )
59
+ parser.add_argument(
60
+ "--polyline-spline",
61
+ action="store_true",
62
+ help="Connect the --spline points with a polyline instead of a smooth spline.",
63
+ )
64
+ parser.add_argument(
65
+ "--audio",
66
+ type=str,
67
+ metavar="TRAJ",
68
+ help="Variable name for audio trajectory - for spectrogram plotting and playback (default: first scalar trajectory with sampling rate > 1000 Hz).",
69
+ )
70
+ parser.add_argument(
71
+ "--framing",
72
+ type=str,
73
+ metavar="TRAJ",
74
+ help="Variable name for framing trajectory (default: --audio, or first trajectory if no audio found).",
75
+ )
76
+ parser.add_argument(
77
+ "--temporal-display",
78
+ type=str,
79
+ metavar="SPEC",
80
+ nargs="+",
81
+ help="List of variable names to include in temporal display (default: all plus {--audio}_SPECT).",
82
+ )
83
+ parser.add_argument(
84
+ "--spatial-exclude",
85
+ type=str,
86
+ nargs="+",
87
+ metavar="TRAJ",
88
+ help="List of trajectory names to exclude from the spatial view (default: none).",
89
+ )
90
+ parser.add_argument(
91
+ "--comps",
92
+ type=int,
93
+ nargs="+",
94
+ metavar=("N|COL", "COL"),
95
+ help="Number of dimensions for spatial trajectories, or list of column indices to use for each dimension (default: all dimensions, up to 3, are used for spatial view in x,y,z order).",
96
+ )
97
+ parser.add_argument(
98
+ "--view",
99
+ type=float,
100
+ nargs=3,
101
+ metavar=("ELEV", "AZIM", "ROLL"),
102
+ help="Initial view angles (degrees) for the 3D spatial display: azimuth, elevation and roll. Only has an effect when the data is 3D. Only has an effect on the first opened window; subsequent windows inherit the opening window's view (default: 0, -90, 0).",
103
+ )
104
+ parser.add_argument(
105
+ "--head",
106
+ type=float,
107
+ metavar="MS",
108
+ help="Start of selection (ms) for the temporal view (default: 0).",
109
+ )
110
+ parser.add_argument(
111
+ "--tail",
112
+ type=float,
113
+ metavar="MS",
114
+ help="End of selection (ms) for the temporal view (default: duration of the current trajectory).",
115
+ )
116
+ parser.add_argument(
117
+ "--sex",
118
+ choices=["M", "F"],
119
+ help="Pass 'F' for female, 'M' for male. This can be later customized in the 'Configure spectral analysis' dialog, but it affects the default LPC degree (default: M).",
120
+ )
121
+ parser.add_argument(
122
+ "--spect-lim",
123
+ type=float,
124
+ metavar="HZ",
125
+ help="Frequency upper limit (Hz) for spectrogram display (default: Nyquist frequency).",
126
+ )
127
+ parser.add_argument(
128
+ "--lproc",
129
+ type=str,
130
+ metavar="PROC",
131
+ help="Label procedure to use for labeling (default: none).",
132
+ )
133
+ args = parser.parse_args()
134
+
135
+ phonoscape(
136
+ args.file,
137
+ args.variables,
138
+ palate=args.palate,
139
+ pharynx=args.pharynx,
140
+ spline=args.spline,
141
+ polyline_spline=args.polyline_spline,
142
+ audio=args.audio,
143
+ framing=args.framing,
144
+ temporal_display=args.temporal_display,
145
+ spatial_exclude=args.spatial_exclude,
146
+ comps=(
147
+ None
148
+ if not args.comps
149
+ else args.comps[0] if len(args.comps) == 1 else args.comps
150
+ ),
151
+ view=cast(tuple[float, float, float], tuple(args.view)) if args.view else None,
152
+ head=args.head,
153
+ tail=args.tail,
154
+ sex=args.sex,
155
+ spect_lim=args.spect_lim,
156
+ lproc=args.lproc,
157
+ )