Ceci est la version audio du défi d’encodage d’images Twitter .
Concevez un format de compression audio pouvant représenter au moins une minute de musique sur 140 octets ou moins de texte imprimable encodé en UTF-8.
Implémentez-le en écrivant un programme en ligne de commande qui utilise les 3 arguments suivants (après le nom du programme lui-même):
- La ficelle
encode
oudecode
. - Le nom de fichier d'entrée.
- Le nom du fichier de sortie.
(Si votre langage de programmation préféré ne permet pas d'utiliser des arguments de ligne de commande, vous pouvez utiliser une approche alternative, mais vous devez l'expliquer dans votre réponse.)
L' encode
opération convertira le format audio choisi en votre format compressé «tweet» et l' decode
opération convertira votre format «tweet» au format audio d'origine. (Bien entendu, vous êtes censé implémenter une compression avec perte, le fichier de sortie ne doit pas nécessairement être identique à celui de l'entrée, mais dans le même format)
Inclure dans votre réponse:
- Le code source de votre programme, en entier. (Si la page est trop longue, vous pouvez l'héberger ailleurs et y poster un lien.)
- Une explication de la façon dont cela fonctionne.
- Au moins un exemple, avec un lien vers le ou les fichiers audio d'origine, le texte «tweet» qu'il compresse et le fichier audio obtenu en décodant le tweet. (Le répondeur est responsable des assertions de “fair use” du copyright.)
Règles
- Je me réserve le droit de supprimer les échappatoires du règlement du concours à tout moment.
- [Édité le 24 avril] Pour l’entrée de votre
encode
fonction (et la sortie de votredecode
fonction), vous pouvez utiliser n’importe quel format audio commun raisonnable, que ce soit:- Forme d'onde non compressée, comme WAV.
- Forme d'onde compressée, comme MP3.
- Le style “Partition”, comme le MIDI.
- Votre format compressé «tweet» doit en fait coder les sons du fichier d’entrée. Ainsi, les types de sortie suivants ne comptent pas :
- Un URI ou un chemin de fichier indiquant l'emplacement où la sortie réelle est stockée.
- Une clé pour une table de base de données où la sortie réelle est stockée sous forme de blob.
- Quelque chose de similaire.
- Votre programme doit être conçu pour compresser des fichiers de musique génériques , évitez donc de faire des choses trop manifestement liées à votre exemple de chanson. Par exemple, si vous montrez «Twinkle, Twinkle, Little Star», votre programme de compression ne doit pas coder en dur un symbole spécifique pour la séquence do-do-so-so-la-la-so.
- La sortie de votre programme devrait pouvoir passer par Twitter et en ressortir indemne. Je n'ai pas de liste des caractères exacts pris en charge, mais essayez de vous en tenir aux lettres, aux chiffres, aux symboles et à la ponctuation; et évitez les caractères de contrôle, en combinant des caractères, des marqueurs BIDI, ou d'autres choses étranges comme ça.
- Vous pouvez soumettre plus d'une entrée.
Critère de jugement
Il s’agit d’un concours de popularité (c’est-à-dire que la plupart des votes positifs augmentent), mais les électeurs sont invités à prendre en compte les éléments suivants:
Précision
- Pouvez-vous toujours reconnaître la chanson après l'avoir comprimée?
- Ca sonne bien?
- Pouvez-vous toujours reconnaître quels instruments sont joués?
- Pouvez-vous encore reconnaître les paroles? (C'est probablement impossible, mais ce serait impressionnant si quelqu'un le faisait.)
Complexité
Le choix de la chanson exemple compte ici.
- [Ajouté le 24 avril] Ce défi sera plus facile avec les formats MIDI ou similaires. Toutefois, si vous faites l'effort supplémentaire de le faire fonctionner avec des formats de type forme d'onde, cela mérite un crédit supplémentaire.
- Quelle est la structure? Bien sûr, vous pouvez répondre à l'exigence d'une minute en répétant simplement les 4 mêmes mesures un nombre arbitraire de fois. Mais les structures de chansons plus complexes méritent plus de points.
- Le format peut-il gérer plusieurs notes jouées en même temps?
Le code
- Gardez-le aussi court et simple que possible. Cependant, ce n'est pas un code de golf, la lisibilité est donc plus importante que le nombre de caractères.
- Des algorithmes intelligents et compliqués sont également acceptables, dans la mesure où ils sont justifiés par une amélioration de la qualité des résultats.
Réponses:
Scala
Bien sûr, il serait plus facile de coder des fichiers MIDI, mais qui a un tas de fichiers MIDI qui traînent? Ce n'est pas 1997!
Tout d’abord: j’ai décidé d’interpréter un «octet Unicode» comme un «caractère Unicode» et d’utiliser des caractères CJK, car:
Il y a quelques astuces que j'utilise pour extraire chaque source d'entropie des sources:
Tout d'abord, la musique est faite avec des notes. De plus, nous considérons généralement la même note dans une octave différente comme la même note (c'est pourquoi une guitare à 12 cordes sonne bien), de sorte que nous n'avons que 12 possibilités pour encoder. (Quand je produis B, par exemple, je produis un accord composé uniquement de B dans toutes les octaves, un peu comme une guitare à 12 cordes).
Ensuite, je me souviens du cours de musique au lycée que la plupart des transitions de notes sont petites (une note vers le haut ou le bas). Les sauts sont moins fréquents. Cela nous indique qu'il y a probablement moins d'entropie dans les tailles de saut que dans les notes elles-mêmes.
Donc, notre approche est de diviser notre source en plusieurs blocs - j'ai trouvé que 14 blocs par seconde fonctionnaient bien (note de côté, je me suis toujours demandé pourquoi l'audio était codé à 44100 Hz. Il s'avère que 44100 a beaucoup de facteurs, donc j'aurais pu choisir 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 15, 18, 20, 21, 25, 28 ou 30 blocs par seconde, et cela aurait été divisé proprement ). Nous avons ensuite FFT ces blocs (enfin, techniquement, pas rapidement, car la bibliothèque que j'ai utilisée n'est pas rapide pour les blocs non-power-of-2. Et techniquement, j'ai utilisé une transformation de Hartley , pas de Fourier).
Nous trouvons ensuite la note qui sonne le plus fort (j’ai utilisé la pondération A , avec des seuils haut et bas, principalement parce que c’est plus facile à mettre en œuvre), et soit coder cette note, soit coder le silence (la détection de silence est basée sur SNR - low SNR est le silence).
Nous traduisons ensuite nos notes codées en sauts et les transmettons à un codeur arithmétique adaptatif. Le processus de traduction en texte est similaire à la question de compression d'image (mais implique une utilisation abusive de BigInteger).
Jusqu'ici, tout va bien, mais que se passe-t-il si l'échantillon a trop d'entropie? Nous utilisons un modèle psychoacoustique brut pour en supprimer. Le saut d'entropie le plus bas est "aucun changement", nous examinons donc nos données FFT pour essayer de trouver des blocs où l'auditeur ne remarquera probablement pas si nous continuons à jouer la note précédente, en recherchant des blocs contenant la note du bloc précédent. presque aussi fort que la note la plus forte (où "presque" est contrôlé par le paramètre de qualité).
Nous avons donc une cible de 140 caractères. Nous commençons par encoder à la qualité 1.0 (qualité maximale), et voyons combien de caractères il s’agit. Si c'est trop, on tombe à 0,95 et on répète, jusqu'à atteindre 140 caractères (ou on abandonne après la qualité 0.05). Cela fait du codeur un codeur n-pass, pour n <= 20 (bien que ce soit massivement inefficace dans d’autres domaines aussi, alors ça me fait mal).
L'encodeur / décodeur attend de l'audio au format mono s16be. Ceci peut être réalisé en utilisant avconv comme:
Pour exécuter l'encodeur:
Code complet à l' adresse https://github.com/jamespic/twelvestring .
Piège à noter: vous aurez besoin de la bibliothèque de codage arithmétique de nayuki, qui ne dispose pas actuellement d'artefacts Maven. Au lieu de cela, vous devrez construire et installer localement la fourchette de développement .
Et voici quelques exemples. Ils paraissent affreux, mais presque reconnaissables:
Mise à jour
J'ai peaufiné le seuil de silence dans le code et l'ai ré-encodé. Les encodages ont été mis à jour en conséquence. De plus, j'ai ajouté une autre chanson (techniquement, pas en open source, mais je doute que le détenteur du copyright original sentira que sa propriété intellectuelle est menacée), juste pour le plaisir:
Plus de mises à jour
J'ai légèrement modifié le codeur, ce qui a eu un impact surprenant sur la qualité (j'avais oublié qu'en DHT, les signaux déphasés sont effectivement négatifs, donc je les ignorais).
Une version antérieure du code prenait simplement le plus gros de ces signaux déphasés, mais nous prenons maintenant le RMS. De plus, j'ai ajouté une fonction de fenêtre assez conservatrice à l'encodeur (Tukey, alpha 0.3), pour tenter de lutter contre les artefacts.
Tout est mis à jour en conséquence.
la source
BitOutputStream::close
méthode que j'avais oublié d'appeler. Je vais corriger le code et mettre à jour les sorties.Python
Je ne fais aucune distinction particulière en ce qui concerne UTF-8, ma soumission satisfait donc à l'exigence de 140 octets. Je ne fais aucune déclaration sur l'utilité, la précision ou l'efficacité de ma solution.
J'ai utilisé une fréquence d'échantillonnage de 44100 Hz pour l'entrée et la sortie. SAMPLES_PER_BYTE contrôle la qualité de la conversion. Plus le chiffre est bas, meilleure est la qualité du son. Les valeurs que j'ai utilisées sont données dans la section résultats.
Usage
Encoder
Le fichier d'entrée doit être un wav. Il n'encode que le premier canal.
Décoder
Jouer de la musique décodée
Le code
Les entrées
Ma soumission officielle est Impromptu pour Pianoforte et Beatbox de Kevin MacLeod . Pour ce fichier, j'ai utilisé un SAMPLES_PER_BYTE de 25450.
J'ai aussi pris la liberté de coder Twinkle, Twinkle, Little Star avec un SAMPLES_PER_BYTE de 10200. Cela sonne beaucoup mieux.
Le résultat
Impromptu pour Pianoforte et Beatbox
Lien
Scintille, scintille petite étoile
Lien
la source