Engineering School, 2nd year
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

198 lines
6.0 KiB

function outSamples = beatTracking1(fileName)
// Read samples
[samples sampleFreq nBits] = wavread(fileName);
// We keep only the first channel
samples = samples(1, :);
outSamples = samples;
// Computes size
[nChannels nSamples] = size(samples);
// Instant energy
instantEnergyWindow = 1024;
instantEnergies = nSamples / instantEnergyWindow;
// Average energy
averageEnergyWindow = 43;
averageEnergies = instantEnergies;
beatConstant = 1.3;
beatRatio = .01;
// Time arrays
t = [0 : nSamples - 1];
tEnergies = [0 : instantEnergies - 1] * instantEnergyWindow;
// Energies arrays
instantEnergy = zeros(1, instantEnergies);
averageEnergy = zeros(1, averageEnergies);
// Compute instant energy
for i = [0 : instantEnergies - 1],
tsum = 0;
for s = [(i * instantEnergyWindow) + 1: ((i + 1) * instantEnergyWindow)],
tsum = tsum + samples(s)^2;
end
instantEnergy(i + 1) = tsum;
end
// running windowed sum of instant energies
tmpEnergy = 0;
for i = [1 : averageEnergyWindow],
tmpEnergy = tmpEnergy + instantEnergy(i);
end
averageEnergy(1) = tmpEnergy;
for i = [2 : averageEnergies - averageEnergyWindow],
averageEnergy(i) = averageEnergy(i - 1) - instantEnergy(i - 1) + instantEnergy(i + averageEnergyWindow - 1);
end
for i = [averageEnergies - averageEnergyWindow + 1: averageEnergies],
averageEnergy(i) = averageEnergy(i - 1) - instantEnergy(i - 1);
end
// average the sum
averageEnergy = averageEnergy / averageEnergyWindow;
// computes the variance
energyVariance = zeros(averageEnergy);
for i = [1 : averageEnergies],
v = 0
for j = [i : i + averageEnergyWindow - 1],
if j <= instantEnergies then
v = v + (instantEnergy(j) - averageEnergy(i))^2;
end
end
energyVariance(i) = v;
end
energyVariance = sqrt(energyVariance);
// Computes the beat detection constants
beatConstants = -0.0025714 * energyVariance + 1.5142857;
// Compares the instant energies and the average energies
difference = instantEnergy - beatConstant * averageEnergy;
difference2 = instantEnergy - beatConstants .* averageEnergy;
// averages the difference
h = [.2 .2 .2 .2 .2];
filteredDifference = convol(h, difference);
filteredDifference = filteredDifference(3 : averageEnergies + 2);
filteredDifference2 = convol(h, difference2);
filteredDifference2 = filteredDifference2(3 : averageEnergies + 2);
// Ratio computation
ratio = zeros(instantEnergy);
for i = [1 : instantEnergies],
if averageEnergy(i) <> 0 then
ratio(i) = instantEnergy(i) / averageEnergy(i);
end
end
// Beat detection
beatIdx = 1;
beat = [];
for i = [1 : instantEnergies - 1],
//if (ratio(i) < beatRatio) & (ratio(i+1) > beatRatio) then
//if (filteredDifference(i) < 0) & (filteredDifference(i+1) > 0) then
if (filteredDifference(i) < 0) & (filteredDifference(i+1) > 0) then
//if (difference(i) < 0) & (difference(i+1) > 0) then
// draws a line
beat(beatIdx) = tEnergies(i);
beatIdx = beatIdx + 1;
end
end
beatIdx2 = 1;
beat2 = [];
for i = [1 : instantEnergies - 1],
//if (ratio(i) < beatRatio) & (ratio(i+1) > beatRatio) then
if (filteredDifference2(i) < 0) & (filteredDifference2(i+1) > 0) then
//if (difference(i) < 0) & (difference(i+1) > 0) then
// draws a line
beat2(beatIdx2) = tEnergies(i);
beatIdx2 = beatIdx2 + 1;
// put a beep (4000 Hz) in the signal
for j = [0 : sampleFreq / 100],
outSamples(tEnergies(i) + j) = .9 * sin(2 * %pi * (j * sampleFreq / 4000));
end
end
end
// Plotting...
scf(1);
subplot(2, 1, 1);
plot2d(t, samples, style=color('grey'));
for i = [1 : beatIdx - 1],
xsegs([beat(i) beat(i)], [.2 -.2], color('red'));
end
xtitle('Echantillons de ' + fileName , 'echantillons', 'amplitude');
subplot(2, 1, 2);
plot2d(tEnergies, instantEnergy, style=color('green'));
plot2d(tEnergies, averageEnergy, style=color('blue'));
xtitle('Energies de ' + fileName, 'echantillons', 'energie');
legend(['Energie instantanee', 'Energie moyenne'], 1, %t);
scf(2);
subplot(3, 1, 1);
plot2d(tEnergies, instantEnergy, style=color('green'));
plot2d(tEnergies, averageEnergy, style=color('blue'));
xtitle('Energies of ' + fileName, 'samples', 'energy');
legend(['Instant energy', 'Average energy'], 1, %t);
subplot(3, 1, 2);
plot2d(tEnergies, energyVariance, style=color('purple'));
xtitle('Energy variance of ' + fileName, 'samples', 'variance');
subplot(3, 1, 3);
plot2d(tEnergies, beatConstants, style=color('red'));
xtitle('Evolution of the beat detection constant of ' + fileName, 'samples');
scf(3);
subplot(2, 1, 1);
plot2d(tEnergies, difference, style=color('cyan'));
plot2d(tEnergies, filteredDifference, style=color('red'));
plot2d([tEnergies(1) tEnergies(instantEnergies)], [0 0]);
xtitle('Difference between instant and ' + string(beatConstant) + ' * average energies of ' + fileName, 'samples');
legend(['Difference', 'Average difference'], 1, %t);
subplot(2, 1, 2);
plot2d(tEnergies, difference2, style=color('cyan'));
plot2d(tEnergies, filteredDifference2, style=color('red'));
plot2d([tEnergies(1) tEnergies(instantEnergies)], [0 0]);
xtitle('Difference between instant and computed constant * average energies of ' + fileName, 'samples');
scf(4);
plot2d(tEnergies, ratio, style=color('orange'), logflag='nl');
plot2d([tEnergies(1) tEnergies(instantEnergies)], [beatRatio beatRatio]);
xtitle('Ratio between instant and average energies of ' + fileName, 'samples');
legend(['Ratio', 'Beat detection limit'], 4, %t);
scf(5);
subplot(3, 1, 1);
plot2d(t, samples, style=color('grey'));
for i = [1 : beatIdx - 1],
xsegs([beat(i) beat(i)], [.2 0], color('blue'));
end
for i = [1 : beatIdx2 - 1],
xsegs([beat2(i) beat2(i)], [-.2 0], color('red'));
end
xtitle('Echantillons de ' + fileName , '', 'amplitude');
subplot(3, 1, 2);
plot2d(tEnergies, filteredDifference, style=color('blue'));
plot2d([tEnergies(1) tEnergies(instantEnergies)], [0 0]);
xtitle('Difference lissee entre l`energie instantanee et ' + string(beatConstant) + ' * l`energie moyenne de ' + fileName);
subplot(3, 1, 3);
plot2d(tEnergies, filteredDifference2, style=color('red'));
plot2d([tEnergies(1) tEnergies(instantEnergies)], [0 0]);
xtitle('Difference lissee entre l`energie instantanee et C(i) * l`energie moyenne de ' + fileName);