Donnerstag, 7. Juli 2011

Beats per Minute Detection

Beats per Minute ist wie der Name schon sagt eine Einheit, die Auskunft über die Schwebung oder besser den Rhythmus und damit auch indirekt über den Takt bzw. die Geschwindigkeit eines Songs gibt. Dieser Wert ist wichtig um die Geschwindigkeit zweier Musiktitel aneinander an zu passen. Langsamere Titel haben einen BPM-Wert von ca. 60 bis 80. Normale Pop-Songs liegen in der Regel um 120 bpm und Speed-Metal kann Werte bis 200 bpm aufweisen. Der schnellste Song der Welt ist Thousand von Moby und hat einen BPM-Wert von 1.000. Wir haben allerdings nicht den Anspruch auch solche Exoten zu analysieren.
Wie bereits erwähnt ist das aber in Flash nur auf Sound-Objekten möglich, bei denen keine Sandbox-Verletzungen vorliegen.
Beats sind Bässe - also Frequenzen im niedrigen Bereich bis maximal 120 Hz. Um diese Frequenzen aus einem Titel herauszufiltern bedarf es einer Art Spektral-Analyse. Die Fourier-Transformation errechnet aus einem Audio-Signal einzelne Sinus-Signale. Diese sind jeweils um einen Faktor in Höhe (Amplitude) und Breite (Zeit) gestreckt bzw. gestaucht. Je langsamer ein solches Sinussignal ist, desto tiefer ist der Sound.
Die Soundmixer-Klasse besitzt eine Funktion namens computeSpektrum(), der als Paramter ein Boolean-Wert übergegeben werden kann. Dieses Flag unterscheidet die Berechnung des Spektrums und ermöglicht die Nutzung eines in Flash eingebauten Algorithmus zur Fast Fourier Transformation (FFT). Da es aber aus Sandbox-Gründen und der Tatsache, dass die Soundmixer-Klasse nur einen globalen Kontext besitzt, nicht möglich ist diese Klasse zu verwenden und mussten wir andere Möglichkeiten in Betracht ziehen. Das Byte-Array, welches uns durch die Sound-Methode extract() zurückgegeben wird, beschreibt das komplexe Signal. Durch einige Frameworks von Dritt-Anbietern, die aus C++ adaptiert wurden, ist es möglich auch im Nachhinein diese FFT (sogar noch performanter als von Adobe) durchzuführen. Aber auch diese Algorithmen reichen uns leider nicht aus um die Berechnung in Echtzeit (während des Spielens eines Songs) auszuführen. Das SampleData-Event wird zu oft geworfen und würde man nicht jedes Sample berücksichtigen, läuft man Gefahr für die Berechnung wichtige Beats zu unterschlagen.
Der Alternative Lösungsweg ist Beats aus einem komplexen Signal ohne FFT zu errechnen. Die Erfahrung hat gezeigt, dass das langwellige Beat-Signal das komplette Signal dominiert. Außerdem ist die Amplitude bei einem Bass meist höher als im Vorfeld. Diese beiden Eigenschaften machen wir uns zunutze.
Bei jedem Sample wird die maximale Amplituden-Höhe der letzten Samples gemittelt. Übersteigt die aktuelle Amplitudenhöhe diesen Wert, so ist die Energie höher und es könnte sich um einen Bass handeln. Um zu analysieren ob eine längere Welle das Signal dominiert, werden zeitlich aufeinanderfolgende Amplitudenwerte verglichen. Übersteigt die Erhöhung oder Verringerung dieser Werte einen Schwellwert (5%) nicht und ist das dann in einem gewissen Abstand (2048 Werte) bis zu einem Prozentsatz von 90% der Fall, so gehen wir von einem Beat aus.
Links dominieren kurzwellige hohe Frequenzen, rechts dominieren langwellige tiefe Frequenzen

Der Abstand zweier Beats wird erfasst. Sind diese in einem Zeitfenster von max. 2 Sekunden (langsamer ist selten ein BPM-Wert eines Songs) und entsprechen einem möglichen BPM-Wert, so wird die Zeit-Erfasst und der aktuelle BPM-Wert angepasst. Dies geschieht über ein Momentum-Learning. Der aktuelle Wert hat nur einen Einfluss von ca. 5% auf die Vorigen Werte.
Da langsamere Rechner nicht mit der Rechenlast zurechtkommen, wurde ein Button eingeführt, der die BPM-Ermittlung erst auf Kommando startet. So sind langsamere Rechner nicht von einem Absturz des Skriptes betroffen.
Die Ermittelten BPM-Werte sind bei House-Musik (viele eindeutige Beats) schnell und sehr zuverlässig. Bei langsamer und leiser Musik (wie Entspannungsmusik) oder Umwelt-Geräuschen kann es lange dauern bzw. auch zu fehlerhaften Ergebnissen kommen. Für unseren Anwendungsfall ist die Ermittlung jedoch voll funktional. 

Keine Kommentare:

Kommentar veröffentlichen