diff --git a/client/audio_capture.py b/client/audio_capture.py index 5817b4a..bbae094 100644 --- a/client/audio_capture.py +++ b/client/audio_capture.py @@ -15,6 +15,7 @@ class AudioCapture: self, sample_rate: int = 16000, chunk_duration: float = 3.0, + overlap_duration: float = 0.5, device: Optional[int] = None ): """ @@ -23,12 +24,15 @@ class AudioCapture: Args: sample_rate: Target audio sample rate in Hz (16000 for Whisper) chunk_duration: Duration of each audio chunk in seconds + overlap_duration: Duration of overlap between chunks in seconds (prevents word cutoff) device: Input device index, or None for default """ self.target_sample_rate = sample_rate self.chunk_duration = chunk_duration + self.overlap_duration = overlap_duration self.device = device self.chunk_size = int(sample_rate * chunk_duration) + self.overlap_size = int(sample_rate * overlap_duration) # Hardware sample rate (will be auto-detected) self.hardware_sample_rate = None @@ -156,8 +160,10 @@ class AudioCapture: """Recording loop that runs in a separate thread.""" buffer = np.array([], dtype=np.float32) - # Calculate hardware chunk size + # Calculate hardware chunk and overlap sizes hardware_chunk_size = int(self.hardware_sample_rate * self.chunk_duration) + hardware_overlap_size = int(self.hardware_sample_rate * self.overlap_duration) + hardware_stride = hardware_chunk_size - hardware_overlap_size try: with sd.InputStream( @@ -177,7 +183,10 @@ class AudioCapture: if len(buffer) >= hardware_chunk_size: # Extract chunk chunk = buffer[:hardware_chunk_size] - buffer = buffer[hardware_chunk_size:] + + # Move buffer forward by stride (not full chunk size) + # This creates overlap between consecutive chunks + buffer = buffer[hardware_stride:] # Resample to target rate if needed if self.hardware_sample_rate != self.target_sample_rate: diff --git a/config/default_config.yaml b/config/default_config.yaml index 31733e9..95767c2 100644 --- a/config/default_config.yaml +++ b/config/default_config.yaml @@ -6,6 +6,7 @@ audio: input_device: "default" sample_rate: 16000 chunk_duration: 3.0 + overlap_duration: 0.5 # Overlap between chunks to prevent word cutoff (seconds) noise_suppression: enabled: true diff --git a/gui/main_window_qt.py b/gui/main_window_qt.py index 06463c0..adec397 100644 --- a/gui/main_window_qt.py +++ b/gui/main_window_qt.py @@ -278,6 +278,7 @@ class MainWindow(QMainWindow): self.audio_capture = AudioCapture( sample_rate=self.config.get('audio.sample_rate', 16000), chunk_duration=self.config.get('audio.chunk_duration', 3.0), + overlap_duration=self.config.get('audio.overlap_duration', 0.5), device=audio_device ) @@ -296,7 +297,7 @@ class MainWindow(QMainWindow): self.is_transcribing = True self.start_button.setText("⏸ Stop Transcription") self.start_button.setStyleSheet("background-color: #e74c3c; color: white;") - self.status_label.setText("🔴 Recording...") + self.status_label.setText("🔴 Transcribing...") except Exception as e: QMessageBox.critical(self, "Error", f"Failed to start transcription:\n{e}") diff --git a/main_cli.py b/main_cli.py index 299d067..f871992 100755 --- a/main_cli.py +++ b/main_cli.py @@ -92,6 +92,7 @@ class TranscriptionCLI: self.audio_capture = AudioCapture( sample_rate=self.config.get('audio.sample_rate', 16000), chunk_duration=self.config.get('audio.chunk_duration', 3.0), + overlap_duration=self.config.get('audio.overlap_duration', 0.5), device=audio_device )