Autor Wątek: Beat detection  (Przeczytany 3574 razy)

Offline P@tyS

  • Użytkownik
    • Patys coding

# Styczeń 29, 2015, 15:08:48
Witam,
Niestety bardzo mało znam się na muzyce, więc muszę was się poradzić. Tworzę grę (dokładnie ta: http://bitcoin-patys.rhcloud.com/download) i chciałbym aby bitcoiny i szurikeny spadały w rytm muzyki. Czyli jak jest 'uderzenie bitu' pojawia się nowy bitcoin/szuriken.

Potrzebuję czegoś w miarę cross-platform (windows i linux), ale nie chcę jakiś super zaawansownych bibliotek (coś lekkiego, wystarczy mi ten jeden feauture). Z tego co udało mi się znaleść, pod SFML nie dam rady tego zrobić (chyba, ale w API nie widzę potrzebnych funckcji). Muzykę mam w formacie mp3, ogg ewentualnie mogę wyeksportować to do innego, tyle że musi to być obsługiwany format, żebym mógł go odtworzyć w grze.

Co potrzebuję, by ten beat wykryć? Jakaś prosta biblioteka do tego? Jak to poźniej odtwarzać (przez SFML czy tą bibliotekę)?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline bluebat

  • Użytkownik

# Styczeń 29, 2015, 17:08:09
Beat w uproszczeniu to momenty, kiedy amplituda przekracza jakiś wyznaczony poziom. Możesz łatwo napisać toola, który będzie to liczył i zapisać z niego momenty beatu do pliku.
Mniej więcej schemat działania:
- zdekoduj sobie dźwięk do tablicy próbek.
- patrz na bloki próbek długości powiedzmy 1/30 sekundy.
- policz średnią amplitudę w bloku (w uproszczeniu: po wszystkich próbkach s, średnia z fabs(s)).
- eksperymentalnie dobieraj próg amplitudy A
- jeżeli w tym bloku średnia amplituda > A, a w poprzednim nie, to mamy beat.
- jak dobrze dobierzesz A, to beaty powinny się zgadzać i być tak często jak chcesz. Może być potrzeba ręcznie usunąć/dodać jakieś beaty, żeby lepiej pasowało do gry.

Offline P@tyS

  • Użytkownik
    • Patys coding

# Styczeń 29, 2015, 17:37:08
Dzięki za wytłumaczenie :D

Chciałbym to zrobić od razu w grze, bez dodatkowych plików itd.

Więc w sfml znalazłem, że po wczytaniu do sf::SoundBuffer mogę 'wybrać' sample (const Int16 *    getSamples () const : Get the array of audio samples stored in the buffer. ) i dalej w dokumentacji mam "A sample is a 16 bits signed integer that defines the amplitude of the sound at a given time." Więc biorę tą tablicę z samplami (w nich jest ta amplituda, tak?). Liczę z tego średnią itd. Rozumiem że jest 44100 sampli na sekundę, czyli obliczam z 1470 sampli średnią dla jednego bloku.

Cytuj
- jeżeli w tym bloku średnia amplituda > A, a w poprzednim nie, to mamy beat.
a jak w obu jest powyżej A?

Wszystko się zgadza?
« Ostatnia zmiana: Styczeń 29, 2015, 17:56:32 wysłana przez P@tyS »

Offline kubera

  • Użytkownik
    • Prywatna strona

# Styczeń 29, 2015, 18:21:24
Z góry napiszę, że nie jestem muzykiem :)
Przydatne mogą być BPM i takty.
Pierwsze to Bits per Minute. Takt to np. 4 uderzenia.
Nie musisz analizować do końca utworu. Co najwyżej nie zawsze trafisz.
Mierząc czas w jednostkach utworów możesz uzyskać ciekawy efekt.
A bossa możesz zrzucać wg tzw. frazy.

Muzyka jest w jakimś stopniu matematyczna i można na tym bazować.

P. S.
Ilość bpm można często zmierzyć zliczając uderzenia przez pół minuty, a potem mnożąc przez dwa.

Czyli wystarczy kilka liczb i pomiar czasu bez wnikania w sam utwór.

Pozdrawiam

Offline Gimer

  • Użytkownik
    • Portfolio

# Styczeń 29, 2015, 18:44:29
Powyższy sposób sprawdzi się tylko w techno albo tam gdzie bity występują co tę samą jednostkę czasu. Znacznie trafniej jest próbkować dźwięk i uzależnić fale wrogów od amplitudy.

Offline Karol

  • Użytkownik

  • +1
