diff --git a/energy_based_recorder.py b/energy_based_recorder.py index f8e4477..535e493 100644 --- a/energy_based_recorder.py +++ b/energy_based_recorder.py @@ -29,6 +29,7 @@ class EnergyBasedRecorder: self.silence_threshold = silence_threshold # 静音阈值,低于此值持续多久认为结束 self.min_recording_time = min_recording_time # 最小录音时间 self.max_recording_time = max_recording_time # 最大录音时间 + self.pre_record_duration = 2.0 # 预录音时长(秒) # 状态变量 self.audio = None @@ -41,6 +42,10 @@ class EnergyBasedRecorder: self.energy_history = [] # 能量历史 self.max_energy_history = 50 # 最大能量历史记录 + # 预录音缓冲区 + self.pre_record_buffer = [] # 预录音缓冲区 + self.pre_record_max_frames = int(self.pre_record_duration * self.RATE / self.CHUNK_SIZE) # 最大预录音帧数 + # 性能监控 self.frame_count = 0 self.start_time = time.time() @@ -201,11 +206,26 @@ class EnergyBasedRecorder: except Exception as e: print(f"❌ 系统播放器也失败: {e}") + def update_pre_record_buffer(self, audio_data): + """更新预录音缓冲区""" + self.pre_record_buffer.append(audio_data) + + # 保持缓冲区大小 + if len(self.pre_record_buffer) > self.pre_record_max_frames: + self.pre_record_buffer.pop(0) + def start_recording(self): """开始录音""" print("🎙️ 检测到声音,开始录音...") self.recording = True self.recorded_frames = [] + + # 将预录音缓冲区的内容添加到录音中 + self.recorded_frames.extend(self.pre_record_buffer) + + # 清空预录音缓冲区 + self.pre_record_buffer = [] + self.recording_start_time = time.time() self.last_sound_time = time.time() self.energy_history = [] # 重置能量历史 @@ -215,7 +235,12 @@ class EnergyBasedRecorder: if len(self.recorded_frames) > 0: audio_data = b''.join(self.recorded_frames) duration = len(audio_data) / (self.RATE * 2) # 16位音频,每样本2字节 - print(f"📝 录音完成,时长: {duration:.2f}秒") + + # 计算实际录音时长和预录音时长 + actual_duration = duration + pre_record_duration = min(duration, self.pre_record_duration) + + print(f"📝 录音完成,时长: {actual_duration:.2f}秒 (包含预录音 {pre_record_duration:.1f}秒)") # 保存录音 success, filename = self.save_recording(audio_data) @@ -275,6 +300,8 @@ class EnergyBasedRecorder: print("- 动态阈值调整(基于背景噪音)") print("- 零交叉率检测(区分语音和噪音)") print("- 实时显示ZCR和背景能量") + print("- 预录音功能(包含声音开始前2秒)") + print("- 环形缓冲区防止丢失开头音频") print("=" * 50) try: @@ -315,21 +342,26 @@ class EnergyBasedRecorder: print(f"\n⏰ 达到最大录音时间 {self.max_recording_time}秒") self.stop_recording() - # 显示录音状态 + # 显示录音状态(包含预录音信息) + pre_duration = len(self.pre_record_buffer) * self.CHUNK_SIZE / self.RATE bg_energy = np.median(self.energy_history[-10:]) if len(self.energy_history) >= 10 else 0 status = f"录音中... {recording_duration:.1f}s | 能量: {energy:.0f} | ZCR: {zcr:.0f} | 背景: {bg_energy:.0f}" print(f"\r{status}", end='', flush=True) else: - # 监听模式 - 使用高级检测 + # 监听模式 - 更新预录音缓冲区 + self.update_pre_record_buffer(data) + + # 使用高级检测 if self.is_voice_active_advanced(energy, zcr): # 检测到声音,开始录音 self.start_recording() else: - # 显示监听状态 + # 显示监听状态(包含缓冲区信息) avg_energy = self.get_average_energy() bg_energy = np.median(self.energy_history[-10:]) if len(self.energy_history) >= 10 else 0 - status = f"监听中... 能量: {energy:.0f} | ZCR: {zcr:.0f} | 背景: {bg_energy:.0f}" + buffer_usage = len(self.pre_record_buffer) / self.pre_record_max_frames * 100 + status = f"监听中... 能量: {energy:.0f} | ZCR: {zcr:.0f} | 背景: {bg_energy:.0f} | 缓冲: {buffer_usage:.0f}%" print(f"\r{status}", end='', flush=True) # 减少CPU使用