Programmatically detect and extract an audio envelope - c

All suggestions and links to relevant info welcome here. This is the scenario:
Let us say I have a .wav file of someone speaking (and therefore all the samples associated with it).
I would like to run an algorithm on the series of samples to detect when an event happens i.e. the beginning and the end of an envelope. I would then use this starting and end point to extract that data to be used elsewhere.
What would be the best way to tackle this? Any pseudocode? Example code? Source code?
I will eventually be writing this in C.
Thanks!
EDIT 1
Parsing the wav file is not a problem. But some pseudo-code for the envelope detection would be nice! :)

The usual method is:
take absolute value of waveform, abs(x[t])
low pass filter (say 10 Hz cut-off)
apply threshold

You could use the same method as an old fashioned analog meter. Rectify the sample vector, pass the absolute value result though a low pass filter (FIR, IIR, moving average, etc.), than compare against some threshold. For a more accurate event time, you will have to subtract the group delay time of the low pass filter.
Added: You might also need to remove DC beforehand (say with a high-pass filter or other DC blocker equivalent to capacitive coupling).

Source code of simple envelope detectors can be found in the Music-DSP Source Code Archive.

I have written an activity detector class in Java. It's part of my open-source Java DSP collection.

first order low pass filter C# Code:
double old_y = 0;
double R1Filter(double x, double rct)
{
if (rct == 0.0)
return 0;
if (x > old_y)
old_y = old_y-(old_y - x)*rct/256;
else
old_y = old_y + (x - old_y) * rct/256;
return old_y;
}
When rct=2, it works like this:
The signal = (ucm + ucm * ma * Cos(big_omega * x)) * (Cos(small_omega1 * x) + Cos(small_omega2 * x) )
where ucm=3,big_omega=200,small_omega1=4,small_omega2=12 and ma=0.8
Pay attention that the filter may change the phase of the base band signal.

Related

Appending values to DataSet in Apache Flink

I am currently writing an (simple) analytisis code to sum time connected powerreadings. With the data being assumingly raw (e.g. disturbances from the measuring device have not been calculated out) I have to account for disturbances by calculation the mean of the first one thousand samples. The calculation of the mean itself is not a problem. I only am unsure of how to generate the appropriate DataSet.
For now it looks about like this:
DataSet<Tupel2<long,double>>Gyrotron_1=ECRH.includeFields('11000000000'); // obviously the line to declare the first gyrotron, continues for the next ten lines, assuming separattion of not occupied space
DataSet<Tupel2<long,double>>Gyrotron_2=ECRH.includeFields('10100000000');
DataSet<Tupel2<long,double>>Gyrotron_3=ECRH.includeFields('10010000000');
DataSet<Tupel2<long,double>>Gyrotron_4=ECRH.includeFields('10001000000');
DataSet<Tupel2<long,double>>Gyrotron_5=ECRH.includeFields('10000100000');
DataSet<Tupel2<long,double>>Gyrotron_6=ECRH.includeFields('10000010000');
DataSet<Tupel2<long,double>>Gyrotron_7=ECRH.includeFields('10000001000');
DataSet<Tupel2<long,double>>Gyrotron_8=ECRH.includeFields('10000000100');
DataSet<Tupel2<long,double>>Gyrotron_9=ECRH.includeFields('10000000010');
DataSet<Tupel2<long,double>>Gyrotron_10=ECRH.includeFields('10000000001');
for (int=1,i<=10;i++) {
DataSet<double> offset=Gyroton_'+i+'.groupBy(1).first(1000).sum()/1000;
}
It's the part in the for-loop I'm unsure of. Does anybody know if it is possible to append values to DataSets and if so how?
In case of doubt, I could always put the values into an array but I do not know if that is the wise thing to do.
This code will not work for many reasons. I'd recommend looking into the fundamentals of Java and the basic data structures and also in Flink.
It's really hard to understand what you actually try to achieve but this is the closest that I came up with
String[] codes = { "11000000000", ..., "10000000001" };
DataSet<Tuple2<Long, Double>> result = env.fromElements();
for (final String code : codes) {
DataSet<Tuple2<Long, Double>> codeResult = ECRH.includeFields(code)
.groupBy(1)
.first(1000)
.sum(0)
.map(sum -> new Tuple2<>(sum.f0, sum.f1 / 1000d));
result = codeResult.union(result);
}
result.print();
But please take the time and understand the basics before delving deeper. I also recommend to use an IDE like IntelliJ that would point to at least 6 issues in your code.

How to update weights when using mini batches?

