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. 

Visualisierung und Geschwindigkeitsanpassung eines Sounds

Die Visualisierung eines direkt eingeladenen Sounds (per Webadresse) in der MP3-Pitch-Player-Klasse geschieht über das Anzeigen des aktuellen Signals. Das Ändern der Geschwindigkeit passiert über die Manipulation derselben Daten. Da diese Algorithmen regelmäßig ausgeführt werden müssen – idealer Weise jedes Sample -, stehen diese Operation in einer Methode, die vom geworfenen SoundEvent SAMPLE_DATA aufgerufen wird.
Durch die Initialisierung des Sounds haben wir einen Byte-Stream erhalten, der im Wechsel Float-Werte für den linken und für den rechten Stereo-Ausgang enthält. Die aktuelle Soundposition (anhand der Phase=seconds*Abtastrate von 44,100Hz) stellt den aktuellen Index im Byte-Stream dar. Wir speichern uns die nächsten 2048 Werte vor und können an Hand dieser weiterarbeiten.
Für die Visualisierung werden sie auf ein BitmapData-Objekt gezeichnet. Die horizontale Achse beschreibt den Zeitverlauf, die vertikale Achse beschreibt die Amplitudenauslenkung. Anschließend wird darauf ein Blur-Filter angewandt um den gezeigten Effekt zu erhalten.
Visualisierung von Sounds in Strix 

Zum Verschnellern und Verlangsamen wird die Soundposition nicht um den gewohnten Faktor (1) inkrementiert, sondern um den durch die Variable speed definierten Faktor. Für Strix haben wir den Wertebereich auf -2 bis 2 festgelegt, sodass die Musik bis zu doppelt so schnell Rückwärts und Vorwärts gespielt werden kann. Die so ermittelten Float-Werte schreiben wir wieder in das Target des Events, welches dem gespielten Byte-Stream entspricht. 

Anbindung der Media-On-Demand Anbieter

Grundsätzlich werden die gespielten Medien nach Typ unterschieden. Derzeit gibt es Videos, die in Flash-Containern gespielt werden (dazu gehören YouTube und Vimeo), und Sounds, die eine eigene Visualisierung besitzen (dazu gehören Jamendo und generell MP3s im Web).
Um die Anbindung in Flash zu abstrahieren, wurde das Interface IPlayer eingeführt. Dieser erlaubt den Zugriff auf alle gängigen Operationen (wie Play, Pause, Seek etc.) und gibt eine Visualisierung in Form eines MovieClips zurück. Das Interface sieht dabei wie folgt aus:

package com.strix.player
{
                import flash.display.MovieClip;
                interface IPlayer
                {
                               //initial
                               function init():void;
                               function destroy():void;

                               //actions
                               function playVideo():void;
                               function pauseVideo():void;
                               function stopVideo():void;
                               function resizeVideo(width:Number, height:Number):void;

                               //setter
                               function setVolume(volume:Number):void;
                               function setMute(mute:Boolean):void;
                               function setPlaybackSpeed(speed:Number):void;
                               function seekTo(seconds:Number):void;
                              
                               //getter
                               function isMuted():Boolean;
                               function isReady():Boolean;
                               function getVolume():Number;
                               function getCurrentTime():Number;
                               function getDuration():Number;
                               function getPercentLoaded():Number;
                               function getPlayerState():Number;
                               function getErrorState():Number;
                               function getPlaybackSpeed():Number;
                               function getVisualRepresentation():MovieClip;
                               function getLogo():MovieClip;
                               function getLink():String;
                }             
}

