Audio analysis to detect low volume periods - audio

i have a sequence of audio files (they are currently both wav and mp3). These files consist of a beep, a pause and then the reply of a person. I need to find the reaction time between the beep and the person replying. There is a lot of data so i would like to make a program that could do this for me. Does anyone have any idea what language this could be done in, or know of any existing programs that will do this. I have looked into the wave tool in python, and can't seem to find any data that represents the low moments.
i program to function like this:
wav = open(wave file)
chunk = getNextChunk(wav)
volume = analyse(chunk)
check against threshold
if silent period, check for loud period
find difference
log time in seconds
Can anyone help me with this, i know its a very open ended question, but i have no idea where to start with this, i've programmed in java and python among others, but will use whats best, same with the sound format. Would it also be better to make the files mono?
Thanks for your help!

As to your choise of language I would personally choose Matlab. However it costs money, and as you already have experience with python the numpy module might be the right thing for you.
Based on your description of your problem, this could be one approach:
Load wav
Find envelope and smooth with a fast time constant
Threshold
Find time for beep
Find time for response
Calculate difference
Going to mono will be fine and reduce your amount of data at the same time.

I have found a solution that works, although my algorithm for detecting audio is pretty lousy, and is not very accurate. The amplitude or frequency of the sound seems to be visible, so the more digits a number has, the louder it is. I detect long sequences of digits to determine this, but one digit that doesnt fit the pattern and the cycle resets. Would be better to dermine based on the difference between the previous digits.
import wave, struct, logging
# open up a wave
w = wave.open('wavefile.WAV', 'rb')
length = w.getnframes()
rate = w.getframerate()
logging.basicConfig(filename='example.log',level=logging.DEBUG)
count = 0
start = 1
end = 0
startData = 0
endData = 0
for i in range(0,length):
waveData = w.readframes(1)
data = struct.unpack("<h", waveData)
if (start == 1):
if (len(str(int(data[0])))>=len(str(1234))):
count=count+1
else:
count=0
if (count == 100):
startData=i-100
print("Start "+str(startData/float(rate)))
count = 0
start = 0
end = 1
if (end == 1):
if (len(str(int(data[0])))<=len(str(12))):
count=count+1
else:
count=0
if (count == 10):
endData=i-10
print("End "+str(endData/float(rate)))
count = 0
start = 1
end = 0
frames=endData-startData
duration=frames/float(rate)
print("Duration: "+str(duration))

Related

Python - Iterate over while loop to compile an average runtime of program

So I want to preface this by saying one of the biggest problems with this I'm assuming is the return section of this code. With that being said, exactly what I'm trying to do is based off of my previous question for this code which was answered in two different ways, one said to be faster than the other. I wanted to see just how much faster myself by comparing the numbers. The problem I am now having though is that I would like to iterate over this function X amount of times, take the runtimes for each of those executions of the code, compile them, and create an average so I can then do the same with the other proposed solution, and compare the two. The main answer or help I'm currently looking for is getting this to iterate so I can have X different runtimes available to be seen. After that I will try to figure out how to compile them on my own, unless someone would be kind enough to help me through this entire process in one go.
import time
start_time = time.time()
def fibonacci():
previous_num, result = 0, 1
user = 1000
iterations = 10
while len(str(result)) < user:
while iterations != 0:
iterations -= 1
previous_num, result = result, previous_num + result
print(iterations)
return result
print(fibonacci())
print("--- %s seconds ---" % (time.time() - start_time))

How to skew random choice probability towards one option?

I am using the random library in python to select win or lose.
import random
choice = random.choice(['win','lose'])
Is there anyway I can say set the probability in the code to say I want more lose than win everytime the code runs?
Well, #CloC is technically right, you could do that, but better use the standard Python library as it is designed, less code, less bugs
F.e., sampling with probability of Win being 60%
v = random.choices(["Win", "Lose"], weights=[60, 40], k=1)
A way to control random (which wont be random...) would be to:
Generate a number between 1 and 100:
n = random.randint(1,101)
and then compare it with the percentage of win/loses you want :
chances_to_win = 51 # 50%
if n < chances_to_win:
print(str(chances_to_win-1) +"% chances to Win")
choice = "Win"
else:
print(str(100-(chances_to_win-1)) +"% chances to Lose")
choice = "Lose"
That way, you can control what is the percentage of wins and loses.

Python 3.x Homework help. Sequential number guessing game.