I am trying to implement mini batch training to my neural network instead of the "online" stochastic method of updating weights every training sample.
I have developed a somewhat novice neural network in C whereby i can adjust the number of neurons in each layer , activation functions etc. This is to help me understand neural networks. I have trained the network on mnist data set but it takes around 200 epochs to get down do an error rate of 20% on the training set which seams very poor to me. I am currently using online stochastic gradient decent to train the network. What i would like to try is use mini batches instead. I understand the concept that i must accumulate and average the error from each training sample before i propagate the error back. My problem comes in when i want to calculate the changes i must make to the weights. To explain this better consider a very simple perceptron model. One input, one hidden layer one output. To calculate the change i need to make to the weight between the input and the hidden unit i will use this following equation:
∂C/∂w1= ∂C/∂O*∂O/∂h*∂h/∂w1
If you do the partial derivatives you get:
∂C/∂w1= (Output-Expected Answer)(w2)(input)
Now this formula says that you need to multiply the back propogated error by the input. For online stochastic training that makes sense because you use 1 input per weight update. For minibatch training you used many inputs so which input does the error get multiplied by?
I hope you can assist me with this.
void propogateBack(void){
//calculate 6C/6G
for (count=0;count<network.outputs;count++){
network.g_error[count] = derive_cost((training.answer[training_current])-(network.g[count]));
}
//calculate 6G/6O
for (count=0;count<network.outputs;count++){
network.o_error[count] = derive_activation(network.g[count])*(network.g_error[count]);
}
//calculate 6O/6S3
for (count=0;count<network.h3_neurons;count++){
network.s3_error[count] = 0;
for (count2=0;count2<network.outputs;count2++){
network.s3_error[count] += (network.w4[count2][count])*(network.o_error[count2]);
}
}
//calculate 6S3/6H3
for (count=0;count<network.h3_neurons;count++){
network.h3_error[count] = (derive_activation(network.s3[count]))*(network.s3_error[count]);
}
//calculate 6H3/6S2
network.s2_error[count] = = 0;
for (count=0;count<network.h2_neurons;count++){
for (count2=0;count2<network.h3_neurons;count2++){
network.s2_error[count] = += (network.w3[count2][count])*(network.h3_error[count2]);
}
}
//calculate 6S2/6H2
for (count=0;count<network.h2_neurons;count++){
network.h2_error[count] = (derive_activation(network.s2[count]))*(network.s2_error[count]);
}
//calculate 6H2/6S1
network.s1_error[count] = 0;
for (count=0;count<network.h1_neurons;count++){
for (count2=0;count2<network.h2_neurons;count2++){
buffer += (network.w2[count2][count])*network.h2_error[count2];
}
}
//calculate 6S1/6H1
for (count=0;count<network.h1_neurons;count++){
network.h1_error[count] = (derive_activation(network.s1[count]))*(network.s1_error[count]);
}
}
void updateWeights(void){
//////////////////w1
for(count=0;count<network.h1_neurons;count++){
for(count2=0;count2<network.inputs;count2++){
network.w1[count][count2] -= learning_rate*(network.h1_error[count]*network.input[count2]);
}
}
//////////////////w2
for(count=0;count<network.h2_neurons;count++){
for(count2=0;count2<network.h1_neurons;count2++){
network.w2[count][count2] -= learning_rate*(network.h2_error[count]*network.s1[count2]);
}
}
//////////////////w3
for(count=0;count<network.h3_neurons;count++){
for(count2=0;count2<network.h2_neurons;count2++){
network.w3[count][count2] -= learning_rate*(network.h3_error[count]*network.s2[count2]);
}
}
//////////////////w4
for(count=0;count<network.outputs;count++){
for(count2=0;count2<network.h3_neurons;count2++){
network.w4[count][count2] -= learning_rate*(network.o_error[count]*network.s3[count2]);
}
}
}
The code i have attached is how i do the online stochastic updates. As you can see in the updateWeights() function the weight updates are based on the input values (dependent on the sample fed in) and the hidden unit values (also dependent on the input sample value fed in). So when i have the minibatch average gradient that i am propogating back how will i update the weights? which input values do i use?
Ok so i figured it out. When using mini batches you should not accumulate and average out the error at the output of the network. Each training examples error gets propogated back as you would normally except instead of updating the weights you accumulate the changes you would have made to each weight. When you have looped through the mini batch you then average the accumulations and change the weights accordingly.
I was under the impression that when using mini batches you do not have to propogate any error back until you have looped through the mini batch. I was wrong you still need to do that the only difference is you only update the weights once you have looped through your mini batch size.
For minibatch training you used many inputs so which input does the error get multiplied by?
"Many inputs" this is a proportion of the dataset size N, which typically segments your data into sizes which are not too large to fit into memory. DL needs Big Data and the full batch cannot fit into most computer systems to process in one go and therefore the mini-batch is necessary.
The error which gets backpropagated is the sum or average error calculated for the data samples in your current mini-batch $X^{{t}}$ which is of size M where $M<N$, $J^{{t}} = 1/m \sum_1^M ( f(x_m^{t})-y_m^{t} )^2$. This is the sum of the squared distances to the target across samples in the batch 't'. This is the forward step and then the backwards propagation of this error is made using the chain rule through the 'neurons' of the network; using this single value of the error for the whole batch. The update of the parameters is based upon this value for this mini-batch.
There are variations to how this scheme is implemented but if you consider your idea of using "many inputs" in the calculation of the parameter update using multiple input samples from the batch, we are averaging over multiple gradients to smooth over the gradient in comparison to stochastic gradient descent.

