17

W ramach projektu zabawy w domu, próbuję znaleźć sposób na zredukowanie/przekonwertowanie piosenki do buczenia jak sygnał audio (podstawowa melodia, którą my, ludzie, postrzegamy, gdy słuchamy piosenki). Zanim przejdę dalej opisując moją próbę rozwiązania tego problemu, chciałbym wspomnieć, że jestem całkowicie nowy w analizie dźwięku, chociaż mam duże doświadczenie w analizowaniu obrazów i filmów.Jak przekonwertować ścieżkę tonacji z algorytmu wyodrębniania melodii na brzęczenie jak sygnał dźwiękowy?

Po trochę google, znalazłem kilka algorytmów ekstrakcji melodii. Biorąc pod uwagę polifoniczny sygnał dźwiękowy utworu (np. Plik .wav), wyprowadzają ścieżkę tonacji - w każdym momencie oceniają dominującą tonację (pochodzącą od głosu wokalisty lub jakiegoś instrumentu generującego melodię) i śledzą dominującą nachylenie w czasie.

Przeczytałem kilka artykułów i zdają się obliczać transformatę Fouriera utworu, a następnie przeprowadzić analizę spektrogramu, aby uzyskać i śledzić dominujący ton. Wyodrębnianie melodii jest tylko częścią systemu, który próbuję rozwijać, więc nie mam nic przeciwko używaniu jakiegokolwiek algorytmu, który jest dostępny, o ile wykonuje przyzwoite zadanie na moich plikach audio i kod jest dostępny. Ponieważ jestem na tym początku, chętnie usłyszę wszelkie sugestie na temat tego, które algorytmy działają dobrze i gdzie mogę znaleźć jego kod.

znalazłem dwa algorytmy:

  1. Yaapt pitch tracking
  2. Melodia

Wybrałem Melodia jak wyniki na różnych gatunkach muzycznych wyglądał całkiem imponujące. Proszę sprawdzić this to see its results. Brzęczenie, które słyszysz dla każdego utworu jest w istocie tym, co mnie interesuje.

"To pokolenie tego nucenia dla jakiejkolwiek arbitralnej piosenki, z którą chcę ci pomóc w tym pytaniu".

Algorytm (dostępny jako wtyczka dla wampirów) wyświetla ścieżkę tonacji --- [time_stamp, wysokość/częstotliwość] --- macierz Nx2, w której w pierwszej kolumnie znajduje się znacznik czasu (w sekundach) i sekunda kolumna jest wykrywana dominującym tonem w odpowiednim znaczniku czasu. Poniżej pokazano wizualizację ścieżki dźwiękowej uzyskanej z algorytmu nałożonego na fioletowy kolor z sygnałem w dziedzinie czasu piosenki (powyżej) i spektrogramu/krótkiego czasu-czwartego. Wartości ujemne skoku/częstotliwości reprezentują algorytmy oceny dominującego skoku dla segmentów nie-dźwięcznych/nie-melodycznych. Więc wszystkie oceny pochylenia> = 0 odpowiadają melodii, reszta nie jest dla mnie ważna.

Pitch-track overlay with a song's waveform and spectrogram

Teraz chcę przekonwertować ten odstęp ścieżek z powrotem do brzęczenia jak sygnału audio - podobnie jak autorzy mają go na swojej stronie internetowej.

Poniżej znajduje się funkcja MATLAB, że napisałem to zrobić:

function [melSignal] = melody2audio(melody, varargin) 
% melSignal = melody2audio(melody, Fs, synthtype) 
% melSignal = melody2audio(melody, Fs) 
% melSignal = melody2audio(melody) 
% 
% Convert melody/pitch-track to a time-domain signal 
% 
% Inputs: 
% 
%  melody - [time-stamp, dominant-frequency] 
%   an Nx2 matrix with time-stamp in the 
%   first column and the detected dominant 
%   frequency at corresponding time-stamp 
%   in the second column. 
% 
%  synthtype - string to choose synthesis method 
%  passed to synth function in synth.m 
%  current choices are: 'fm', 'sine' or 'saw' 
%  default='fm' 
% 
%  Fs - sampling frequency in Hz 
%  default = 44.1e3 
% 
% Output: 
% 
%  melSignal -- time-domain representation of the 
%     melody. When you play this, you 
%     are supposed to hear a humming 
%     of the input melody/pitch-track 
% 

    p = inputParser; 
    p.addRequired('melody', @isnumeric); 
    p.addParamValue('Fs', 44100, @(x) isnumeric(x) && isscalar(x)); 
    p.addParamValue('synthtype', 'fm', @(x) ismember(x, {'fm', 'sine', 'saw'})); 
    p.addParamValue('amp', 60/127, @(x) isnumeric(x) && isscalar(x)); 
    p.parse(melody, varargin{:}); 

    parameters = p.Results; 

    % get parameter values 
    Fs = parameters.Fs; 
    synthtype = parameters.synthtype; 
    amp = parameters.amp; 

    % generate melody 
    numTimePoints = size(melody,1); 
    endtime = melody(end,1); 
    melSignal = zeros(1, ceil(endtime*Fs)); 

    h = waitbar(0, 'Generating Melody Audio'); 

    for i = 1:numTimePoints 

     % frequency 
     freq = max(0, melody(i,2)); 

     % duration 
     if i > 1 
      n1 = floor(melody(i-1,1)*Fs)+1; 
      dur = melody(i,1) - melody(i-1,1); 
     else 
      n1 = 1; 
      dur = melody(i,1);    
     end 

     % synthesize/generate signal of given freq 
     sig = synth(freq, dur, amp, Fs, synthtype); 

     N = length(sig); 

     % augment note to whole signal 
     melSignal(n1:n1+N-1) = melSignal(n1:n1+N-1) + reshape(sig,1,[]); 

     % update status 
     waitbar(i/size(melody,1)); 

    end 

    close(h); 

end 

Podstawowym logika tego kodu jest następujący: w każdym czasie znaczek, ja syntezy falę krótkotrwały (słownie sine -fala) z częstotliwością równą wykrytej dominującej częstotliwości/częstotliwości w tym znaczniku czasu przez czas równy jej luce z następnym znacznikiem czasu w macierzy melodii wejściowych. Zastanawiam się tylko, czy robię to dobrze.

Następnie biorę sygnał dźwiękowy, który otrzymuję z tej funkcji i odtwarzam z oryginalnym utworem (melodia na lewym kanale i oryginalna piosenka na prawym kanale).Chociaż wygenerowany sygnał dźwiękowy wydaje się dość dobrze segmentować źródła generujące melodię (głos/ołów-instrument) - jego aktywny głos jest wszędzie i zero wszędzie - sam sygnał daleki jest od brzęczenia (dostaję coś w stylu Beep Beep Beeeeep Beep Beep Beeeeeeeep), które autorzy pokazują na swojej stronie internetowej. Poniżej znajduje się wizualizacja pokazująca sygnał w dziedzinie czasu wejściowej piosenki na dole i sygnał w domenie czasu melodii wygenerowanej za pomocą mojej funkcji.

enter image description here

Jeden główny problem jest - chociaż ja biorąc pod uwagę częstotliwość fali do generowania w każdym czasie znaczek, a także czas trwania, nie wiem jak ustawić amplitudę fali. Na razie ustawiłem amplitudę na płaską/a-stałą wartość i podejrzewam, że to jest problem.

Czy ktoś ma jakieś sugestie na ten temat? Z zadowoleniem przyjmuję sugestie w dowolnym języku programowania (najlepiej MATLAB, python, C++), ale myślę, że moje pytanie tutaj jest bardziej ogólne --- Jak generować falę przy każdym znaczniku czasu?

Kilka pomysłów/poprawki w moim umyśle:

  1. ustawiona amplituda przez coraz uśrednionego/max szacunkową wartość amplitudy z sygnału w dziedzinie czasu oryginalnego utworu.
  2. Całkowicie zmień moje podejście --- oblicz spektrogram/krótkoterminową fourierową transformację sygnału audio utworu. odcinanie prawie/zero-out lub cicho wszystkie inne częstotliwości, z wyjątkiem tych w mojej pitch-track (lub są zbliżone do mojego pitch-track). Następnie obliczyć odwrotną krótkoterminową transformatę Fouriera, aby uzyskać sygnał w dziedzinie czasu.
+0

