Notice: This forum has been recovered from an old backup, so some content, links, and dates may be outdated. The forum is currently read-only while we restore sign-in and registration functionality. Details

If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.

Reacting to sound level in Eventghost

If you have a question or need help, this is the place to be.
Post Reply
lucianopacheco
Posts: 3
Joined: Fri Aug 08, 2014 4:54 pm

Reacting to sound level in Eventghost

Post by lucianopacheco »

Hi Guys,

I┬┤m trying to setup a profile and coudn┬┤t find anything about it.

My eventghost runs on a PC with a Microphone plugged in the sound card.
I need to monitor the sound level (decibel) captured by the Mic and have eventghost react to it if the sound reaches some threashold (70dB for ex).
Any idea on how to do this? Any software or plugin compatible with eventghost?
Thanks a lot.

Regards,
Luciano.
Dragon470
Experienced User
Posts: 205
Joined: Thu Feb 10, 2011 2:16 am

Re: Reacting to sound level in Eventghost

Post by Dragon470 »

This can be done. You don't even need to use any third party software. You will need pyaudio (python library). I just did some very quick testing and it works. I don't have any math done to get the correct decibel readouts. So here is what I scraped together:

Code: Select all

import pyaudio
import struct
import math
import time

INITIAL_TAP_THRESHOLD = 0.010
FORMAT = pyaudio.paInt16 
SHORT_NORMALIZE = (1.0/32768.0)
CHANNELS = 2
RATE = 44100  
INPUT_BLOCK_TIME = 0.05
INPUT_FRAMES_PER_BLOCK = int(RATE*INPUT_BLOCK_TIME)

OVERSENSITIVE = 15.0/INPUT_BLOCK_TIME                    

UNDERSENSITIVE = 120.0/INPUT_BLOCK_TIME # if we get this many quiet blocks in a row, decrease the threshold

MAX_TAP_BLOCKS = 0.15/INPUT_BLOCK_TIME # if the noise was longer than this many blocks, it's not a 'tap'

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 )

pa = pyaudio.PyAudio()                                 #]
                                                       #|
stream = pa.open(format = FORMAT,                      #|
         channels = CHANNELS,                          #|---- You always use this in pyaudio...
         rate = RATE,                                  #|
         input = True,                                 #|
         frames_per_buffer = INPUT_FRAMES_PER_BLOCK)   #]

tap_threshold = INITIAL_TAP_THRESHOLD                  #]
noisycount = MAX_TAP_BLOCKS+1                          #|---- Variables for noise detector...
quietcount = 0                                         #|
errorcount = 0                                         #]         

for i in range(50):
    try:                                                    #]
        block = stream.read(INPUT_FRAMES_PER_BLOCK)         #|
    except IOError, e:                                      #|---- just in case there is an error!
        errorcount += 1                                     #|
        print( "(%d) Error recording: %s"%(errorcount,e) )  #|
        noisycount = 1                                      #]

    amplitude = get_rms(block)
    if amplitude > tap_threshold: # if its to loud...
        quietcount = 0
        noisycount += 1
        if noisycount > OVERSENSITIVE:
            tap_threshold *= 1.1 # turn down the sensitivity

    else: # if its to quiet...

        if 1 <= noisycount <= MAX_TAP_BLOCKS:
            print 'tap!'
        noisycount = 0
        quietcount += 1
        if quietcount > UNDERSENSITIVE:
            tap_threshold *= 0.9 # turn up the sensitivity
    print "count " + str(i) + " " + str(amplitude) + " threshold " + str(tap_threshold)
    time.sleep(0.5)

stream.close()


The library files:
pyaudio.zip
pyaudio library
(43.23 KiB) Downloaded 137 times
unzipped to the main eventghost folder.


The script scans for 0.05 seconds every 0.5 seconds for 25 seconds. If I clap it registers about 3 or 4 readouts later. All the "Tap!" is part of someone else's code.
lucianopacheco
Posts: 3
Joined: Fri Aug 08, 2014 4:54 pm

Re: Reacting to sound level in Eventghost

Post by lucianopacheco »

Wow. Thank you very much mate.
Tomorrow I will give it a try and report back with my results.
Thanks!!
Dragon470
Experienced User
Posts: 205
Joined: Thu Feb 10, 2011 2:16 am

Re: Reacting to sound level in Eventghost

Post by Dragon470 »

Here is a much more simplified (I stripped out the tapping) script. I also added what I think is a decibel math, but it only goes up to 100. So I am not sure if the math is right.

Code: Select all

import pyaudio
import struct
import math
import time

FORMAT = pyaudio.paInt16 
SHORT_NORMALIZE = (1.0/32768.0)
CHANNELS = 2
RATE = 44100  
INPUT_BLOCK_TIME = 0.05
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 )

pa = pyaudio.PyAudio()                                 #]
                                                       #|
stream = pa.open(format = FORMAT,                      #|
         channels = CHANNELS,                          #|---- You always use this in pyaudio...
         rate = RATE,                                  #|
         input = True,                                 #|
         frames_per_buffer = INPUT_FRAMES_PER_BLOCK)   #]


for i in range(50):
    try:                                                    #]
        block = stream.read(INPUT_FRAMES_PER_BLOCK)         #|
    except IOError, e:                                      #|---- just in case there is an error!
        print( "Error recording: ")                         #|

    amplitude = get_rms(block)
    print "count " + str(i) + " " + str(amplitude)
    print "db " + str((20*math.log10(amplitude/0.00001)))
    time.sleep(0.5)

stream.close()

P.S. It does require a default microphone set. I also do get an error message about the library not installed sometimes, I just have to restart eventghost (sometimes multiple times).
lucianopacheco
Posts: 3
Joined: Fri Aug 08, 2014 4:54 pm

Re: Reacting to sound level in Eventghost

Post by lucianopacheco »

Awesome!! Your help has been huge!
It works really well.. I m gonna need to test for some threshold. Now I just need to make some tests and refine the sensitivity. But I think its gonna work very well.
I realized you need a default microphone. Also, I dont know if Eventghost can run this script along with all the other scripts it has to run normally (maybe I need to lower the number of samples).
Also Im struggling to have windows recognize my JBL Flip (bluetooth speaker and microphone) as a default microphone.

Thanks again!
Post Reply