Filtering "Smoothing" an array of numbers in C

I am writing an application in X-code. It is gathering the sensor data (gyroscope) and then transforming it throw FFTW. At the end I am getting the result in an array. In the app. I am plotting the graph but there is so much peaks (see the graph in red) and i would like to smooth it.
My array:
double magnitude[S];
...
magnitude[i]=sqrt((fft_result[i][0])*(fft_result[i][0])+ (fft_result[i][1])*(fft_result[i][1]) );
An example array (for 30 samples, normally I am working with 256 samples):
"0.9261901713034604",
"2.436272348237486",
"1.618854900218465",
"1.849221286218342",
"0.8495016887742839",
"0.5716796354304043",
"0.4229791869017677",
"0.3731843430827401",
"0.3254446111798023",
"0.2542702545675339",
"0.25237940627189",
"0.2273716541964159",
"0.2012780334451323",
"0.2116151847259499",
"0.1921943719520009",
"0.1982429400169304",
"0.18001770452247",
"0.1982429400169304",
"0.1921943719520009",
"0.2116151847259499",
"0.2012780334451323",
"0.2273716541964159",
"0.25237940627189",
"0.2542702545675339",
"0.3254446111798023",
"0.3731843430827401",
"0.4229791869017677",
"0.5716796354304043",
"0.8495016887742839",
"1.849221286218342"
How to filter /smooth it? whats about gauss? Any idea how to begin or even giving me a sample code.
Thank you for your help!
best regards
josef
Simplest way to smooth would be to replace each sample with the average of it and its 2 neighbors.
The simpliest idea would be taking average of 2 points and putting them into an array. Something like
double smooth_array[S];
for (i = 0; i<S-2; i++)
smooth_array[i]=(magnitude[i] + magnitude[i+1])/2;
smooth_array[S-1]=magnitude[S-1];
It is not best one, but I think it should be ok.
If you need the scientific approach - use some kind of approximation / approximation algorithms. Something like least squares function approximation or even full SE13/SE35 etc. algorithms.

Testing an Algorithms speed. How?