Możesz stworzyć midi, który ma takie same wysokości/pochylenia/czasy/czasy, co twoja melodia, wybierz odpowiedni instrument i wyrenderuj go w wybranym programie/bibliotece. alternatywnie, można było nadać każdej nucie obwiednię amplitudy, która zaczyna się silnie (albo buduje się od zera szybko, albo zaczyna silny), zmniejsza się do trzymanej w milczeniu ilości i kończy na końcu. Nazywa się to kopertą ADSR. – Patashu

+0

Jakoś mój nowy stolik jako projekt domowy nie jest imponujący. -1 za sprawienie, że poczułam się jak Igor jaskiniowiec (tylko żartuję). –

Odpowiedz

2

Chociaż nie mam dostępu do funkcji synth(), w zależności od parametrów, które należy wykonać, powiedziałbym, że problem polega na tym, że nie obsługujesz fazy.

To znaczy - nie wystarczy scalić fragmenty przebiegu razem, należy upewnić się, że mają ciągłą fazę. W przeciwnym razie tworzysz nieciągłość w przebiegu za każdym razem, gdy łączysz dwa fragmenty przebiegu. Jeśli tak, przypuszczam, że przez cały czas słyszysz tę samą częstotliwość i brzmi to bardziej jak piłokształtny niż sinusoidę - czy mam rację?

Rozwiązaniem jest ustawienie początkowej fazy urywka n do końcowej fazy fragmentu n-1. Oto przykład jak można złączyć dwa przebiegi o różnych częstotliwościach bez tworzenia nieciągłości fazy:

fs = 44100; % sampling frequency 

% synthesize a cosine waveform with frequency f1 and starting additional phase p1 
p1 = 0; 
dur1 = 1; 
t1 = 0:1/fs:dur1; 

x1(1:length(t1)) = 0.5*cos(2*pi*f1*t1 + p1); 

% Compute the phase at the end of the waveform 
p2 = mod(2*pi*f1*dur1 + p1,2*pi); 

dur2 = 1; 
t2 = 0:1/fs:dur2; 
x2(1:length(t2)) = 0.5*cos(2*pi*f2*t2 + p2); % use p2 so that the phase is continuous! 

x3 = [x1 x2]; % this should give you a waveform without any discontinuities 

Należy zauważyć, że podczas gdy ten daje ciągły przebieg, przejście częstotliwości jest natychmiastowa. Jeśli chcesz, aby częstotliwość stopniowo zmieniała się z time_n do time_n + 1, musiałbyś użyć czegoś bardziej złożonego, jak interpolacja McAulay-Quatieri. Ale w każdym razie, jeśli twoje fragmenty są wystarczająco krótkie, powinno to brzmieć wystarczająco dobrze.

Jeśli dobrze rozumiem, twoim celem jest słuchanie sekwencji częstotliwości, a nie jej brzmienie. W tym przypadku amplituda nie jest tak ważna i można ją naprawić.

Jeśli chcesz, aby brzmiało jak oryginalne źródło, to zupełnie inna historia i prawdopodobnie poza zakresem tej dyskusji.

Mam nadzieję, że to odpowie na twoje pytanie!

+0

@justin wielkie dzięki za rozwiązanie. To był rzeczywiście problem i po naprawie brzmi to znacznie lepiej. Ale czuję, że muszę wprowadzić lepszą amplitudę, aby była bardziej realistyczna, ale nieco poza zasięgiem mojego pytania w tym poście. Czytam, że postrzegana amplituda zależy od częstotliwości (wyższa częstotliwość, wyższa postrzegana amplituda). Zastanawiam się, czy mogę znaleźć jakiś model matematyczny dla tej zależności, więc mogę zmienić amplitudę na podstawie dominującego skoku/częstotliwości. Może to zabrzmi jeszcze lepiej. – cdeepakroy

+0

Możesz również rozwinąć interpolację McAulaya-Quatieri lub wskazać mi prostszy artykuł - wciąż słyszę jakieś huczenie w punkcie, w którym sygnał przechodzi z dźwięcznego na bezdźwięczny, nawet po zastosowaniu wygładzenia. – cdeepakroy

+1

