I am trying to detect peaks from two microphones at the same time with python and pyaudio and calculate the time difference between them. I'm using two Konig usb microphones (http://www.konigelectronic.com/en_us/1102418). But everytime the time difference between the microphones varies between 0.1 and 20ms, without replacing them. Is it possible to have the same difference all the time if I place them next to each other? The final purpose is to calculate the TDOA of 4 microphones. I found this code on stackoverflow for detecting taps and edited the code so it will record from two mics.

import pyaudio
import struct
import math
import datetime
import time
import audioop

FORMAT = pyaudio.paInt16 
SHORT_NORMALIZE = (1.0/32768.0)
RATE = 44100  
printed = 1000
printed1 = 1000
timeKonig1 = None
timeKonig = None
detectedmic1 = False
detectedmic2 = False

def get_rms( block ):
    return audioop.rms(block, 2)

def get_rms1( block1 ):
    return audioop.rms(block1, 2)

class TapTester(object):
    def __init__(self):
        self.pa = pyaudio.PyAudio()
        self.stream = self.open_mic_stream()
        self.stream1 = self.open_mic_stream1()
        self.tap_threshold = INITIAL_TAP_THRESHOLD
        self.tap_threshold1 = INITIAL_TAP_THRESHOLD1

    def stop(self):

    def open_mic_stream( self ):

        stream = self.pa.open(   format = FORMAT,
                                 channels = CHANNELS,
                                 rate = RATE,
                                 input = True,
                                 input_device_index = 1,
                                 frames_per_buffer = INPUT_FRAMES_PER_BLOCK)        

        return stream
    def open_mic_stream1( self ):

        stream1 = self.pa.open(  format = FORMAT,
                                 channels = CHANNELS,
                                 rate = RATE,
                                 input = True,
                                 input_device_index = 0,
                                 frames_per_buffer = INPUT_FRAMES_PER_BLOCK)

        return stream1

    def listen(self):
        block = self.stream.read(INPUT_FRAMES_PER_BLOCK, exception_on_overflow = False)
        amplitude = get_rms( block )
        block1 = self.stream1.read(INPUT_FRAMES_PER_BLOCK, exception_on_overflow = False)
        amplitude1 = get_rms( block1 )
        global printed
        if amplitude > self.tap_threshold and printed < i:
            global timeKonig
            timeKonig = datetime.datetime.now()
            global detectedmic1
            detectedmic1 = True
            printed = i + 1000           
        global printed1
        if amplitude1 > self.tap_threshold1 and printed1 < i:
            global timeKonig1
            timeKonig1 = datetime.datetime.now()
            global detectedmic2
            detectedmic2 = True
            printed1 = i + 1000           
        if detectedmic1 and detectedmic2:
            if timeKonig > timeKonig1:
                if (timeKonig - timeKonig1).microseconds < 20000:
                    print "1. ", (timeKonig - timeKonig1).microseconds
                if timeKonig < timeKonig1:
                    if (timeKonig1 - timeKonig).microseconds < 20000:
                        print "2. ", (timeKonig1 - timeKonig).microseconds
            detectedmic1, detectedmic2 = False, False

if __name__ == "__main__":
    tt = TapTester()

    for i in range(10000000):
  • 1
    I tried something similar with three microphones connected to an ADC (they returned a voltage). I hoped to be able to "triangulate" the sound source. It didn't really work. It's hard to get equal level responses and it's hard to get accurate times (and you need at least four microphones to "triangulate"). I think having to use USB will just further muck up the ability to get accurate timings. If you get it to work that will be a notable achievement! – joan Apr 5 '17 at 14:53

I think it's unlikely that you're going to be able to persuade USB mics to provide you with the timing accuracy you need for this kind of test (although I'd be very happy to be proved wrong). Linux is not a Real Time Operating System (RTOS), and can't provide the kind of timing guarantees that you need.

If you're just measuring the time of arrival of impulse noises (claps) you might be able to make use of something like this Sparkfun sound detector (cheaper versions are available on Ebay), hooked up to the Pi's GPIO pins. That board should spit out a simple binary 0 or 1 indicating the presence of sound. I think you should be able to achieve more reliable timing using that approach and a library such as pigpio.

If you just can't achieve the reliability you need on a Pi it would be worth considering switching to something along the lines of an Arduino. There's less overhead to get in the way of accuracy.


I finally managed to calculate the time difference of arrival with the usb microphones and to actually calculate a coordinate and show this on a map (created with matplotlib). I just connected the three microphones to the Raspberry Pi 3. I figured out that the delay of the microphone after the first microphone is about 3ms. I hardcoded the delay and placed the microphones in several distances from each other. The result is that the system actually can locate sound. See the images of a detected sound next to a microphone next to microphone and a detected sound between two microphones between two microphones.

  • Can you share the code, please? – Tarlan Ahad Mar 31 at 3:32

Not the answer you're looking for? Browse other questions tagged or ask your own question.