# Styczeń 29, 2015, 18:46:53
Więc biorę tą tablicę z samplami (w nich jest ta amplituda, tak?). Liczę z tego średnią itd. Rozumiem że jest 44100 sampli na sekundę, czyli obliczam z 1470 sampli średnią dla jednego bloku.
Najlepiej użyj BASS lub FMod i pobierz FFT, wtedy możesz analizować głośność wybranego zakresu częstotliwości - to w miarę prosty sposób i efektywny (beat najczęściej to niskie tony, prawie basowe, chyba, że celujesz też w kicki, haty i snary). Analizując głośność całego utworu będziesz miał wiele fałszywych wyników.

Offline Xender

  • Użytkownik

  • +1
# Styczeń 29, 2015, 23:13:03
No, wreszcie ktoś wspomniał o transformacie Fouriera (dokładniej FFT fragmentów o określonej długości, pewnie kilkaset milisekund).

Nie znam się szczególnie, ale się wypowiem, że brzmi sensownie[j], niż analiza pojedynczych próbek.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Styczeń 30, 2015, 00:39:39
Powyższy sposób sprawdzi się tylko w techno albo tam gdzie bity występują co tę samą jednostkę czasu.
Czyli w 99.9% muzyki. Zmiany tempa podczas utworu to naprawdę rzadkość. Już częściej bywa że w jakichś starszych kawałkach tempo się delikatnie rozjeżdża z uwagi na nagrywanie bez metronomu.

Cytuj
No, wreszcie ktoś wspomniał o transformacie Fouriera (dokładniej FFT fragmentów o określonej długości, pewnie kilkaset milisekund).

Nie znam się szczególnie, ale się wypowiem, że brzmi sensownie[j], niż analiza pojedynczych próbek.
Jeśli FFT, to na pewno nie okno na kilkaset milisekund, a max kilka/kilkanaście. W zależności od potrzeb wyjdzie z tego 64 do 512 próbek (od 1.45 do 11.6ms przy standardowym odtwarzaniu 44100smp/s).

Offline Dab

  • Redaktor
    • blog

  • +1
# Styczeń 30, 2015, 00:58:31
To nie jest takie proste jak może się początkowo wydawać. Mocno polecam do tego celu bibliotekę aubio: http://aubio.org/

Offline Lobsang Rampa

  • Użytkownik
    • Global Epidemic

# Styczeń 30, 2015, 10:11:36
Jeśli chodzi o samo uderzenie beatu, to osobiście na początek bym spróbował pociągnąć utwór mocnym filtrem dolnoprzepustowym a następnie analizował skoki amplitudy. Kawałek powinien też być wcześniej znormalizowany. Sam filtr najprościej wykonać za pomocą średniej kroczącej (każdą próbkę sygnału wyjściowego obliczamy jako średnią z "N" próbek pobranych z jej otoczenia w sygnale wejściowym). Ilością użytych próbek do uśredniania zmieniamy częstotliwość graniczną filtru.
« Ostatnia zmiana: Styczeń 30, 2015, 10:33:40 wysłana przez Lobsang Rampa »

Offline laggyluk

  • Użytkownik
    • http://laggyluk.com

# Styczeń 30, 2015, 11:43:03
też myślę że najlepiej wykrywać beat przefiltrowaną amplitudą, na jakimś sztywnym bpm nie ma co polegać. pomijając zmiany tempa to i tak się będzie rozjeżdżać

Offline P@tyS

  • Użytkownik
    • Patys coding

# Styczeń 30, 2015, 12:22:11
Jeżeli użyłbym FFT (np na podstawie tego: http://www.codeproject.com/Articles/9388/How-to-implement-the-FFT-algorithm) to mam porównać czy dany fragment jest większy: od poprzedniego, czy od średniej z tych fragmentów, czy na sztywno ustalić jakiś próg? Jeżeli tak to mamy beat?

Normalizację, filtry itd odpuszczę sobię, gdyż nie musi to być super dokładne. Wystarczy żeby 'czuło się' że wszystko idzie w rytm muzyki. :)

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

  • +1
# Styczeń 30, 2015, 12:49:44
Cytuj
Kawałek powinien też być wcześniej znormalizowany.
Nie widzę takiej potrzeby. Normalizacja przy analizie częstotliwości nie daje kompletnie nic.

Cytuj
na jakimś sztywnym bpm nie ma co polegać.
Ja na sztywnym BPM polegałem w każdym swoim demie/intrze (co ich trochę było) plus w jednej grze na IGK - z całkowitym sukcesem we wszystkich przypadkach.