Zmiana amplitudy sinusoidy tylko nieznacznie różni się od postrzeganego realistycznego (to jest słowa?) Zsyntetyzowanego sygnału - nadal będzie w zasadzie brzmieć jak pojedyncza sinusoida.Jeśli chcesz, aby brzmiało jak oryginalne źródło, masz dwie możliwości: albo uzyskaj syntezator dla swojego źródła (głosu/instrumentu) i użyj sekwencji f0 do kierowania syntezą lub użyj algorytmu separacji źródła zamiast algorytmu estymacji f0 aby bezpośrednio oddzielić sygnał od źródła sygnału (przynajmniej próbuj to zrobić, to wciąż jest otwarty problem badawczy). – jjs

5

Jeśli dobrze rozumiem, wydaje się, że masz już dokładną reprezentację boiska, ale Twoim problemem jest to, że to, co generujesz, nie brzmi "wystarczająco dobrze".

Zaczynając od twojego drugiego podejścia: odfiltrowanie czegokolwiek oprócz boiska nie doprowadzi do niczego dobrego. Usuwając wszystko poza kilkoma przedziałami częstotliwości odpowiadającymi lokalnym oszacowaniom wysokości tonu, tracisz tekst sygnału wejściowego, co sprawia, że ​​brzmi dobrze. W rzeczywistości, jeśli wziąłbyś to do ekstremum i usunąłeś wszystko poza jedną próbką odpowiadającą wysokości i wziął ifft, dostałeśby dokładnie sinusoidę, która jest co robisz obecnie. Jeśli jednak chcesz to zrobić, polecam wykonać to wszystko przez zastosowanie filtru do sygnału czasowego, a nie wchodzenie i wychodzenie z domeny częstotliwości, co jest droższe i bardziej kłopotliwe. Filtr miałby niewielkie ograniczenie częstotliwości, które chcesz zachować, a to pozwoliłoby uzyskać dźwięk o lepszej teksturze.

Jednakże, jeśli masz już szacunkowe wartości nachylenia i czasu trwania, z których jesteś zadowolony, ale chcesz poprawić jakość renderowania dźwięku, sugeruję, abyś po prostu zamienił swoje fale sinusoidalne - które zawsze będą brzmiały jak głupi sygnał dźwiękowy nie ważne, jak bardzo je masujesz - z pewnymi próbkami (lub skrzypcami lub fletem lub cokolwiek chcesz) próbkami dla każdej częstotliwości w skali. Jeśli pamięć jest problemem lub jeśli utwory, które reprezentujesz, nie mieszczą się w dobrze hartowanej skali (na przykład myślenie o środkowo-wschodnim pieśni), zamiast brzęczącej próbki dla każdej nuty skali, możesz mieć tylko brzęczące próbki dla kilka częstotliwości. Następnie można uzyskać szumiący dźwięk z dowolnej częstotliwości, wykonując konwersję częstotliwości próbkowania z jednej z tych brzęczących próbek. Pobranie kilku próbek do wykonania konwersji próbki umożliwiłoby wybranie tego, który pochyla się do "najlepszego" współczynnika z częstotliwością, którą trzeba wytworzyć, ponieważ złożoność konwersji próbkowania zależy od tego stosunku. Oczywiście dodanie częstotliwości próbkowania byłoby bardziej pracochłonne i wymagające obliczeniowo w porównaniu do posiadania banku próbek do wyboru.

Korzystanie z banku rzeczywistych próbek będzie miało duży wpływ na jakość renderowanych elementów. Pozwoli ci to również na realistyczne ataki na każdą nową melodię, którą grasz.

Następnie tak, jak sugerujesz, możesz również grać z amplitudą, podążając za chwilową amplitudą sygnału wejściowego, aby uzyskać bardziej złożony rendering utworu.

Wreszcie, zagrałbym również z oszacowaniem czasu trwania, tak abyś miał płynniejsze przejścia z jednego dźwięku do drugiego. Odgadywanie na podstawie wydajności pliku dźwiękowego, który bardzo mi się podobał (beep beep beep beepeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee) Można tego uniknąć, przedłużając szacunki czasu trwania, aby pozbyć się ciszy, która jest krótsza niż, powiedzmy .1 sekunda. W ten sposób zachowasz prawdziwe ciszy z oryginalnej piosenki, ale unikniesz odcięcia każdej nuty swojej piosenki.

