3/24/2015

Pemisahan Suara menggunakan Binary Masking (BM)


Ketika berbicara di suatu tempat yang ramai, kita tetap bisa fokus pada apa yang disampaikan oleh lawan bicara meskipun suara yang terdengar tercampur dengan noise di sekitarnya. Mendengar dan fokus pada suara yang ingin kita dengar adalah hal yang mudah bagi kita, manusia. Namun, itu adalah hal yang rumit di signal processing. Banyak sekali penelitian terkait pemisahan suara yang bisa kita temukan melalui google (ketik saja "source separation") dan pada kesempatan ini, saya akan mengulas tentang pemisahan suara melalui simulasi dengan metode yang sangat sederhana yaitu Binary Masking. Pastikan anda telah membaca dan mencoba postingan sebelumnya terkait Short-Time Fourier Transform (STFT) sebelum melanjutkan bacaan ini karena metode yang akan kita buat ini menggunakan STFT.


Asumsikan kita mempunyai dua mikrofon (seperti halnya telinga manusia) dan suara-suara yang akan tercampur pada masing-masing mikrofon memiliki loudness yang berbeda-beda tergantung dari arah datang suara terhadap mikrofon. Coba bayangkan ketika seseorang di sebelah kanan kita sedang memanggil nama kita, tentu suara yang didengar oleh telinga kanan akan lebih keras dibandingkan dengan yang didengar oleh telinga kiri. Nah seperti itulah suara yang akan didengar oleh masing-masing mikrofon. Oleh karena itu, model pencampuran yang digunakan adalah fungsi dari arah datang suara yakni memenuhi persamaan di bawah ini.


dimana X adalah suara tercampur, S adalah suara asli, dan A adalah matrik pencampuran. A merupakan fungsi dari arah datang suara yakni



θi menunjukkan arah datang suara ke-i.


Tiga suara asli sebelum dicampur yang datang dari arah 0, 30 dan 150 derajat.

Suara yang direkam oleh Mik 1 dan Mik 2

Ingat pada asumsi di atas bahwa suara yang direkam oleh mikrofon 1 dan 2 akan memiliki loudness yang berbeda-beda tergantung dari arah datangnya terhadap mikrofon. Dengan informasi tersebut, kita dapat menggunakan persamaan di bawah ini untuk memisahkan suara yang tercampur tersebut.


dimana  Ø adalah fase (dalam derajat), x1 adalah rekaman mikrofon 1, dan x2 adalah rekaman mikrofon 2. Kemudian kita membuat histogram dari Ø.

Plot dari histogram Q setelah dinormalisasi

Puncak-puncak pada histogram mengindikasikan lokasi indek waktu dan frekuensi pada STFT dari X1 dan X2 dimana jika kita dapat mengambil bagian tersebut dan mengekstraknya kembali dari domain waktu-frekuensi ke domain waktu, maka kita akan mendapatkan suara-suara yang terpisah. Berikut persamaan yang digunakan



BM adalah binary masking, qi adalah puncak ke-i pada histogram, dan Δ adalah terkait rentang fase (Ø) yang mengindikasi indek waktu-frekuensi yang berisi hanya satu suara. Untuk memisahkan suara kita menggunakan persamaan di bawah ini.


dimana xest adalah suara estimasi.


Suara-suara estimasi

Berikut Code Octave yang digunakan dalam simulasi ini.

close all
clear
clc

% Membaca file wav
[s1 fs] = wavread('1.wav'); s1 = s1';
s2 = wavread('2.wav'); s2 = s2';
s3 = wavread('3.wav'); s3 = s3';
t = (0:length(s1)-1)/fs; t = t;
% Arah datang suara
q1 = 0;
q2 = 30;
q3 = 150;

% Matrix Pencampuran
A = [0.75-0.25*cos(q1) 0.75-0.25*cos(q2) 0.75-0.25*cos(q3); ...
  0.75+0.25*cos(q1) 0.75+0.25*cos(q2) 0.75+0.25*cos(q3)];
 
% Pencampuran Suara
X = A*[s1;s2;s3];

% Suara untuk masing-masing mikrofon
mic1 = X(1,:);
mic2 = X(2,:);
wavwrite(mic1',fs,'mic1.wav')
wavwrite(mic2',fs,'mic2.wav')

% STFT
nfft = 1024;
N = nfft/4;
Mic1 = stft_sin(mic1,N,nfft);
Mic2 = stft_sin(mic2,N,nfft);

% Phase
Phase = atan2(abs(Mic1),abs(Mic2))*180/pi;
[row col] = size(Phase);
PhaseReshape = reshape(Phase,1,row*col);
theta = linspace(0,90,200);
[yhist xhist] = hist(PhaseReshape,theta);
yhist = yhist/max(yhist);
plot(xhist,yhist,'k-','LineWidth',2)
xlim([0 90])
ylim([0 1.1])

% Temukan tiga puncak
n_peak = 3;
[pks loc] = findpeaks(yhist');
while length(pks) > 3
  pks(pks==min(pks)) = []; 
end
hold on, plot(xhist(loc),pks,'r^','LineWidth',2,'MarkerSize',10)

% Pemisahan
RangePhasePerkiraan = 3;
ndata = length(mic1);
for i = 1:length(loc)
  BM = (Phase < xhist(loc(i)) + RangePhasePerkiraan) & ...
          Phase > xhist(loc(i)) - RangePhasePerkiraan;
  if i == 1
    Temp = istft_sin(Mic1.*BM,N,ndata) + istft_sin(Mic2.*BM,N,ndata);
    SuaraEstimasi = zeros(3,length(Temp));
    SuaraEstimasi(i,:) = Temp;
  else
    Temp = istft_sin(Mic1.*BM,N,ndata) + istft_sin(Mic2.*BM,N,ndata);
    SuaraEstimasi(i,:) = Temp;
  end
end

s1_estimasi = SuaraEstimasi(1,:);
s2_estimasi = SuaraEstimasi(2,:);
s3_estimasi = SuaraEstimasi(3,:);
wavwrite(s1_estimasi',fs,'s1_new.wav')
wavwrite(s2_estimasi',fs,'s2_new.wav')
wavwrite(s3_estimasi',fs,'s3_new.wav')

% Plotting : Suara asli

figure
subplot(311)
plot(t,s1)
ylim([min(s1) max(s1)])
subplot(312)
plot(t,s2)
ylim([min(s2) max(s2)])
subplot(313)
plot(t,s3)
ylim([min(s3) max(s3)])

% Plotting : Suara yang direkam oleh mic 1 dan 2
figure
subplot(211)
plot(t,mic1)
subplot(212)
plot(t,mic2)

% Plotting : Suara Estimasi

figure
subplot(311)
plot(t,s1_estimasi),ylim([min(s1_estimasi) max(s1_estimasi)])
subplot(312)
plot(t,s2_estimasi),ylim([min(s2_estimasi) max(s2_estimasi)])
subplot(313)
plot(t,s3_estimasi),ylim([min(s3_estimasi) max(s3_estimasi)])

Kalian juga dapat mendownload code-nya pada link ini. Namun jangan lupa download code STFT pada postingan sebelumnya agar code di atas dapat dijalankan.

Selamat mencoba dan semoga bermanfaat.

No comments:

Post a Comment