I’m trying to get the microphone to work without any luck. I’ve got it to the point where a .wav file is saved. The file is the appropriate duration, but it is silent (just as has been reported here and here). I’ve even tried the hacky solution I found here but couldn’t get it to work either (I end up with a zero-byte wav file). Does anyone have a solution to this?
This is might be helpful and is also a follow up to my post “Need voicekey working code (psychopy3)” . With help from many posts here, in stack exchange, and other places, I have the following code working to get sound from a mic, establish a primitive threshold, and use the mic signal live as a voice key. See if you can get this running to establish that the mic stream is working and then we can work on writing the file(s). (note this is for psychopy3, python3, and linux). I modified some of the borrowed code from python2. Note: I make no claims and assume no liability for the following (and yes, I use nonstandard full 8 tabs and my coding style is ugly… there may be irrelevant variables and code here because I am building on it. Trust anything Jon Peirce or other capable people say about this. Hope nothing broke in the paste)
#!/usr/bin/python3
import pyaudio
import struct
import math
import numpy
import psychopy
from psychopy import visual, core, event, sound
# https://stackoverflow.com/questions/4160175/detect-tap-with-pyaudio-from-live-mic
### FOR MICROPHONE
INITIAL_TAP_THRESHOLD = 0.010
FORMAT = pyaudio.paInt16
SHORT_NORMALIZE = (1.0/32768.0)
CHANNELS = 2
RATE = 44100
INPUT_BLOCK_TIME = 0.005
INPUT_FRAMES_PER_BLOCK = int(RATE*INPUT_BLOCK_TIME)
###################################################
def get_rms(block):
# RMS amplitude is defined as the square root of the
# mean over time of the square of the amplitude.
# so we need to convert this string of bytes into
# a string of 16-bit samples...
# we will get one short out for each
# two chars in the string.
count = len(block)/2
format = "%dh"%(count)
shorts = struct.unpack( format, block )
# iterate over the block.
sum_squares = 0.0
for sample in shorts:
# sample is a signed short in +/- 32768.
# normalize it to 1.0
n = sample * SHORT_NORMALIZE
sum_squares += n*n
return math.sqrt( sum_squares / count )
timer1=core.Clock()
sw1=timer1.getTime()
sw2=timer1.getTime()
pa = pyaudio.PyAudio()
micstream = pa.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True, output=False,
frames_per_buffer = INPUT_FRAMES_PER_BLOCK)
# calibrate 500 samples in background
print ("calib starting: \nfinding ceiling of silence noise ...")
amps=[]
for i in range(500):
try:
block = micstream.read(INPUT_FRAMES_PER_BLOCK)
except IOError as e:
print( "(%d) Error recording: %s"%(errorcount,e) )
amplitude = get_rms(block)
amps.append(amplitude)
print ( "%9.6f"% numpy.mean(amps) )
print ( "%9.6f"% numpy.min(amps) )
print ( "%9.6f"% numpy.max(amps) )
MULTIPLIER=1.500
nfloor=MULTIPLIER*numpy.max(amps)
print ("calib complete: \nsetting threshold to 2.0 x silence maxnoise (%7.4f)"%nfloor)
print (" mic is live for a while " )
sw1=timer1.getTime()
sw2=timer1.getTime()
sw3=timer1.getTime()
core.wait(0.5000)
#stream.stop_stream()
#stream.start_stream()
print (" trial amplitude streamstart RT " )
vk=0
for i in range(5): # run 5 test trials
core.wait(1.0000)
amplitude=0.000
vk=0
bracket=2000.00 # resp timeout
ET=0.0
print ("trial")
sw1=timer1.getTime()
micstream.start_stream()
sw2=timer1.getTime()
while vk==0 and ET < bracket:
block = micstream.read(INPUT_FRAMES_PER_BLOCK)
amplitude = get_rms(block)
#print ( amplitude)
ET=(timer1.getTime()-sw2) * 1000.000
if amplitude > nfloor:
sw3=timer1.getTime()
print("%4d %8.6f %8.2f %8.2f"%( i, amplitude, 1000.0*(sw2-sw1), 1000.0*(sw3-sw2) ) )
vk=1
micstream.stop_stream()
if vk==0 and ET > bracket:
print( ET, "timeout: no resp")
RT=99999.99
else:
RT= 1000.0*(sw3-sw2)
print ("\t\t\t\t\tWR: %12.4f\n"%RT)
AFAIK, if you can get this much working, then you will just need to convert the “blocks” to wav and write the file.