+0

dziękuję za krytykę i sugestie. Chodziło o to, co wskazał salamon. Nie upewniłem się, że kolejne fale sinusoidalne podążają nieprzerwanie, wprowadzając między nimi ostrą nieciągłość. Tak więc sygnał nie brzmiał rytualnie. Po naprawie brzmi znacznie lepiej. – cdeepakroy

+0

W tangencjalnej notatce na temat zamiany fali sinusoidalnej na bardziej realistyczny sygnał za pomocą banku próbek z prawdziwego instrumentu --- jest taki zestaw próbek dostępnych lub istnieją modele matematyczne dla dowolnych instrumentów. Najwyraźniej to, co definiuje wyjątkowość dźwięku instrumentu, to podteksty lub harmoniczne - całkowite wielokrotności częstotliwości podstawowej. Czytałem, że jest to stosunek amplitud tych harmonicznych do częstotliwości podstawowej f, która charakteryzuje dźwięk instrumentu. tory pitch wydają się raczej kontinuum częstotliwości niż dyskretną nutą. – cdeepakroy

+0

@cdeepakroy Tak i nie. Tak, te wskaźniki, o których wspomniałeś, wydają się być podobne dla instrumentów tego samego typu, ale wciąż różnią się w zależności od konkretnego instrumentu, w obrębie każdej nuty i od tego, jak mocno lub delikatnie gra nuta. I tak energia ma tendencję do gromadzenia się wokół wielokrotności całkowitych częstotliwości podstawowej, ale w żaden sposób nie może być łatwo zredukowana do nich: ta ilustracja mówi sama za siebie: http://kozco.com/tech/audacity/piano_G1.jpg. Jeśli więc nie ma banku próbek, dodanie harmonicznych na pewno będzie brzmiało lepiej, ale pozostanie dalekie od naturalnego brzmienia. – Lolo

1

Masz co najmniej 2 problemy.

Po pierwsze, jak przypuszczałeś, twoja analiza wyrzuciła całą informację o amplitudzie części melodycznej pierwotnego widma. Będziesz potrzebował algorytmu, który przechwyci te informacje (a nie tylko amplitudę całego sygnału dla polifonicznego sygnału wejściowego lub tylko z pola tonalnego FFT dla wszystkich naturalnych dźwięków muzycznych). Jest to nietrywialny problem, gdzieś pomiędzy ekstrakcją smoły melodycznej i rozdzielaniem ślepego źródła.

Po drugie, dźwięk ma barwę, w tym tony dźwiękowe i koperty, nawet ze stałą częstotliwością. Twoja metoda syntezy tworzy tylko jedną falę sinusoidalną, podczas gdy buczenie prawdopodobnie tworzy kilka ciekawszych podtekstów, w tym wiele wyższych częstotliwości niż tylko wysokość dźwięku. Aby uzyskać nieco bardziej naturalny dźwięk, można spróbować przeanalizować spektrum siebie nucąc pojedynczy ton i spróbować odtworzyć wszystkie te dziesiątki sinusoidalnych fal dźwiękowych zamiast jednego, każdy o odpowiedniej względnej amplitudzie, podczas syntezy każdego znacznika czasu w twojej analizie. Możesz także spojrzeć na obwiednię amplitudy w czasie, gdy nucisz jedną krótką nutę i użyć tej koperty do modulowania amplitudy twojego syntezatora.

+0

była ciekawa propozycja przeanalizowania spektrum mnie/człowieka nuciącego pojedynczy ton. Ale wierzę, że mogę to zrobić tylko dla nut w kilku oktawach i przeanalizować je. Wtedy będę potrzebował modelu matematycznego, który pozwoli mi uzyskać (poprzez interpolację lub ekstrapolację) sygnał na dowolnej ciągłej częstotliwości, co wydaje mi się na podstawie tonu ścieżki algorytmu ekstrakcji melodii. Czy istnieje taki matematyczny model? Jestem nowa w tej dziedzinie, więc byłoby pomocne, gdybyś mógł wskazać mi taką literaturę. – cdeepakroy

+0

Literatura na temat formantów wokalnych może obejmować niektóre modele, które możesz chcieć wypróbować. – hotpaw2

Powiązane problemy