Cytuj
pomijając zmiany tempa to i tak się będzie rozjeżdżać
Będzie się rozjeżdżać wyłącznie jak źle określisz tempo, albo je sobie zaokrąglisz. Czyli wszystkie detektory BPM "na stukanie" odpadają w przedbiegach. Zapytaj swojego muzyka o tempo każdego użytego utworu i jesteś w domu. Jeżeli nie masz takiej możliwości, weź dowolny program muzyczny lub do sampli, określ położenie pierwszego i ostatniego beatu, policz beaty pomiędzy, podziel i się zsynchronizuj na podstawie liczby/pozycji próbek (oczywiście niczego nie zaokrąglamy przy liczeniu i jedziemy na floatach).

Cytuj
mam porównać czy dany fragment jest większy: od poprzedniego, czy od średniej z tych fragmentów, czy na sztywno ustalić jakiś próg? Jeżeli tak to mamy beat?
Jeśli jest więcej od sąsiadów (oczywiście bierzemy pod uwagę wartości bezwzględne/długości wektorów), to znaczy że masz w tym miejscu lokalne maksimum. Do tego załóż sobie jakie jest maksymalne tempo które obsługujesz i wyjdzie Ci najkrótszy możliwy czas pomiędzy beatami. Z tego zakresu wybierasz maksymalny peak i prawdopodobnie jest to beat.

Oczywiście taki i podobne algorytmy najprawdopodobniej posypią się na większości breakdownów.

Offline Lobsang Rampa

  • Użytkownik
    • Global Epidemic

# Styczeń 30, 2015, 13:06:07
Nie widzę takiej potrzeby. Normalizacja przy analizie częstotliwości nie daje kompletnie nic.
Bez normalizacji (dotyczy to metody z filtrem), dla utworów o innych poziomie głośności trzeba będzie dobierać indywidualnie progi wywalania (wykrywanie skoków amplitudy). Próg wyzwalania prawdopodobnie i tak trzeba będzie w jakimś zakresie korygować w zależności od rodzaju utwory, ale nie będzie już na to wpływać ogólna głośność utworu.

Inna sprawa, że zazwyczaj kompresory dźwięku domyślnie normalizują kawałki, więc prawdopodobnie kawałek będzie już znormalizowany. Tym nie mniej dobrą praktyką w DSP jest normalizacja sygnałów dźwiękowych przed ich dalszym przetwarzaniem.
« Ostatnia zmiana: Styczeń 30, 2015, 13:10:07 wysłana przez Lobsang Rampa »

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Styczeń 30, 2015, 13:19:50
Cytuj
Bez normalizacji, dla utworów o innych poziomie głośności trzeba będzie dobierać indywidualnie progi wywalania (wykrywanie skoków amplitudy).
I tak będzie trzeba, bo zwykła normalizacja podciągnie ci tylko do największej amplitudy, która niekoniecznie może być beatem. No i beat beatowi nie równy, bo w tym samym kawałku na start możesz mieć cyki zamiast beatu, potem klasycznie na zmianę kick i kick+snare, a w breakdownie całość potraktowaną mocnym lowpassem albo w ogóle bez beatu. Jeden sztywny próg nie wystarczy ci nigdy - musisz dopasować się do danego fragmentu nagrania i szukać beatów w tym co tam znajdziesz.

Tym bardziej jeśli chcesz robić FFT, bo tam zamiast jednej amplitudy dostajesz kilkadziesiąt/kilkaset.

Cytuj
Inna sprawa, że zazwyczaj kompresory dźwięku domyślnie normalizują kawałki, więc prawdopodobnie kawałek będzie już znormalizowany.
Fakt. W komercyjnej muzyce praktycznie zawsze kawałki miksują pod linijkę, ale na szczęście nie zawsze. Ale całe szczęście, że robiąc muzykę do gry nie trzeba wpisywać się w ten trend i można zostawić sobie trochę miejsca na prawdziwą dynamikę.

Cytuj
Tym nie mniej dobrą praktyką w DSP jest normalizacja sygnałów dźwiękowych przed ich dalszym przetwarzaniem.
Dobrą praktyką to jest przejście z sygnałem na floaty (albo zgrywanie we floatach od razu) przed jakimkolwiek przetwarzaniem i trzymanie całości we floatach aż do ostatecznego masteringu. ;)

Ale jak masz już sygnał w 16bps, to na potrzeby gry nie ma co tego normalizować, bo stracisz możliwość spokojnego streamowania kawałka z dekodera mp3, czy czegokolwiek.