Search code examples
pythonlinuxaudioalsapyaudio

Sound output is present in sound input even with no mic in linux


I'm trying to simultaneously play a sound and record voltage output from a piezo sensor. For this, I connect my sound board analog outputs to speakers, and my sound board analog input to a piezo sensor.

When I record signal from the sensor but playing no sound, it works perfectly. But, when I play a sound during the recording, I can see the sound I'm playing in the sensor's signal, as if the output and input of the sound board were connected. The most strange is that even when I unplug the sensor, the output signal is still present in the recording.

In other words, the problem is: I start recording, when I start playing the sound it appears in the sensor's signal (even with speakers turned off).

I'm using only ALSA, pulseaudio is not installed. I'm using python (and pyaudio) to generate sound signal, write the signal to sound board outputs and read data from sound board input. I also tested in Audacity, but the result was the same. I also tested with arecord:

$ arecord --channel=1 --rate=128000 --format=S32_LE Test.wav

And then:

$ mplayer Audio/Alarms/Annoying_Alien_Buzzer-Kevan-1659966176.mp3 

And then stopped the recording. When I play Test.wav, all the sound signal from the played file is there.

I know it may sound obvious, but I want to say that there is NO MIC connected anywhere in the setup.

Here is some info:

====================
Box:

$ uname -a
Linux MalfattiTux 4.1.12-gentoo #3 SMP Thu Jan 21 17:24:27 BRST 2016 x86_64 Intel(R) Core(TM) i7-4710HQ CPU @ 2.50GHz GenuineIntel GNU/Linux

Audio boards:

$ lspci | grep -i audio
00:03.0 Audio device: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller (rev 06)
00:1b.0 Audio device: Intel Corporation 8 Series/C220 Series Chipset High Definition Audio Controller (rev 05)## Heading ##

Output devices:

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: ALC3239 Analog [ALC3239 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 1: ALC3239 Digital [ALC3239 Digital]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Input devices:

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: PCH [HDA Intel PCH], device 0: ALC3239 Analog [ALC3239 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Python code to play and record (minimal working example):

import array
import pyaudio
import random

Rate = 128000
SoundPulseDur = 5 # in seconds

print('Generating sound pulse...')
SoundNoise = [random.random() for _ in range(round(Rate*SoundPulseDur))]
SoundPulse = [SoundNoise[ElI]*2-1 for ElI,ElV in enumerate(SoundNoise)]
SoundPulse[-1] = 0


print('Interleaving channels...')
SoundList = [0]*(2*len(SoundPulse))
for _ in range(len(SoundPulse)):
    SoundList[_ *2] = SoundPulse[_]
    SoundList[_ *2+1] = 0

Sound = array.array('f')
Sound.fromlist(SoundList)
Sound = bytes(Sound)


print('Generating sound objects...')
# Output
p = pyaudio.PyAudio()
Stimulation = p.open(format=pyaudio.paFloat32,
                channels=2,
                rate=Rate,
                output=True)

# Input
q = pyaudio.PyAudio()
InOn = False
RecStop = True
def InCallBack(in_data, frame_count, time_info, status):
    if InOn:
        global SoundRec
        SoundRec.append(in_data)

    if RecStop:
        InFlag = pyaudio.paComplete
    else:
        InFlag = pyaudio.paContinue
    return(None, InFlag)

Reading = q.open(format=pyaudio.paFloat32,
                     channels=1,
                     rate=Rate,
                     input=True,
                     output=False,
                     stream_callback=InCallBack)

SoundRec = []
Reading.start_stream()
RecStop = False; InOn = True
Stimulation.write(Sound)
InOn = False; RecStop = True
Reading.stop_stream()

Solution

  • This sound like electric noise from your sound-card. I take it you're using an onboard card? If so, there's not much you can do to avoid recording the noise, unless you want to buy a better/external sound-card.

    As to an actual solution; Personally, I would record my audio output, and use that audio data to cancel the noise from the piezo sensor data.

    This should theoretically also be possible to do live, if you can read your sound output to the piezo recording script with for example PyAudio