音樂評分系統MATLAB仿真

分別提取演唱者音頻與模版音頻的特徵參數,通過特徵參數的差值得到演唱得分。

源碼分三個部分:
1. main.m
主文件,運行入口
音頻的讀入,對基音特徵進行分段DTW,根據DTW的結果計算得分
計算方式爲:(cos((pl/tpl)*pi)+1)*50
其中,pl爲待評分音頻的結果 tpl爲對照音頻的結果
2. solve.m
基音特徵提取函數
流程:
預加重->分幀->加窗->求短時平均能量->求自相關(求基音)
主要參數:
ek :高頻提升參數
L :幀長(ms)
RL :幀移(ms)
kee:清濁音閾值
調整參數可以調整系統的整體特性以適應不同需求
3. DTW.m
動態時間規整函數
N^2複雜度,分段加快處理速度


%main.m
%西安電子科技大學 windroid
clear all;
%默認音源已提前進行統一化處理
%讀取數據
file1 = 'C:\Users\97628\Desktop\音樂\music\暗香0.wma';
file2 = 'C:\Users\97628\Desktop\音樂\music\暗香1.wma';
[e1,Fs1] = audioread(file1);
[e2,Fs2] = audioread(file2);

f1 = solve(e1, Fs1);
f2 = solve(e2, Fs2);

figure(1);
subplot(211);plot(f1);title('file1基音頻率');xlabel('幀數');ylabel('幅度');
subplot(212);plot(f2);title('file2基音頻率');xlabel('幀數');ylabel('幅度');

%DTW是爲了小範圍擬合 所以輸入的音頻需要提前對齊
%DTW -> n^2算法
%按幀分段
D = 100;
pl = 0;
for i=1:D:min(length(f1), length(f2))-D
    pl = pl + DTW(f1(:,i:i+D), f2(:,i:i+D));
end
%空對照組
tpl = 0;
zf = zeros(1, length(f2));
for i=1:D:min(length(f1), length(zf))-D
    tpl = tpl + DTW(f1(:,i:i+D), zf(:,i:i+D));
end

if(tpl<pl)
    info = '音源差距太大,無法評分'
else
    %滿分100
    %正弦曲線
    score = (cos((pl/tpl)*pi)+1)*50
end

%solve.m
function f = solve(e, Fs)
%e:音頻數據; Fs:採樣率
%返回基音頻率 列向量
%
%函數過程:
%   預加重->分幀->加窗->求短時平均能量->求自相關(求基音)
%關鍵參數:
%   ek L RL kee
%西安電子科技大學 windroid

%預加重
ek = -0.98; %-1 ~ 0
e = filter([1,ek],1,e);  %un爲經過高頻提升後的時域信號
log = '預加重完成'
un = e;
%figure(1);plot(e);title('原始語音信號');xlabel('樣點數');ylabel('幅度');
%figure(2);plot(un);title('預加重後的語音信號');xlabel('樣點數');ylabel('幅度');

L = 30; % 幀長(ms)
RL = 20; % 幀移(ms)
t = length(e)*1000/Fs; % 時長(ms)
N = floor((t-L)/RL); % 幀數
ns = floor(Fs*L/1000); %幀採樣點數
rnl = floor(Fs*RL/1000); %幀移點數

un(length(un)+1:ceil(t/L)*ns, :) = 0; % 信號尾0擴充
su = size(un);
if su(2) == 2
    un = (un(:, 1) + un(:, 2))/2;
end

%分幀
e1 = zeros(N, ns);
for i = 1:1:N
    e1(i, :) = un((i-1)*rnl+1:(i-1)*rnl+ns, 1)';
end
%figure(3);plot(e1(100, :));title('分幀後的第100幀信號');xlabel('樣點數');ylabel('幅度');
log = '分幀完成'

%加窗
e2 = zeros(N, ns);
for i = 1:1:N
    e2(i, :) = e1(i, :).*(hamming(ns))';
end
%figure(5);plot(e2(100, :));title('加窗後的第100幀信號');xlabel('樣點數');ylabel('幅度');
%figure(6);plot(ee);title('加窗後的短時平均能量');xlabel('幀數');ylabel('能量');
log = '加窗完成'

%{
%削波
emax = max(abs(e2'))';%中心削波
t = 0.7;
e3 = zeros(N, ns);
for i = 1:1:N 
    for j = 1:1:ns
        tc = t*emax(i);
        if e2(i, j) > tc
            e3(i, j) = e2(i, j) - tc;
        elseif e2(i, j) < -tc
            e3(i, j) = e2(i, j) + tc;
        else
            e3(i, j) = 0;
        end
    end
end
%figure(7);plot(e3(100, :));title('中心削波後的第100幀信號');xlabel('樣點數');ylabel('幅度');

%TODO %三電平削波
%}
%{
%聲頻分離
LE = 1024;
t = zeros(LE, 1);
t(51:950, 1) = hanning(900);
ef = zeros(N, LE);
for i= 1:1:N
    fe = fft(e1(i, :), LE);
    fe = fe.*(t');
    ef(i,:) = ifft(fe, LE);
end
%}

%短時平均能量
ee = sum(e1.^2, 2)';
ne = sum(ee)/N;

%figure(8);
%subplot(211);plot(ee);title('短時平均能量');xlabel('幀數');ylabel('能量');

log = '正在求基音'
%求自相關
LE = ns;
re = e2;
tR = zeros(1, N);
kee = 1;%閾for i = 1:1:N
    if ee(:, i) < kee*ne
        continue
    end
    R = zeros(1, LE);
    for k = 1:1:LE
        for t = 1:1:LE-k
            R(1, t) = R(1, t) + re(i, t)*re(i, t + k);
        end
    end
    [~ ,tR(1, i)] = max(R);
end
%subplot(212);plot(tR);title('基音頻率');xlabel('幀數');ylabel('幅度');

f = tR;

%DTW.m
function dist = DTW(t,r)
%西安電子科技大學 windroid
%參考:http://www.cnblogs.com/luxiaoxun/archive/2013/05/09/3069036.html
%↑鏈接代碼有問題
n = length(t);
m = length(r);
% 幀匹配距離矩陣
d = zeros(n,m);
for i = 1:n
    for j = 1:m
        d(i,j) = (t(:,i)-r(:,j))^2;
    end
end
% 累積距離矩陣
D = ones(n,m) * realmax;
D(1,1) = d(1,1);

log = '正在DP'
% 動態規劃
for i = 1:n
    for j = 1:m
        if i>1
            D1 = D(i-1,j);
            if j>1
                D2 = D(i-1,j-1);
                D3 = D(i,j-1);
            else
                D2 = realmax;
                D3 = realmax;
            end
        else
            D1 = realmax;
            D2 = realmax;
            if j>1
                D3 = D(i,j-1);
            else
                %D3 = realmax;
                %此時 i == 1 && j == 1
                D(i, j) = d(i, j);
                continue
            end
        end
        D(i,j) = d(i,j) + min(min(D1,D2),D3);
    end
end
dist = D(n,m);

測試音頻結果:


預加重


分幀加窗


短時平均能量


短時平均能量與基音頻率的關係


基音頻率對比


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章