2

I have to record 3 microphones simultaneously with as little delay between them as possible. This will then allow me to calculate the TDOA of sound between the microphones, so that I can pinpoint the source location.

However, I keep on getting a Input Overflow error thrown by PulseAudio, which makes the data unusable as the frames in that chunk captured by the microphone are discarded.

So far, I have attempted to fix the problem by changing the chunk size, even setting it to 2x my rate at one point. Initially I was using PyAudio, but the current version of my code runs sounddevice.

In order to start all three recordings at the same time I've been using multiprocessing, with each process containing its own input stream, but even running all 3 streams in one process caused the overflow(s).

I've also tried running the stream with or without callbacks, but that made no difference. Same with writing the data to memory or directly to disk.

CHUNK = 48000*2 #Chunk sizes varied from 5 up to 96000, both didn't work
RATE = 48000
CHANNELS = 1
FILE_NAME = 'recording'

def recorder(start, mic_num, file_name):
    running = False
    q = Queue()
    file = sf.SoundFile(f'./recordings/{file_name}_{mic_num}.wav', mode = 'w', samplerate = RATE, channels = CHANNELS)
    print('Created', mic_num) 

    def mic_processor(data, frames, time, status):
        if(status):
            #RIP recording :/
            print(status) #Only status ever thrown is input overflow
            global running
            running = False
            sys.exit()
        q.put(data)

    while not running:
        if(datetime.datetime.now() >= start):
            stream = sd.InputStream(samplerate = RATE, blocksize = CHUNK, device = mic_num, channels = CHANNELS, callback = mic_processor)
            stream.start()
            print('Microphone', mic_num, 'recording')
            running = True
    while running:
        try:
            file.write(q.get())
        except KeyboardInterrupt:
            stream.stop()
            file.flush()
            file.close()
            running = False

if __name__ == '__main__':
    start = datetime.timedelta(seconds=5)+datetime.datetime.now()

    p1 = Process(target = recorder, args = (start, 2, FILE_NAME))
    p2 = Process(target = recorder, args = (start, 3, FILE_NAME))
    p3 = Process(target = recorder, args = (start, 4, FILE_NAME))

    p1.start()
    p2.start()
    p3.start()

    while True:
        try:
            time.sleep(0.0001)
            if not p1.is_alive() or not p2.is_alive() or not p3.is_alive():
                print('Something went wrong with one of the processes, gotta exit :/')
                p1.terminate()
                p2.terminate()
                p3.terminate()
                sys.exit()
        except KeyboardInterrupt:
            print('Writing to file')
            time.sleep(0.5)
            while p1.is_alive() or p2.is_alive() or p3.is_alive():
                time.sleep(0.1)
            break

Ideally, I'd hope to have no input overflows anymore, but at this point I'm completely stumped as to how to prevent them. Should I maybe just switch to ALSA instead of PulseAudio?

I'd really appreciate any help I can get with this :)

Leoworm
  • 21
  • 1
  • Can you say a few words about your devices `2`, `3` and `4`? Are they synchronized? – Matthias Sep 03 '19 at 05:44
  • Microphones 2, 3 and 4 are the USB microphones, and are synchronized using the system time. I generate a datetime 5 seconds in the future, pass it to each process, and once the process realizes that the given time is now it starts the recording. I have managed to get the synchronization of the start of recording very tight. – Leoworm Sep 03 '19 at 15:11
  • So they are separate devices with no physical connection between them? It looks like you'll never know the exact delay between them, right? You might have less problems when combining the devices with a custom `.asoundrc`, but it might still not work very well. Apart from having an unknown delay between the devices, you'll probably also experience clock drift, see e.g. https://www.quora.com/What-is-the-best-way-to-connect-three-USB-microphones-into-a-single-computer-for-multi-person-podcasting or https://sound.stackexchange.com/questions/23849/monitoring-multiple-usb-microphones. – Matthias Sep 04 '19 at 07:00
  • The delay between them isn't really my main problem currently. If I can't even get the code to record the input for more than 1 second without throwing an error, removing delay won't really help that much. – Leoworm Sep 04 '19 at 10:07
  • It might not be your problem now, but it may be later, when trying to calculate the TDOA. I just wanted to mention that you might be wasting you time debugging a setup that might ultimately fail. – Matthias Sep 05 '19 at 06:45
  • Did you try `CHUNK=0`? Did you try using the `maxsize` argument of `Queue`? You should probably use `put_nowait()` in that case. – Matthias Sep 07 '19 at 13:26
  • Unrelated to your problem: You should make a copy of the audio data before putting it into the queue, otherwise multiple arrays might point to the same memory at some point. – Matthias Sep 07 '19 at 13:28
  • I gave up and bought a mixer, which ended up working perfectly. I don't think that it's possible to do with Pulse or ALSA. – Leoworm Feb 18 '20 at 16:04

0 Answers0