Für YouTube wird zur Laufzeit eine SWF-Datei eingeladen, welche den Chromeless-Player mit dem entsprechenden Video enthält. Chromeless bedeutet dabei, dass die von YouTube bekannten Steuerelemente im Player nicht angezeigt werden. Das Sound- und Video-Abspielen übernimmt der Black-Box-Container. Dieser wird gleichzeitig auch als visuelle Referenz zurückgegeben. Vimeo funktioniert ähnlich wie YouTube, mit dem Unterschied, dass es keinen Chromeless-Player gibt. Stattdessen werden alle Steuerelemente im Video angezeigt.
Der Jamendo-Player ist eine Erweiterung der MP3-Player-Klasse. Sie gibt als visuelle Referenz das eingeladene Album-Cover zurück. Der MP3 Player existiert in 2 Versionen, dem MP3-Player und dem MP3-Pitch-Player. Der MP3-Player ist die einfache Variante: Er lädt die angeforderte Datei in ein Sound-Objekt und lässt sich über die AS3-typischen Funktionen (play(), stop() etc.) steuern. Das Problem dabei ist allerdings, dass ein Verändern der Geschwindigkeit oder ein Visualisieren des Spektrums nicht realisierbar ist.
Der MP3-Pitch-Player lädt eine Datei in ein Sound-Objekt und wandelt dieses in ein Byte-Stream um. Dies geschieht nicht über die Methode SoundMixer.computeSpectrum(), sondern direkt auf dem Sound-Objekt (Sound.extract()). Die Nachteile der einfach zu benutzenden SoundMixer-Klasse sind vielfältig. Der SoundMixer ist eine statische Klasse, die für den kompletten Applikationskontext gilt. Einerseits kann diese also nur das Spektrum aller gespielten Sounds ermitteln. Wir wollen allerdings beide Decks getrennt behandeln. Andererseits kann es beim Spielen von MP3 parallel zu YouTube zu Sandbox-Problemen führen. Dadurch mussten wir aber auch auf die einfache Möglichkeit verzichten eine FFT (Fast Fourier Transformation) zu nutzen. 

Dienstag, 5. Juli 2011

Features

Hier werden schon mal die Features gezeigt. Das Video selber ist nur eine Art Moodboard um zu sehen, wie das finale Feature-Video aussehen kann.
Die Musik stammt von Jamendo.



Erstellung der Turntables

Die Turntables wurden erst in Photoshop erstellt und anschließend nach Flash portiert.
Um die volle Funktionalität und mehrere Ebenen zu verwirklichen, wurden die Decks in unterschiedliche Komponenten unterteilt, die jeweils als PNG mit transparenten Hintergrund extrahiert wurden.


Die Hauptkomponente ist die Hintergrundgrafik. In mehreren Ebenen darüber liegen die Buttons, Regler und der Tone-Arm. In Flash wurden die Einzelbilder in die FLA geladen, positioniert und durch MovieClips abstrahiert. Dadurch konnte genauer und mit direkter Manipulation gearbeitet werden. Zur Laufzeit werden jedoch die aktuellen Grafiken aus dem entsprechenden Verzeichnis geladen. Das fertige Ergebnis sieht dann so aus: 


Fertige Turntables in der Flash-Anwendung

Montag, 4. Juli 2011

HTML5 3D-Features nun auch in der BeuthBox zu testen


Wir haben unsere side by side und syntetischen Verfahren zum live-3D-Erzeugen nun auch auf einer Testseite für die BeuthBox implementiert. Wie gehabt werden die Videos mit HTML5 eingeladen und anschließend per Javascript entsprechend verändert dargestell.

HTML5 Experimentaler Bereich

Für unser Studium der Medieninformatik (Master) testen wir gerade ein paar Verfahren, um mit einem HTML5 Player 3D-Videos zu betrachten. Zum Einsatz kommt dabei lediglich Javascript. Die Videodaten werden durch ein <video>-Element geladen und auf ein Canvas-Element projeziert. Da die Browseruntersützung im Bezug auf die Videoformate nicht einheitlich sind, testen wir erst einmal nur mit .mp4 Dateien. Diese können beispielsweise mit dem Chrome-Browser betrachtet werden.

Momentan werden die folgenden Modi unterstützt:

1)
Quelle: Side-by-side Video (linkes und rechtes Auge getrennt in einem Frame gespeichert)
Ausgabe: 3D-Ansicht anhand des Anaglyph-Verfahrens




2)
Quelle: Reguläres Video
Ausgabe: Syntetische 3D-Ansicht anhand des Anaglyph-Verfahrens




3)
Quelle: Reguläres Video
Ausgabe: Syntetische 3D-Ansicht anhand des Polarisations-Verfahrens