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
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);
|
|
|
|
|