microphones.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. #^IMPORTANT: essential to make multiprocessing work
  2. import queue
  3. import sys
  4. import sounddevice as sd
  5. import soundfile as sf
  6. import numpy # Make sure NumPy is loaded before it is used in the callback
  7. assert numpy # avoid "imported but unused" message (W0611)
  8. from situtils import FPSTimes
  9. import time
  10. class MicrophoneController(FPSTimes):
  11. # https://python-sounddevice.readthedocs.io/en/0.3.15/examples.html#recording-with-arbitrary-duration
  12. @staticmethod
  13. def callback(indata, frames, time, status):
  14. """This is called (from a separate thread) for each audio block."""
  15. if status:
  16. print(status, file=sys.stderr)
  17. MicrophoneController.queue.put(indata.copy())
  18. @classmethod
  19. def run(cls, status, cfg):
  20. # MicrophoneController.initialize(cfg)
  21. print("Running.")
  22. import sounddevice as sd # must be inside the function
  23. if cfg['channel_selectors']: # make it work without ASIO
  24. # https://python-sounddevice.readthedocs.io/en/0.3.15/api/platform-specific-settings.html
  25. asio_in = sd.AsioSettings(channel_selectors=cfg['channel_selectors'])
  26. else:
  27. asio_in = None
  28. MicrophoneController.queue = queue.Queue() # kind of a hack
  29. stream = sd.InputStream(samplerate=cfg['sample_rate'], device=cfg['device'], channels=cfg['number_channels'], callback=MicrophoneController.callback, extra_settings = asio_in)
  30. filename = cfg['file_path']
  31. file = sf.SoundFile(filename, mode='w', samplerate=cfg['sample_rate'], channels=cfg['number_channels'],subtype='PCM_32') # 'w': overwrite mode, 'x': raises error if file exists
  32. # experiment status: 1 - idle, 2 - running (recording, logging), 0 - stopped
  33. with file as f:
  34. while status.value > 0:
  35. try:
  36. if status.value == 2:
  37. # start stream if not active yet
  38. if not stream.active:
  39. print("Audio input stream started.")
  40. t0 = time.time()
  41. stream.start()
  42. with open(cfg['csv_path'], 'a') as f_csv:
  43. f_csv.write(",".join([str(x) for x in (t0,)]) + "\n")
  44. f.write(MicrophoneController.queue.get())
  45. else:
  46. time.sleep(0.005)
  47. except KeyboardInterrupt:
  48. stream.stop()
  49. stream.close()
  50. break