We are supposed to make a number guessing game where depending on what difficulty the player chooses the game generates 4 or 5 numbers and the player is given all but the last, which they have to guess in 3 tries. The numbers have to be equal distances apart, and the numbers have to be within the 1 - 100 range.
So far I know what it will look like roughly.
def guesses:
function for accumulating tries as long as guesses_taken < 3
let user retry, or congratulate and offer to replay
def game_easy:
code for number generation, step value, etc
guesses()
def game_hard:
same code as easy mode, with the appropriate changes
guesses()
For the random numbers, all I have so far is this
guess_init = rand.int (1,100)
step = rand.int (1,20)
guess_init = guess_init + step
and just having it loop and add the step 4 or 5 times respectively.
Where I'm stuck is 1. How to ensure that none of the numbers generated exceed 100 (so it can't be a step of 1 starting at 98), and 2. how to print all but the last number generated.
What I was thinking was assigning the last number generated to a variable that the player input must match. But I was also thinking that if "guess_init" has ran through the loop, then it will already be holding the value of the last number and all Ill have to check is that user input == guess_init.
In your Case you should read the random section from the Python Standard Library. Especially this is relevant:
random.randrange(start, stop[, step])
Return a randomly selected element from range(start, stop, step). This is equivalent to choice(range(start, stop, step)), but doesn’t actually build a range object.

Playing consecutive pitches in MATLAB

so I've been struggling with this for a while. I am supposed to make a sequence of tones play with only one soundsc(wave,fs) call, but when I try to put the tone waves in an array, it just plays them at the same time instead of consecutively. For example:
pitch1 = sin(2*pi*freq1*t);
pitch2 = sin(2*pi*freq2*t);
pitch3 = sin(2*pi*freq3*t);
concat_pitch = [pitch1; pitch2; pitch3]; % I want them to play in order, not together
soundsc(concat_pitch, fs); % this just plays them all together
Can anyone help me out? Thanks.
Change your concatenation to form a single row vector:
concat_pitch = [pitch1, pitch2, pitch3];
Or if the concatenation you specified is important and has to stay as is, then you can loop through the rows of the 2-d matrix:
for ind=1:length(concat_pitch)
soundsc(concat_pitch(ind,:), fs);
end

Creating a continuous tone in MATLAB whose frequency varies in real-time depending on user input

I am currently working on a graphing program in MATLAB that takes input and maps a point to x-y space using this input. However, the program should also output a continuous tone whose frequency varies depending on the location of the point.
I was able to get the tone generation done, however could not get the tone to work continuously due to the nature of the program. (Code in between tone generations) I thought I could solve this using a parfor loop with the code that alters the frequency in one iteration of the loop, and the code that generates the tone in another but cannot seem to get it due to the following error:
Warning: The temporary variable frequency will be cleared at the
beginning of each iteration of the parfor loop. Any value assigned to
it before the loop will be lost. If frequency is used before it is
assigned in the parfor loop, a runtime error will occur. See Parallel
for Loops in MATLAB, "Temporary Variables".
In multiThreadingtest at 5 Error using multiThreadingtest (line 5) Reference to a cleared variable frequency.
Caused by:
Reference to a cleared variable
frequency.
And my code:
global frequency
frequency = 100;
parfor ii=1:2
if ii==1
Fs = 1000;
nSeconds = 5;
y = 100*sin(linspace(0, nSeconds*frequency*2*pi, round(nSeconds*Fs)));
sound(y, Fs);
elseif ii==2
frequency = 100
pause(2);
frequency = 200
pause(2);
frequency = 300
pause(2);
end
end
The solution may not come from multithreading, but from the use of another function to output a tone(audioplayer, play, stop). 'audioplayer/play' has the ability to output sounds that overlap in time. So basically, a pseudo code would be:
get the value of the input
generate/play a corresponding 5 second tone
detect if any change in the input
if no change & elapsed time close to 5 seconds
generate/play an identical 5 second tone
if change
generate a new 5 second tone
%no overlapping
stop old
play new
%overlapping (few milliseconds)
play new
stop old
The matlab code showing the 'sound'/'play' differences.
Fs = 1000;
nSeconds = 5;
frequency = 100;
y1 = 100*sin(linspace(0, nSeconds*frequency*2*pi, round(nSeconds*Fs)));
aud1 = audioplayer(y1, Fs);
frequency = 200;
y2 = 100*sin(linspace(0, nSeconds*frequency*2*pi, round(nSeconds*Fs)));
aud2 = audioplayer(y2, Fs);
% overlapping sound impossible
sound(y1, Fs);
pause(1)
sound(y2, Fs);
% overlapping sound possible
play(aud1);
pause(1);
disp('can compute here');
play(aud2);
pause(1);
stop(aud1);
pause(1);
stop(aud2);

Resources