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.
210 lines
5.2 KiB
210 lines
5.2 KiB
function outSamples = beatTrackingSEF(fileName)
|
|
|
|
// Spectrogramm filename
|
|
sgFile = fileName + '.sg';
|
|
if fileinfo(sgFile) == [] then
|
|
|
|
// Read samples
|
|
[x Fs nBits] = wavread(fileName);
|
|
|
|
// We keep only the first channel
|
|
x = x(1, :);
|
|
|
|
outSamples = x;
|
|
|
|
// Computes size
|
|
[nChannels nSamples] = size(x);
|
|
|
|
wlen = Fs / 100;
|
|
FFTSIZE = 512;
|
|
|
|
|
|
overlap = 2/3;
|
|
filter_order = 10; // must always be even
|
|
Nfen = wlen; // temporal analysis window length
|
|
Nover = round(Nfen*overlap); // overlap in samples
|
|
slen = 25e-3; // length in seconds for the widening
|
|
miniv = 1e-100;
|
|
minimo = 0.1;
|
|
medianSize = 150;
|
|
|
|
c = 0;
|
|
beatLimit = 0.5;
|
|
|
|
// calculate differentiator filter
|
|
m = calculate_differentiator(filter_order + 1);
|
|
|
|
// hop size in time
|
|
Nhop = Nfen - Nover;
|
|
Fns = Fs / Nhop;
|
|
|
|
// design of the low-pass smoothing IIR filter
|
|
alpha = 0.015;
|
|
betav = 0.075;
|
|
d = 5;
|
|
c = 1;
|
|
betav = betav * Fns;
|
|
alpha = alpha * Fns;
|
|
|
|
// SmootingFilter => low-pass smoothing IIR filter definition
|
|
s=%s;
|
|
num = [ d + c, -(c * exp(-1 / betav) + d * exp(-1 / alpha)) ];
|
|
den = [ 1, -(exp(-1 / alpha) + exp(-1 / betav)), exp(-(1 / alpha + 1 / betav)) ];
|
|
|
|
H_Smoothing = sum(num .* s^[size(num, 'c') - 1: -1 : 0]) / sum(den .* s^[size(den, 'c') - 1: -1 : 0]);
|
|
|
|
SmootingFilter = syslin('d', H_Smoothing);
|
|
|
|
// X_fm => spectral analysis
|
|
X_fm = specgram(Nover, FFTSIZE * 2, 'hn', x);
|
|
X_fm = X_fm( : , 1 : FFTSIZE); // we keep only one half of the spectrum
|
|
|
|
// G_fm1 => Smooting along the time axis
|
|
for i = [1 : FFTSIZE],
|
|
G_fm1(:, i) = abs(flts(abs(X_fm(:, i)'), SmootingFilter))';
|
|
end
|
|
|
|
// G_fm2 => log compression
|
|
G_fm2 = G_fm1;
|
|
G_fm2(G_fm2 == 0) = miniv;
|
|
G_fm2 = 20 * log10(G_fm2);
|
|
|
|
// First derivative
|
|
//H_m = [1, -1];
|
|
//for i = [1 : FFTSIZE],
|
|
// der1(:, i) = abs(convol(H_m, G_fm2( : , i)'))';
|
|
//end
|
|
|
|
H_der = sum(m .* s^[size(m, 'c') - 1: -1 : 0]);
|
|
derFilter = syslin('d', s * H_der / s);
|
|
for i = [1 : FFTSIZE],
|
|
der1( : , i) = abs(flts(G_fm2( : , i)', derFilter))';
|
|
end
|
|
ds = size(G_fm2, 'r') - size(der1, 'r');
|
|
der1 = [zeros(ds, FFTSIZE) ; der1];
|
|
der1(der1 < minimo) = 0; // remove small differentiation debris
|
|
|
|
// eliminate (?) differentiator filter transient
|
|
//der1 = der1($ - size(G_fm2, 'r') + 1 : $, : );
|
|
|
|
// Frequency integration
|
|
for i = [1 : size(der1, 'r')],
|
|
v_k(1, i) = sum(der1(i, : ));
|
|
end
|
|
|
|
//H_w = window('hn', 2 * slen * Fs + 1);
|
|
H_w = window('hn', 51);
|
|
H_w = H_w(26 : $);
|
|
wv_k = convol(H_w, v_k);
|
|
wv_k = wv_k(1 : size(v_k, 'c'));
|
|
bn = (~isinf(wv_k)) | (~isnan(wv_k)); // eliminate NaN and Inf if they exist
|
|
index = find(bn == %t);
|
|
wv_k2 = zeros(size(wv_k));
|
|
wv_k2(index) = wv_k(index);
|
|
|
|
g_k = zeros(1, size(wv_k2, 'c') + medianSize)
|
|
g_k(1, medianSize / 2 + 1 : $ - medianSize / 2) = wv_k2;
|
|
|
|
t_k = zeros(wv_k2);
|
|
for i = [medianSize / 2 + 1 : size(g_k, 'c') - medianSize / 2],
|
|
t_k(1, i - medianSize / 2) = c * median(g_k(1, i - medianSize / 2 : i + medianSize / 2));
|
|
end
|
|
|
|
p_k = wv_k2 - t_k;
|
|
p_k(p_k < 0) = 0;
|
|
|
|
// normalization
|
|
//E_fk = p_k / max(p_k);
|
|
|
|
//win_size = 150;
|
|
//E_fk = [p_k zeros(1, win_size)];
|
|
//for i = [1 : size(p_k, 'c')],
|
|
// E_fk(1, i) = E_fk(1, i) / max(E_fk(1, i : i + win_size - 1));
|
|
//end
|
|
//E_fk = E_fk(1 : size(p_k, 'c'));
|
|
E_fk = p_k;
|
|
|
|
win_size = 150;
|
|
m = [zeros(1, win_size / 2) p_k zeros(1, win_size / 2)];
|
|
for i = [1 : size(p_k, 'c')],
|
|
m(1, i) = mean(m(1, i : i + win_size - 1));
|
|
end
|
|
m = m(win_size / 2 + 1 : win_size / 2 + size(p_k, 'c'));
|
|
|
|
// Scales
|
|
ts = [0 : size(x, 'c') - 1] / Fs;
|
|
f = [0 : FFTSIZE - 1] / (2 * FFTSIZE);
|
|
t = [1 : size(X_fm, 'r')];
|
|
te = [0 : size(E_fk, 'c') - 1] * (size(x, 'c') / Fs) / size(E_fk, 'c');
|
|
tb = round(te * Fs) + 1;
|
|
|
|
// Beat detection
|
|
beatIdx = 1;
|
|
beat = [];
|
|
for i = [1 : size(E_fk, 'c') - 1],
|
|
if (E_fk(i) < m(i)) & (E_fk(i + 1) > m(i)) then
|
|
// draws a line
|
|
beat(beatIdx) = te(i);
|
|
beatIdx = beatIdx + 1;
|
|
|
|
// put a beep (4000 Hz) in the signal
|
|
for j = [0 : Fs / 100],
|
|
outSamples(tb(i) + j) = .9 * sin(2 * %pi * (j * Fs / 4000));
|
|
end
|
|
end
|
|
end
|
|
|
|
save(sgFile, X_fm, beat, beatIdx, E_fk, m, G_fm2, der1, te, ts, f, outSamples, x);
|
|
else
|
|
load(sgFile, 'X_fm', 'beat', 'beatIdx', 'E_fk', 'm', 'G_fm2', 'der1', 'te', 'ts', 'f', 'outSamples', 'x');
|
|
end
|
|
|
|
if input('graph [y/n]', 'string') <> 'y' then
|
|
return;
|
|
end
|
|
|
|
// Inversed gray colormap
|
|
cm = hotcolormap(128);
|
|
//cm = cm($:-1:1,:);
|
|
|
|
// Graph plotting
|
|
scf(0);
|
|
subplot(2, 1, 1);
|
|
xtitle('Samples of ' + fileName, 'time (s)', 'amplitude');
|
|
|
|
subplot(2, 1, 2);
|
|
xtitle('SEF of ' + fileName, 'time (s)', 'magnitude');
|
|
|
|
subplot(2, 1, 1);
|
|
plot2d(ts, x, style=color('grey'));
|
|
|
|
for i = [1 : beatIdx - 1],
|
|
xsegs([beat(i) beat(i)], [.2 -.2], color('red'));
|
|
end
|
|
|
|
subplot(2, 1, 2);
|
|
//plot2d([te(1) te($)], [beatLimit beatLimit], style=color('blue'));
|
|
plot2d(te, E_fk, style=color('red'));
|
|
plot2d(te, m, style=color('blue'));
|
|
|
|
if input('spectrogram [y/n]', 'string') <> 'y' then
|
|
return;
|
|
end
|
|
|
|
scf(1);
|
|
|
|
subplot(2, 1, 1);
|
|
xtitle('Smoothed & log compressed spectrogram of ' + fileName, 'time (s)', 'frequency');
|
|
xset("colormap", cm);
|
|
|
|
subplot(2, 1, 2);
|
|
xtitle('Derivated spectrogram of ' + fileName, 'time (s)', 'frequency');
|
|
xset("colormap", cm);
|
|
|
|
|
|
subplot(2, 1, 1);
|
|
grayplot(te(10 : $ - 10), f, G_fm2(10 : $ - 10, : ));
|
|
|
|
subplot(2, 1, 2);
|
|
grayplot(te(10 : $ - 10), f, der1(10 : $ - 10, : ));
|
|
|
|
|