Dies ist die Audioversion der Twitter Image Encoding Challenge .
Entwerfen Sie ein Audiokomprimierungsformat, das mindestens eine Minute Musik in 140 Byte oder weniger druckbarem UTF-8-codiertem Text darstellen kann.
Implementieren Sie es, indem Sie ein Befehlszeilenprogramm schreiben, das die folgenden 3 Argumente (nach dem Namen des Programms selbst) enthält:
- Die Zeichenfolge
encode
oderdecode
. - Der eingegebene Dateiname.
- Der Ausgabedateiname.
(Wenn Ihre bevorzugte Programmiersprache keine Befehlszeilenargumente verwenden kann, können Sie einen alternativen Ansatz verwenden, der jedoch in Ihrer Antwort erläutert werden muss.)
Die encode
Operation konvertiert das von Ihnen gewählte Audioformat in das komprimierte Tweet-Format und die decode
Operation konvertiert das Tweet-Format in das ursprüngliche Audioformat. (Natürlich wird von Ihnen erwartet, dass Sie eine verlustbehaftete Komprimierung implementieren, sodass die Ausgabedatei nicht mit der Eingabe identisch sein muss, sondern nur im selben Format.)
Nehmen Sie in Ihre Antwort auf:
- Der vollständige Quellcode Ihres Programms. (Wenn diese Seite zu lang ist, können Sie sie an einer anderen Stelle hosten und einen Link dazu posten.)
- Eine Erklärung, wie es funktioniert.
- Zumindest ein Beispiel mit einem Link zu den ursprünglichen Audiodateien, dem „Tweet“ -Text, auf den es komprimiert wurde, und der Audiodatei, die durch Dekodieren des Tweets erhalten wurde. (Der Beantworter ist für die Behauptungen des Urheberrechts im Hinblick auf eine „faire Verwendung“ verantwortlich.)
Regeln
- Ich behalte mir das Recht vor, Lücken in den Wettbewerbsregeln jederzeit zu schließen.
- [Bearbeitet am 24. April] Für die Eingabe Ihrer
encode
Funktion (und die Ausgabe Ihrerdecode
Funktion) können Sie jedes vernünftige, übliche Audioformat verwenden, sei es:- Nicht komprimierte Wellenform, wie WAV.
- Komprimierte Wellenform, wie MP3.
- Notenstil wie MIDI.
- Ihr komprimiertes "Tweet" -Format muss die Sounds in der Eingabedatei tatsächlich codieren. Die folgenden Ausgabetypen zählen also nicht :
- Ein URI oder Dateipfad, der den Speicherort angibt, an dem die tatsächliche Ausgabe gespeichert ist.
- Ein Schlüssel zu einer Datenbanktabelle, in der die tatsächliche Ausgabe als Blob gespeichert ist.
- Sowas ähnliches.
- Ihr Programm muss so konzipiert sein, dass es generische Musikdateien komprimiert. Tun Sie also nichts, was zu offensichtlich mit Ihrem speziellen Beispielsong zusammenhängt. Wenn Sie beispielsweise "Twinkle, Twinkle, Little Star" demonstrieren, sollte Ihre Komprimierungsroutine kein bestimmtes Symbol für die Sequenz "do-do-so-so-la-la-so" fest codieren.
- Die Ausgabe Ihres Programms sollte tatsächlich in der Lage sein, Twitter zu durchlaufen und unbeschadet herauszukommen. Ich habe keine genaue Liste der unterstützten Zeichen, versuche jedoch, mich an Buchstaben, Ziffern, Symbole und Satzzeichen zu halten. Vermeiden Sie Steuerzeichen, kombinieren Sie Zeichen, BIDI-Marker oder ähnliches.
- Sie können mehr als einen Beitrag einreichen.
Beurteilungskriterien
Dies ist ein Beliebtheitswettbewerb (dh die meisten Netto-Upvotes gewinnen), aber die Wähler werden aufgefordert, Folgendes zu berücksichtigen:
Richtigkeit
- Kannst du das Lied noch erkennen, nachdem es komprimiert wurde?
- Hört es sich gut an?
- Kannst du noch erkennen, welche Instrumente gespielt werden?
- Kannst du die Texte noch erkennen? (Dies ist wahrscheinlich unmöglich, aber es wäre beeindruckend, wenn es jemandem gelingen würde.)
Komplexität
Die Wahl des Beispielsongs spielt hier eine Rolle.
- [Hinzugefügt am 24. April] Diese Herausforderung ist mit MIDI oder ähnlichen Formaten am einfachsten. Wenn Sie sich jedoch mehr Mühe geben, damit es mit wellenformartigen Formaten funktioniert, verdient dies zusätzliche Anerkennung.
- Wie ist die Struktur? Sicher, Sie können die Ein-Minuten-Anforderung erfüllen, indem Sie dieselben 4 Takte beliebig oft wiederholen. Komplexere Songstrukturen verdienen jedoch mehr Punkte.
- Kann das Format mehrere gleichzeitig gespielte Noten verarbeiten?
Der Code
- Halte es so kurz und einfach wie möglich. Dies ist jedoch kein Codegolf, daher ist die Lesbarkeit wichtiger als die Anzahl der Zeichen.
- Clevere, komplizierte Algorithmen sind ebenfalls in Ordnung, sofern sie durch eine verbesserte Ergebnisqualität gerechtfertigt sind.
Antworten:
Scala
Sicher, es wäre einfacher, MIDI-Dateien zu kodieren, aber wer hat eine Menge MIDI-Dateien, die herumliegen? Es ist nicht 1997!
Das Wichtigste zuerst: Ich habe beschlossen, ein "Unicode-Byte" als "Unicode-Zeichen" zu interpretieren und CJK-Zeichen zu verwenden, weil:
Es gibt ein paar Tricks, mit denen ich jeden letzten Tropfen Entropie aus den Quellen herausdrücke:
Erstens wird Musik mit Noten gemacht. Darüber hinaus betrachten wir dieselbe Note in einer anderen Oktave im Allgemeinen als dieselbe Note (weshalb eine 12-saitige Gitarre richtig klingt), sodass wir nur 12 Codierungsmöglichkeiten haben. (Wenn ich zum Beispiel B ausgebe, gebe ich tatsächlich einen Akkord aus, der in allen Oktaven nur aus B besteht, ein bisschen wie bei einer 12-saitigen Gitarre).
Als nächstes erinnere ich mich aus der Musikklasse, dass die meisten Notenübergänge klein sind (eine Note nach oben oder unten). Sprünge sind seltener. Dies sagt uns, dass es wahrscheinlich weniger Entropie in den Sprunggrößen als in den Noten selbst gibt.
Daher besteht unser Ansatz darin, unsere Quelle in eine Reihe von Blöcken zu unterteilen. Ich fand, dass 14 Blöcke pro Sekunde gut funktionieren (Anmerkung: Ich habe mich immer gefragt, warum Audio mit 44100 Hz codiert wurde. Es stellt sich heraus, dass 44100 viele Faktoren hat. Ich hätte also 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 15, 18, 20, 21, 25, 28 oder 30 Blöcke pro Sekunde wählen können und es hätte sauber geteilt ). Wir haben dann diese Blöcke FFT (naja, technisch nicht schnell, da die Bibliothek, die ich verwendet habe, nicht schnell für Nicht-Potenz-2-Blöcke ist. Und technisch habe ich eine Hartley-Transformation verwendet , nicht Fourier).
Wir finden dann die Note, die am lautesten klingt (ich habe die A-Gewichtung mit hohen und niedrigen Cut-Offs verwendet, hauptsächlich, weil sie am einfachsten zu implementieren ist), und codieren diese Note oder codieren die Stille (die Stilleerkennung basiert auf SNR - niedrigem SNR) ist Stille).
Wir übersetzen dann unsere codierten Noten in Sprünge und geben sie an einen adaptiven arithmetischen Codierer weiter. Der Prozess für die Übersetzung in Text ähnelt der Frage der Bildkomprimierung (beinhaltet jedoch eine missbräuchliche Verwendung von BigInteger).
So weit, so gut, aber was ist, wenn die Probe zu viel Entropie hat? Wir verwenden ein grobes psychoakustisches Modell, um einige zu entfernen. Der niedrigste Entropiesprung ist "keine Änderung", daher untersuchen wir unsere FFT-Daten, um zu versuchen, Blöcke zu finden, bei denen der Hörer es wahrscheinlich nicht bemerkt, wenn wir die vorherige Note weiter spielen, indem wir nach Blöcken suchen, bei denen sich die Note aus dem vorherigen Block befindet fast so laut wie die lauteste Note (wobei "fast" durch den Qualitätsparameter gesteuert wird).
Wir haben also ein Ziel von 140 Zeichen. Wir beginnen mit der Kodierung bei Qualität 1.0 (maximale Qualität) und sehen, wie viele Zeichen das sind. Wenn es zu viele sind, fallen wir auf 0,95 und wiederholen, bis wir 140 Zeichen haben (oder wir geben nach Qualität 0,05 auf). Dies macht den Encoder zu einem n-Pass-Encoder für n <= 20 (obwohl er auch in anderen Bereichen massiv ineffizient ist, also m'eh).
Der Encoder / Decoder erwartet Audio im s16be-Monoformat. Dies kann mit avconv erreicht werden als:
So führen Sie den Encoder aus:
Vollständiger Code unter https://github.com/jamespic/twelvestring .
Fallen zu beachten: Sie benötigen die Arithmetic Coding-Bibliothek von Nayuki, für die derzeit keine Maven-Artefakte verfügbar sind. Stattdessen müssen Sie die Entwicklergabel lokal erstellen und installieren .
Und hier sind einige Beispiele. Sie klingen schrecklich, sind aber fast wiederzuerkennen:
Aktualisieren
Ich habe die Stille-Schwelle im Code angepasst und neu codiert. Die Kodierungen wurden entsprechend aktualisiert. Außerdem habe ich aus Spaß einen weiteren Song hinzugefügt (technisch gesehen kein Open Source-Titel, aber ich bezweifle, dass der ursprüngliche Inhaber des Urheberrechts der Meinung ist, dass seine IP-Adresse in Gefahr ist):
Weitere Updates
Ich habe den Encoder ein wenig überarbeitet, was sich überraschend auf die Qualität ausgewirkt hat (ich hatte vergessen, dass bei DHT die Signale außerhalb der Phase im Grunde genommen negativ sind, also habe ich die Signale außerhalb der Phase ignoriert).
In einer früheren Version des Codes wurde nur das größere dieser phasenverschobenen Signale verwendet, aber jetzt wird der Effektivwert verwendet. Außerdem habe ich dem Encoder (Tukey, alpha 0.3) eine recht konservative Fensterfunktion hinzugefügt, um Artefakte zu bekämpfen.
Alles ist entsprechend aktualisiert.
quelle
BitOutputStream::close
Methode, die ich vergessen hatte anzurufen. Ich werde den Code korrigieren und die Ausgaben aktualisieren.Python
In Bezug auf UTF-8 mache ich kein spezielles Mangling, daher besteht meine Einreichung die 140-Byte-Anforderung. Ich mache keine Ansprüche auf die Nützlichkeit, Genauigkeit oder Effizienz meiner Lösung.
Ich habe eine Samplerate von 44100 Hz für den Ein- und Ausgang verwendet. SAMPLES_PER_BYTE steuert die Qualität der Konvertierung. Je niedriger die Zahl, desto besser ist die Klangqualität. Die von mir verwendeten Werte sind im Ergebnisbereich angegeben.
Verwendung
Kodieren
Die Eingabedatei sollte eine WAV sein. Es wird nur der erste Kanal codiert.
Dekodieren
Abspielen der dekodierten Musik
Der Code
Die Eingänge
Mein offizieller Beitrag ist Impromptu für Pianoforte und Beatbox von Kevin MacLeod . Für diese Datei habe ich einen SAMPLES_PER_BYTE von 25450 verwendet.
Ich habe mir auch erlaubt , Twinkle, Twinkle, Little Star mit einem SAMPLES_PER_BYTE von 10200 zu codieren. Das klingt viel besser.
Die Ausgabe
Impromptu für Pianoforte und Beatbox
Verknüpfung
Funkel, funkel kleiner Stern
Verknüpfung
quelle