recorder.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # 录音模块(电脑麦克风)
  2. import pyaudio
  3. import wave
  4. import numpy as np
  5. from config import Config
  6. def record_until_silence(max_seconds=10, silence_threshold=500, silence_duration_ms=800):
  7. """
  8. 录音直到检测到静音
  9. 返回:bytes (WAV 格式音频数据)
  10. """
  11. CHUNK = 1024
  12. FORMAT = pyaudio.paInt16
  13. CHANNELS = Config.AUDIO_CHANNELS
  14. RATE = Config.AUDIO_SAMPLE_RATE
  15. audio = pyaudio.PyAudio()
  16. # 列出输入设备
  17. print('可用输入设备:')
  18. for i in range(audio.get_device_count()):
  19. info = audio.get_device_info_by_index(i)
  20. if info['maxInputChannels'] > 0:
  21. print(f' [{i}] {info["name"]}')
  22. stream = audio.open(
  23. format=FORMAT,
  24. channels=CHANNELS,
  25. rate=RATE,
  26. input=True,
  27. frames_per_buffer=CHUNK,
  28. )
  29. print('开始录音...(说完后会自动停止)')
  30. frames = []
  31. silent_chunks = 0
  32. chunks_per_silence = int(RATE * silence_duration_ms / 1000 / CHUNK)
  33. max_chunks = int(RATE * max_seconds / CHUNK)
  34. for _ in range(max_chunks):
  35. try:
  36. data = stream.read(CHUNK, exception_on_overflow=False)
  37. except Exception as e:
  38. print(f'录音错误: {e}')
  39. break
  40. frames.append(data)
  41. # 检测音量
  42. audio_data = np.frombuffer(data, dtype=np.int16)
  43. volume = np.abs(audio_data).mean()
  44. if volume < silence_threshold:
  45. silent_chunks += 1
  46. if silent_chunks >= chunks_per_silence and len(frames) > chunks_per_silence:
  47. print('检测到静音,停止录音')
  48. break
  49. else:
  50. silent_chunks = 0
  51. stream.stop_stream()
  52. stream.close()
  53. audio.terminate()
  54. # 编码为 WAV
  55. wav_data = encode_wav(frames, RATE, CHANNELS)
  56. print(f'录音完成:{len(wav_data) / 1024:.1f} KB')
  57. return wav_data
  58. def encode_wav(frames, rate, channels):
  59. """编码为 WAV bytes"""
  60. import io
  61. buffer = io.BytesIO()
  62. with wave.open(buffer, 'wb') as wf:
  63. wf.setnchannels(channels)
  64. wf.setsampwidth(2)
  65. wf.setframerate(rate)
  66. wf.writeframes(b''.join(frames))
  67. return buffer.getvalue()
  68. if __name__ == '__main__':
  69. wav_data = record_until_silence()
  70. with open('test_recording.wav', 'wb') as f:
  71. f.write(wav_data)
  72. print('已保存为 test_recording.wav')