I'm currently testing different algorithms, which determine whether an Integer is a real square or not. During my research I found this question at SOF:
Fastest way to determine if an integer's square root is an integer
I'm compareably new to the Programming scene. When testing the different Algorithms that are presented in the question, I found out that this one
bool istQuadratSimple(int64 x)
{
int32 tst = (int32)sqrt(x);
return tst*tst == x;
}
actually works faster than the one provided by A. Rex in the Question I posted. I've used an NS-Timer object for this testing, printing my results with an NSLog.
My question now is: How is speed-testing done in a professional way? How can I achieve equivalent results to the ones provided in the question I posted above?
The problem with calling just this function in a loop is that everything will be in the cache (both the data and the instructions). You wouldn't measure anything sensible; I wouldn't do that.
Given how small this function is, I would try to look at the generated assembly code of this function and the other one and I would try to reason based on the assembly code (number of instructions and the cost of the individual instructions, for example).
Unfortunately, it only works in trivial / near trivial cases. For example, if the assembly codes are identical then you know there is no difference, you don't need to measure anything. Or if one code is like the other plus additional instructions; in that case you know that the longer one takes longer to execute. And then there are the not so clear cases... :(
(See the update below.)
You can get the assembly with the -S -emit-llvm flags from clang and with the -S flag from gcc.
Hope this help.
UPDATE: Response to Prateek's question in the comment "is there any way to determine the speed of one particular algorithm?"
Yes, it is possible but it gets horribly complicated REALLY quick. Long story short, ignoring the complexity of modern processors and simply accumulating some predefined cost associated with the instructions can lead to very very inaccurate results (the estimate off by a factor of 100, due to the cache and the pipeline, among others). If you try take into consideration the complexity of the modern processors, the hierarchical cache, the pipeline, etc. things get very difficult. See for example Worst Case Execution Time Prediction.
Unless you are in a clear situation (trivial / near trivial case), for example the generated assembly codes are identical or one is like the other plus a few instructions, it is also hard to compare algorithms based on their generated assembly.
However, here a simple function of two lines is shown, and for that, looking at the assembly could help. Hence my answer.
I am not sure if there is any professional way of checking the speed (if there is let me know as well). For the method that you directed to in your question I would probably do something this this in java.
package Programs;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class SquareRootInteger {
public static boolean isPerfectSquare(long n) {
if (n < 0)
return false;
long tst = (long) (Math.sqrt(n) + 0.5);
return tst * tst == n;
}
public static void main(String[] args) {
long iterator = 1;
int precision = 10;
long startTime = System.nanoTime(); //Getting systems time before calling the isPerfectSquare method repeatedly
while (iterator < 1000000000) {
isPerfectSquare(iterator);
iterator++;
}
long endTime = System.nanoTime(); // Getting system time after the 1000000000 executions of isPerfectSquare method
long duration = endTime - startTime;
BigDecimal dur = new BigDecimal(duration);
BigDecimal iter = new BigDecimal(iterator);
System.out.println("Speed "
+ dur.divide(iter, precision, RoundingMode.HALF_UP).toString()
+ " nano secs"); // Getting average time taken for 1 execution of method.
}
}
You can check your method in similar fashion and check which one outperforms other.
Record the time value before your massive calculation and the value after that. The difference is the time executed.
Write a shell script where you will run the program. And run 'time ./xxx.sh' to get it's running time.

I have a .mp3 file. How can I seperate the human voice from the rest of the sound in C?

Is it even possible in C [I know it is possible in general -GOM player does it]? just let me get started... What do you say?
How exactly do you identify human voice distinguished from other sounds?
Filters in mp3 players usually rely on the fact that the voice source (the performer) in a stereo recording studio is positioned at the center. So they just compute the difference between the channels. If you give them a recording where the performer is not positioned like that they fail - the voice is not extracted.
The reliable way is employing a voice detector. This is a very complex problem that involves hardcore math and thorough tuning of the algorithms for your specific task. if you go this way you start with reading on voice coding (vocoders).
This exact topic was discussed here. It started out as a discussion of audio coding technologies, but on the linked page above someone said
That means no way to extract voice form steoro signal?
But it was pointed out that extracting the voice should be no more difficult than eliminating the voice.
I'll let you read further, but I suspect successful extraction may rely on the relatively narrow spectral distribution of the voice compared to instruments.
Note that it is not possible in principle to perfectly separate different sounds which are mixed together in one track. It's like when you mix cream into your coffee - after it has been mixed in, it isn't possible to perfectly separate the cream and the coffee afterwards.
There might be smart signal processing tricks to get an acceptable result, but in general it's impossible to perfectly separate out the voice from the music.
Seperating the human voice from other sounds is no mean feat. If you have a recording of the other sounds then you can reference cancel the background sound which will leave you with the human voice.
If the background noise is random noise of some sort you will get a win by using some form of spectral filtering. But its not simple and would need a fair bit of playing with to get good results. Adobe Audition has an adaptive spectral filter i believe ...
Assume you have white noise with a fairly even frequency distribution across the entire recorded band (on a 44Khz uncompressed recording you are talking about 0 to 22Khz). Then add a voice on it. Obviously the voice is using the same frequencies as the noise. The human voice ranges from ~300Hz to ~3400Hz. Obviously bandpassing the audio will cut you down to only the voice range of 300 to 3400Hz. Now what? You have a voice AND you have the, now bandpassed, white noise. Somehow you need to be able to remove that noise and leave the voice in tact. There are various filtering schemes but all will damage the voice in the process.
Good luck, its really not gonna be simple!
Look up Independent Component Analysis (ICA)
Where buf has the pcm wav 44100 sample rate input data
int
voiceremoval (char *buf, int bytes, int bps, int nch)
{
short int *samples = (short int *) buf;
int numsamples = 0;
int x = 0;
numsamples = bytes / 2;
x = numsamples;
if (bps == 16)
{
short *a = samples;
if (nch == 2)
while (x--)
{
int l, r;
l = a[1] - a[0];
r = a[0] - a[1];
if (l < -32768)
l = -32768;
if (l > 32767)
l = 32767;
if (r 32767)
r = 32767;
a[0] = -l;
a[1] = r;
a += 2;
}
}
return 0;
}

Resources