revoxx 1.1.2__tar.gz → 1.1.3__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 (142) hide show
  1. {revoxx-1.1.2/revoxx.egg-info → revoxx-1.1.3}/PKG-INFO +1 -1
  2. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/audio_queue_processor.py +9 -0
  3. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/recorder.py +13 -0
  4. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/audio_controller.py +12 -0
  5. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/display_controller.py +15 -2
  6. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/edit_controller.py +30 -0
  7. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/active_recordings.py +6 -0
  8. {revoxx-1.1.2 → revoxx-1.1.3/revoxx.egg-info}/PKG-INFO +1 -1
  9. {revoxx-1.1.2 → revoxx-1.1.3}/LICENSE +0 -0
  10. {revoxx-1.1.2 → revoxx-1.1.3}/MANIFEST.in +0 -0
  11. {revoxx-1.1.2 → revoxx-1.1.3}/README.md +0 -0
  12. {revoxx-1.1.2 → revoxx-1.1.3}/doc/import_raw_text.png +0 -0
  13. {revoxx-1.1.2 → revoxx-1.1.3}/doc/screenshot1.png +0 -0
  14. {revoxx-1.1.2 → revoxx-1.1.3}/pyproject.toml +0 -0
  15. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/__init__.py +0 -0
  16. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/__main__.py +0 -0
  17. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/app.py +0 -0
  18. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/__init__.py +0 -0
  19. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/audio_buffer.py +0 -0
  20. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/buffer_manager.py +0 -0
  21. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/edit_commands.py +0 -0
  22. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/editor.py +0 -0
  23. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/level_calculator.py +0 -0
  24. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/player.py +0 -0
  25. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/processors/__init__.py +0 -0
  26. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/processors/clipping_detector.py +0 -0
  27. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/processors/mel_spectrogram.py +0 -0
  28. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/processors/processor_base.py +0 -0
  29. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/queue_manager.py +0 -0
  30. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/shared_state.py +0 -0
  31. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/undo_stack.py +0 -0
  32. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/audio/worker_state.py +0 -0
  33. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/constants.py +0 -0
  34. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/__init__.py +0 -0
  35. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/device_controller.py +0 -0
  36. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/dialog_controller.py +0 -0
  37. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/file_operations_controller.py +0 -0
  38. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/navigation_controller.py +0 -0
  39. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/process_manager.py +0 -0
  40. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/controllers/session_controller.py +0 -0
  41. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/dataset/__init__.py +0 -0
  42. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/dataset/exporter.py +0 -0
  43. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/doc/USER_GUIDE.md +0 -0
  44. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/resources/keyboard_shortcuts.txt +0 -0
  45. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/resources/microphone.png +0 -0
  46. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/resources/templates/dataset_readme.txt +0 -0
  47. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/resources/templates/index_format_with_intensity.txt +0 -0
  48. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/resources/templates/index_format_without_intensity.txt +0 -0
  49. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/session/__init__.py +0 -0
  50. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/session/inspector.py +0 -0
  51. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/session/manager.py +0 -0
  52. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/session/models.py +0 -0
  53. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/session/script_parser.py +0 -0
  54. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/__init__.py +0 -0
  55. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/__init__.py +0 -0
  56. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/dataset_dialog.py +0 -0
  57. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/dialog_utils.py +0 -0
  58. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/find_dialog.py +0 -0
  59. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/help_dialog.py +0 -0
  60. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/import_text_dialog.py +0 -0
  61. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/new_session_dialog.py +0 -0
  62. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/open_session_dialog.py +0 -0
  63. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/progress_dialog.py +0 -0
  64. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/session_settings_dialog.py +0 -0
  65. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/user_guide_dialog.py +0 -0
  66. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/utterance_list_base.py +0 -0
  67. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/dialogs/utterance_order_dialog.py +0 -0
  68. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/emotion_indicator.py +0 -0
  69. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/font_manager.py +0 -0
  70. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/frequency_axis.py +0 -0
  71. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/icon.py +0 -0
  72. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/info_overlay.py +0 -0
  73. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/level_meter/__init__.py +0 -0
  74. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/level_meter/config.py +0 -0
  75. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/level_meter/led_level_meter.py +0 -0
  76. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/menus/application_menu.py +0 -0
  77. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/menus/audio_devices.py +0 -0
  78. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/recording_display_state.py +0 -0
  79. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/__init__.py +0 -0
  80. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/controllers/__init__.py +0 -0
  81. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/controllers/clipping_visualizer.py +0 -0
  82. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/controllers/edge_indicator.py +0 -0
  83. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/controllers/playback_controller.py +0 -0
  84. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/controllers/selection_visualizer.py +0 -0
  85. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/controllers/zoom_controller.py +0 -0
  86. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/display_base.py +0 -0
  87. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/display_utils.py +0 -0
  88. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/mel_processor_manager.py +0 -0
  89. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/playback_handler.py +0 -0
  90. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/recording_display.py +0 -0
  91. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/recording_handler.py +0 -0
  92. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/selection_interaction.py +0 -0
  93. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/selection_state.py +0 -0
  94. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/view_context.py +0 -0
  95. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/spectrogram/widget.py +0 -0
  96. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/style_config.py +0 -0
  97. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/themes.py +0 -0
  98. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/widget_initializer.py +0 -0
  99. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/window_base.py +0 -0
  100. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/window_factory.py +0 -0
  101. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/ui/window_manager.py +0 -0
  102. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/__init__.py +0 -0
  103. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/adaptive_frame_rate.py +0 -0
  104. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/audio_utils.py +0 -0
  105. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/config.py +0 -0
  106. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/device_manager.py +0 -0
  107. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/file_manager.py +0 -0
  108. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/process_cleanup.py +0 -0
  109. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/settings_manager.py +0 -0
  110. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/spectrogram_utils.py +0 -0
  111. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/state.py +0 -0
  112. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/text_importer.py +0 -0
  113. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/text_utils.py +0 -0
  114. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx/utils/tk_compat.py +0 -0
  115. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx.egg-info/SOURCES.txt +0 -0
  116. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx.egg-info/dependency_links.txt +0 -0
  117. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx.egg-info/entry_points.txt +0 -0
  118. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx.egg-info/requires.txt +0 -0
  119. {revoxx-1.1.2 → revoxx-1.1.3}/revoxx.egg-info/top_level.txt +0 -0
  120. {revoxx-1.1.2 → revoxx-1.1.3}/scripts_module/__init__.py +0 -0
  121. {revoxx-1.1.2 → revoxx-1.1.3}/scripts_module/export.py +0 -0
  122. {revoxx-1.1.2 → revoxx-1.1.3}/scripts_module/vadiate.py +0 -0
  123. {revoxx-1.1.2 → revoxx-1.1.3}/setup.cfg +0 -0
  124. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_active_recordings.py +0 -0
  125. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_audio_controller.py +0 -0
  126. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_audio_queue_manager.py +0 -0
  127. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_config.py +0 -0
  128. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_dataset_exporter.py +0 -0
  129. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_device_controller.py +0 -0
  130. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_dialog_controller.py +0 -0
  131. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_display_controller.py +0 -0
  132. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_file_manager.py +0 -0
  133. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_file_operations_controller.py +0 -0
  134. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_ipc_communication.py +0 -0
  135. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_navigation_controller.py +0 -0
  136. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_new_session_dialog.py +0 -0
  137. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_process_manager.py +0 -0
  138. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_session_controller.py +0 -0
  139. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_session_manager.py +0 -0
  140. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_session_models.py +0 -0
  141. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_stable_sorting.py +0 -0
  142. {revoxx-1.1.2 → revoxx-1.1.3}/tests/test_utterance_list_dialog_sorting.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: revoxx
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: Speech recording application for creating high-quality speech datasets
5
5
  Author-email: Grammatek ehf <info@grammatek.com>
