Shriphani ‘PSP’ Palakodety

Weblog of an Aspiring Computer Scientist

Shriphani ‘PSP’ Palakodety header image 2

WAV Files, Spring Semester, Research Hopes, IPL,

May 26th, 2009 · 1 Comment · python

UPDATE 02/13/2010: Most recent version of this script is now moved to: http://shriphani.com/blog/listener.

EDIT: An updated version of this script along with tools to improve the user experience can be obtained at http://shriphani.com/Shriphani_Website/Listener.html

After an looooong time, I’ve decided to put finger on keyboard (I think that sounds stupid). Considering that I now use BOSE headphones which cut me off from the outside world when I am listening to anything (I use the triport headphones; not the Quietcomfort), it has been a bit hard to respond to all the calls for attention over here (no one usually wants me to pay attention and that’s how it works best). So I decided that it would be better if I could use the mic on my mac to check if someone was calling me. This is the first time I have tinkered with .wav files and I am sure that I am doing loads of things wrong. First, I decided to use PyAudio, PortAudio’s Python bindings, to record audio from the microphone, save it to a wav file and then open it and analyze etc. So with help from the Examples that come bundled with PyAudio, here is the code to record from the inbuilt microphone:

Recording:

def record():
    ‘Records Input From Microphone Using PyAudio’
    duration = 1 #record for 1 second. Pretty long duration don’t you think
    outfile = "analysis.wav"

    p = pyaudio.PyAudio()

    inStream = p.open(format=pyaudio.paInt16, channels=1, rate=44100,input=True, frames_per_buffer=1024)

    print "recording has begun"
    out = []
    upper_lim = 44100 / 1024 * duration #upper limit of the range we record to. 44100 / 1024 sized chunk * 5 seconds

    for i in xrange(0, upper_lim):
        data = inStream.read(1024)
        out.append(data)

    #now the writing section where we write to file

    data = .join(out)
    outFile = wave.open(outfile, "wb")
    outFile.setnchannels(1)
    outFile.setsampwidth(p.get_sample_size(pyaudio.paInt16))
    outFile.setframerate(44100)
    outFile.writeframes(data)
    outFile.close()

Then, I opened the wav file and read the first 2000 values from it and obtained the root mean square amplitude and then obtained the intensity of sound using the following snippet:

Analyzing

def analyze():
    inFile = wave.open("analysis.wav", "rb") #open a wav file in read mode
    sample_rate = inFile.getframerate()
    total_samples = inFile.getnframes()
    fftLength = 128
    fft_num = (total_samples/fftLength) -2
    vals = inFile.readframes(2000)
    results = struct.unpack("%dh"%(2000), vals)
    results = [x**2 for x in results]
    intensity = 20 * numpy.log10(numpy.sqrt(sum(results)/2000))
    if (intensity > 55):
        print "Someone might be calling you"
        curtime = time.localtime()
        print "Current Time: %d:%d:%d"%(curtime[3], curtime[4], curtime[5])
        print "Intensity: "+str(intensity) + " dB\n"
    inFile.close()

I chose 55 dB because well 55 dB seems to be the right intensity of sound you would hear if you were conversing with someone 1 meter away.

The next thing to do would be to repeat this action over and over again. I decided to use something like:

while True:
    record()
    analyze()
    sleep(2.0)

I am not sure what went wrong there but when it ran the second time it gave me an “internal PortAudio Error” which pissed me off. However, using BASH to handle the endless loop worked and I could achieve the desired functionality using something like:

while [ "true" ]
do
  python audio_analysis.py
  sleep 2
done

This might be the wrong way to go about it but it works at least…..

Also, I thought growl would be something cool to have and I decided that I would go out there and get it use Growl to notify me but for some screwed up reason I cannot build Growl’s Python bindings using the Enthought Python Distribution which I use. I can however build it using Python 2.6 (and I still use the Numpy that comes with EPD). I get errors like:

running install
running build
running build_py
running build_ext
building '_growlImage' extension
gcc -arch i386 -arch ppc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -g -L/usr/local/lib -L/Library/Frameworks/Python.framework/Versions/4.3.0/lib -bundle -undefined dynamic_lookup build/temp.macosx-10.3-fat-2.5/growlImage.o -o build/lib.macosx-10.3-fat-2.5/_growlImage.so -framework Cocoa
ld: in /Developer/SDKs/MacOSX10.4u.sdk/Library/Frameworks/Python.framework/Versions/4.3.0/lib/libz.1.dylib, file is not of required architecture for architecture ppc
collect2: ld returned 1 exit status
lipo: can't open input file: /var/tmp//ccNgltEc.out (No such file or directory)
error: command 'gcc' failed with exit status 1

I think that I am unable to generate a universal binary there and as a result I can’t use Growl. Anyway, I have two screens and I can leave a terminal window open on one of those to see what’s going on in the surroundings. So sample run:

cm92:scripts shriphani$ ./repeat.sh
Someone might be calling you
Current Time: 11:55:22
Intensity: 56.9166929341 dB

Someone might be calling you
Current Time: 11:55:33
Intensity: 72.6820018669 dB

Someone might be calling you
Current Time: 11:55:51
Intensity: 56.7505666696 dB

Someone might be calling you
Current Time: 11:55:54
Intensity: 55.571208569 dB

Someone might be calling you
Current Time: 11:55:58
Intensity: 60.0388858371 dB

Someone might be calling you
Current Time: 11:56:1
Intensity: 56.3460220002 dB

These results were obtained in the following situations:

  • The TV running.
  • My mom calling me.

Anyway, in other news, I managed to end up with a GPA of 3.85 overall thanks to a series of mistakes towards the end of the semester and lost the 4.0…….. it is depressing, but I’ll just put that behind me for now.

And I’m also trying to find a spot in Prof Kihara’s computational bio lab….. I hope I get to do some research next semester.

The spring was not full of disappointment, I got to meet some awesome professors in the honors seminar (in which I skipped most of the student presentations except the one I was supposed to speak in). I got to meet Prof. Wagstaff who has a prime number named after him, I got to meet Prof Kihara and others.

Congrats to the Deccan Chargers for their excellent performance in the Indian Premier League. Thanks for rewarding our unyielding support by bringing the trophy to Hyderabad.

Now I’ve got to go and entertain myself with Combat Arms.

UPDATE: The script can be obtained at: Script to Record+Analyze and Script to Repeat action.

Tags:

One Comment so far ↓

  • Martin

    Thanks for the code. I’m going to need something like this soon.

    Btw. do you know if there’s any easy and efficient way to read 24-bit wav files? struct.unpack doesn’t seem to support signed 24-bit values.

Leave a Comment