6
6
  Maintainer-email: Grammatek ehf <info@grammatek.com>
@@ -158,6 +158,15 @@ class AudioQueueProcessor:
158
158
  if hasattr(self.app, "window_manager") and self.app.window_manager:
159
159
  active_windows = self.app.window_manager.get_active_windows()
160
160
 
161
+ if not hasattr(self, "_spec_debug_count"):
162
+ self._spec_debug_count = 0
163
+ self._spec_debug_count += 1
164
+ if self._spec_debug_count == 1 and getattr(self.app, "debug", False):
165
+ for window in active_windows:
166
+ has_spec = hasattr(window, "mel_spectrogram") and window.mel_spectrogram
167
+ m_vis = getattr(window, "meters_visible", False)
168
+ print(f"[AudioQueueProcessor] window has_spectrogram={has_spec} meters_visible={m_vis}")
169
+
161
170
  for window in active_windows:
162
171
  has_spectrogram = (
163
172
  hasattr(window, "mel_spectrogram") and window.mel_spectrogram
@@ -77,22 +77,35 @@ class AudioRecorder:
77
77
  Returns:
78
78
  bool: True if stream started successfully, False otherwise
79
79
  """
80
+ debug = self.manager_dict and self.manager_dict.get("debug", False)
81
+
80
82
  # Already recording - ignore duplicate start
81
83
  if self._state == WorkerState.ACTIVE:
82
84
  return True
83
85
 
84
86
  if not self._validate_and_prepare():
87
+ if debug:
88
+ print(f"[Recorder] _validate_and_prepare() failed", file=sys.stderr)
85
89
  return False
86
90
 
87
91
  open_channels = self._determine_channel_configuration()
88
92
 
93
+ if debug:
94
+ print(f"[Recorder] start_recording: device={self.config.input_device}, sr={self.config.sample_rate}, ch={open_channels}", file=sys.stderr)
95
+
89
96
  self.stream = self._create_stream(self.config.sample_rate, open_channels)
90
97
  if not self.stream:
98
+ if debug:
99
+ print(f"[Recorder] _create_stream() returned None - device open FAILED", file=sys.stderr)
100
+ last_err = self.manager_dict.get("last_input_error", "unknown") if self.manager_dict else "N/A"
101
+ print(f"[Recorder] last_input_error={last_err}", file=sys.stderr)
91
102
  self._state = WorkerState.IDLE
92
103
  return False
93
104
 
94
105
  self.stream.start()
95
106
  self._state = WorkerState.ACTIVE
107
+ if debug:
108
+ print(f"[Recorder] stream started successfully, audio_queue_active={self._is_audio_queue_active()}", file=sys.stderr)
96
109
  return True
97
110
 
98
111
  def _validate_and_prepare(self) -> bool:
@@ -338,10 +338,15 @@ class AudioController:
338
338
  # Mode-specific setup
339
339
  if mode == "recording":
340
340
  if not self._setup_recording_mode():
341
+ if self.app.debug:
342
+ print(f"[AudioController] _setup_recording_mode() returned False (no current label?)")
341
343
  return # No current label, can't record
342
344
  else:
343
345
  self._setup_monitoring_mode()
344
346
 
347
+ if self.app.debug:
348
+ print(f"[AudioController] _start_audio_capture({mode}) waiting for spectrograms...")
349
+
345
350
  # Execute the actual audio capture start
346
351
  # Ensure spectrograms are ready before starting (especially for monitoring)
347
352
  self.app.display_controller.when_spectrograms_ready(
@@ -445,6 +450,11 @@ class AudioController:
445
450
  3. Sending start command to the recording process
446
451
  4. Updating status message in UI
447
452
  """
453
+ if self.app.debug:
454
+ print(f"[AudioController] _do_start_audio_capture({mode}) - spectrograms ready")
455
+ print(f"[AudioController] audio_queue_active={self.app.process_manager.is_audio_queue_active()}")
456
+ print(f"[AudioController] record_process alive={self.app.process_manager.record_process and self.app.process_manager.record_process.is_alive()}")
457
+
448
458
  self.app.display_controller.start_spectrogram_recording(
449
459
  self.app.config.audio.sample_rate
450
460
  )
@@ -456,6 +466,8 @@ class AudioController:
456
466
  self._verify_input_device()
457
467
 
458
468
  self.app.queue_manager.start_recording()
469
+ if self.app.debug:
470
+ print(f"[AudioController] start_recording command sent to record process")
459
471
 
460
472
  if mode == "recording":
461
473
  self.app.display_controller.update_display()
@@ -82,6 +82,13 @@ class DisplayController:
82
82
  # Load the recording
83
83
  filepath = self.app.file_manager.get_recording_path(current_label, current_take)
84
84
  if filepath.exists():
85
+ # Guard against 0-byte / corrupt files (e.g. from a previous crash)
86
+ if filepath.stat().st_size == 0:
87
+ filepath.unlink()
88
+ self.clear_spectrograms()
89
+ self.update_info_panel()
90
+ return
91
+
85
92
  try:
86
93
  audio_data, sr = self.app.file_manager.load_audio(filepath)
87
94
 
@@ -569,13 +576,16 @@ class DisplayController:
569
576
  Args:
570
577
  callback: Function to call when spectrograms are ready
571
578
  """
572
- # Collect windows that need spectrograms
579
+ # Collect windows that need spectrograms (only if meters are visible)
573
580
  windows_needing_spectrograms = [
574
- w for w in self._get_active_windows() if not w.mel_spectrogram
581
+ w for w in self._get_active_windows()
582
+ if not w.mel_spectrogram and getattr(w, "meters_visible", False)
575
583
  ]
576
584
 
577
585
  if not windows_needing_spectrograms:
578
586
  # All ready, execute immediately
587
+ if self.app.debug:
588
+ print(f"[DisplayController] when_spectrograms_ready: all ready, executing callback immediately")
579
589
  callback()
580
590
  else:
581
591
  # wait for all spectrograms
@@ -585,6 +595,9 @@ class DisplayController:
585
595
  if hasattr(w, "spec_frame")
586
596
  ]
587
597
 
598
+ if self.app.debug:
599
+ print(f"[DisplayController] when_spectrograms_ready: {len(windows_needing_spectrograms)} windows need spectrograms, {len(spec_frames)} have spec_frame")
600
+
588
601
  if spec_frames:
589
602
  WidgetInitializer.fire_when_all_ready(
590
603
  self.app.window.window,
@@ -111,6 +111,36 @@ class EditController:
111
111
  audio_before, start_sample, end_sample, sr
112
112
  )
113
113
 
114
+ # Check if deletion removed all audio
115
+ if len(audio_after) == 0:
116
+ # Move the now-empty recording to trash instead of saving a 0-byte file
117
+ self.app.file_manager.move_to_trash(label, take)
118
+
119
+ # Update active recordings cache and take counter
120
+ if self.app.active_recordings:
121
+ self.app.active_recordings.on_recording_deleted(label, take)
122
+ self.app.state.recording.takes = (
123
+ self.app.active_recordings.get_all_takes()
124
+ )
125
+
126
+ self.app.state.recording.set_displayed_take(label, 0)
127
+
128
+ # Clear selection and display
129
+ selection_state.clear_all()
130
+ if self.app.window and self.app.window.mel_spectrogram:
131
+ self.app.window.mel_spectrogram.selection_visualizer.clear()
132
+
133
+ self.app.display_controller.clear_spectrograms()
134
+ self.app.navigation_controller.update_take_status()
135
+
136
+ if self.app.window.info_panel_visible:
137
+ self.app.display_controller.update_info_panel()
138
+
139
+ self.app.display_controller.set_status(
140
+ "Recording deleted (all audio removed)", MsgType.TEMPORARY
141
+ )
142
+ return True
143
+
114
144
  # Save the edited audio
115
145
  subtype = self._get_audio_subtype()
116
146
  self.app.file_manager.save_audio(filepath, audio_after, sr, subtype)
@@ -151,6 +151,9 @@ class ActiveRecordings:
151
151
  elif self.sort_column == "recordings":
152
152
  # Sort by takes, then by label for stable ordering
153
153
  return lambda item: (item["takes"], item["label"].lower())
154
+ elif self.sort_column == "text_length":
155
+ # Sort by text length, then by label for stable ordering
156
+ return lambda item: (item["text_length"], item["label"].lower())
154
157
  else:
155
158
  # Default to index (no sort)
156
159
  return lambda item: item["index"]
@@ -179,6 +182,9 @@ class ActiveRecordings:
179
182
  elif self.sort_column == "recordings":
180
183
  filenames = self._takes_cache.get(label, [])
181
184
  item["takes"] = len(filenames)
185
+ elif self.sort_column == "text_length":
186
+ clean_text = self._extract_clean_text(self._utterances[i])
187
+ item["text_length"] = len(clean_text)
182
188
 
183
189
  items.append(item)
184
190
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: revoxx
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: Speech recording application for creating high-quality speech datasets
5
5
  Author-email: Grammatek ehf <info@grammatek.com>
6
6
  Maintainer-email: Grammatek ehf <info@grammatek.com>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes