Avec ou sans perte?

18

Étant donné un fichier audio, déterminez s'il est codé dans un format avec perte ou dans un format sans perte. Aux fins de ce défi, seuls les formats suivants doivent être classés:

Règles

  • Si l'entrée est prise sous la forme d'un nom de fichier, aucune hypothèse ne doit être faite sur le nom de fichier (par exemple, l'extension n'est pas garantie d'être correcte pour le format, ni même présente).
  • Aucune métadonnée ID3 ou APEv2 ne sera présente dans les fichiers d'entrée.
  • Deux sorties uniques et distinctes peuvent être utilisées, telles que 0et 1, lossyet lossless, fooet bar, etc.

Cas de test

Les cas de test pour ce défi consistent en un fichier zip situé ici qui contient deux répertoires: lossyet lossless. Chaque répertoire contient plusieurs fichiers audio qui sont tous des ondes sinusoïdales de 0,5 seconde à 440 Hz, encodés dans différents formats. Tous les fichiers audio ont des extensions correspondant aux formats ci-dessus, à l'exception de A440.m4a(qui est de l'audio AAC dans un conteneur MPEG Layer 4).

Mego
la source
" Audio AAC dans un conteneur MPEG Layer 4 " soulève la question: quels autres formats de conteneur les réponses doivent-elles gérer?
Peter Taylor
@PeterTaylor Seul AAC a reçu une mention spéciale parce que je ne pouvais pas trouver un moyen de fournir de l'audio AAC sans l'intégrer dans un conteneur MPEG Layer 4 via FFMPEG. L'audio Vorbis est intégré dans un conteneur Ogg (comme c'est la norme pour l'audio Vorbis). Tous les autres sont des formats autonomes.
Mego
Êtes-vous sûr du fichier TTA? Selon la spécification , les fichiers TTA devraient commencer par le nombre magique TTA1 ou TTA2. FFM2 (le numéro magique de votre fichier) semble correspondre au flux FFmpeg. Le fichier Linux reconnaît l'en-tête TTA1, mais pas celui FFM2.
Dennis
Aussi, pouvons-nous supposer que l'AAC sera toujours dans un en-tête MPEG Layer 4? Sinon, que pouvons- nous supposer?
Dennis
Pouvons-nous prendre le contenu du fichier en entrée ou notre code doit-il les récupérer?
Shaggy

Réponses:

18

Gelée , 7 5 octets

ƈƈeØA

Les formats avec perte renvoient 0 , les formats sans perte renvoient 1 .

Essayez-le en ligne! (permaliens dans Gist)

Contexte

Les formats que nous devons prendre en charge ont les nombres magiques suivants, c'est-à-dire qu'ils commencent par ces octets.

Format    Header (text)       Header (hex)
-----------------------------------------------------------------------------------
AC3       .w                  0B 77
AMR       #!AMR               23 21 41 4D 52
AAC       ÿñP@..ü             FF F1 50 40 00 1F FC
  M4A     ... ftypM4A         00 00 00 20 66 74 79 70 4D 34 41 20
MP2       ÿû                  FF FB
MP3       ÿû                  FF FB
OGG       OggS                4F 67 67 53
WMA       0&²u.fÏ.¦Ù.ª.bÎl    30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C

AIFF      FORM????AIFF        46 4F 52 4D ?? ?? ?? ?? 41 49 46 46
FLAC      fLaC                66 4C 61 43
TTA       TTA1                54 54 41 31
  FFM2    FFM2                46 46 4D 32
WAV       RIFF????WAVE        52 49 46 46 ?? ?? ?? ?? 57 41 56 45

Les entrées en retrait sont des conteneurs pour le format précédent qui apparaissent dans les cas de test. ?désigne un octet variable. .désigne un octet non imprimable. Tous les autres octets sont affichés comme leur caractère ISO 8859-1.

En ne regardant que le deuxième octet, nous pouvons déterminer le format de manière simple:

Les formats sans perte ont une lettre majuscule comme deuxième octet, contrairement aux formats avec perte.

Comment ça fonctionne

ƈƈeØA  Main link. No arguments.

ƈ      Read a char from STDIN and set the left argument to this character.
 ƈ     Read another char from STDIN and set the return value to this character.
   ØA  Yield the uppercase alphabet, i.e., "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
  e    Exists; return 1 if the return value (second char on STDIN) belongs to the
       uppercase alphabet, 0 if not.
Dennis
la source
2
Ceci est une solution très intelligente.
Mego
10

C, 82 80 32 octets

Inspiré par la réponse de @Dennis , cela peut être réduit beaucoup plus:

main(){return getchar()&200^64;}

Dirigez les données du fichier vers stdin. Renvoie 0 pour lossless, ou différent de zéro pour lossy.

Ou le chèque original plus long:

char v[5];main(){scanf("%4c",v);return*v&&strstr("fLaC FORM RIFF TTA1 FFM2",v);}

Dirigez les données du fichier vers stdin. Renvoie une valeur non nulle (1) pour lossless ou 0 pour lossy.

D'après ce que je peux dire, tous les formats que vous avez répertoriés ont des nombres magiques distincts (sauf AIFF / WAV, mais ils sont tous les deux sans perte), donc cela vérifie simplement ce nombre magique pour une valeur sans perte connue. Il *v&&s'agit simplement de se protéger contre les fichiers correspondants qui commencent par un octet nul (M4A).

J'ai inclus les valeurs que j'ai trouvées dans les fiches techniques ( fLaC= FLAC, RIFF= WAV / AIFF, TTA1= TTA), et FORM= AIFF et FFM2= TTA proviennent des exemples de fichiers fournis (je ne peux que deviner que ce sont des formats d'emballage ou des versions ultérieures).


Ou une alternative plus courte à la sensation de tricherie:

Fichier Bash +, 61 octets

N="$(file "$1")";[[ $N = *": d"* || $N = *IF* || $N = *FL* ]]

Prend le nom de fichier comme argument. Renvoie 0 pour lossless, ou différent de zéro pour lossy.

Fait exactement ce que vous attendez; demande filequel est le type de fichier, puis vérifie les modèles connus. Correspondances TTA : d( : data), correspondance AIFF / WAV IFet correspondances FLAC FL. Aucun des résultats sans perte ne correspond à aucun de ceux-ci, et j'ai testé qu'il fonctionne toujours si les noms de fichiers sont supprimés.


Essai:

for f in "$@"; do
    echo "Checking $f:";
    ./identify2 "$f" && echo "shorter C says LOSSLESS" || echo "shorter C says LOSSY";
    ./identify < "$f" && echo "longer C says LOSSY" || echo "longer C says LOSSLESS";
    ./identify.sh "$f" && echo "file says LOSSLESS" || echo "file says LOSSY";
done;

# This can be invoked to test all files at once with:
./identify_all.sh */*
Dave
la source
Votre solution Bash fonctionne-t-elle également si l'extension de fichier est incorrecte? "l'extension n'est pas garantie pour être correcte pour le format", vous devriez donc être en mesure de donner une extension incorrecte à un fichier tout en le faisant fonctionner.
mbomb007
@ mbomb007 Je viens de tester avec les extensions mélangées et il les identifie toujours très bien. Je pense fileque ne fait pas confiance aux extensions de toute façon (beaucoup de choses que les utilisateurs renomment un png en jpeg reviennent à le convertir!)
Dave
7

GS2 , 3 octets

◄5ì

Les formats avec perte renvoient 0 , les formats sans perte renvoient 1 .

Essayez-le en ligne! (permaliens dans Gist)

Contexte

Les formats que nous devons prendre en charge ont les nombres magiques suivants, c'est-à-dire qu'ils commencent par ces octets.

Format    Header (text)       Header (hex)
-----------------------------------------------------------------------------------
AC3       .w                  0B 77
AMR       #!AMR               23 21 41 4D 52
AAC       ÿñP@..ü             FF F1 50 40 00 1F FC
  M4A     ... ftypM4A         00 00 00 20 66 74 79 70 4D 34 41 20
MP2       ÿû                  FF FB
MP3       ÿû                  FF FB
OGG       OggS                4F 67 67 53
WMA       0&²u.fÏ.¦Ù.ª.bÎl    30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C

AIFF      FORM????AIFF        46 4F 52 4D ?? ?? ?? ?? 41 49 46 46
FLAC      fLaC                66 4C 61 43
TTA       TTA1                54 54 41 31
  FFM2    FFM2                46 46 4D 32
WAV       RIFF????WAVE        52 49 46 46 ?? ?? ?? ?? 57 41 56 45

Les entrées en retrait sont des conteneurs pour le format précédent qui apparaissent dans les cas de test. ?désigne un octet variable. .désigne un octet non imprimable. Tous les autres octets sont affichés comme leur caractère ISO 8859-1.

En ne regardant que le deuxième octet, nous pouvons déterminer le format de manière simple:

Les formats sans perte ont une lettre majuscule comme deuxième octet, contrairement aux formats avec perte.

Comment ça fonctionne

     (implcit) Push the entire input from STDIN as a string on the stack.
◄    Push 1.
 5   Get the strings character at index 1, i.e., its second character.
  ì  Test if the character is an uppercase letter.
Dennis
la source
2

JavaScript (ES6), 20 octets

c=>/^[fFRT]/.test(c)

Explication

Prend le contenu du fichier en entrée et retourne truesi le fichier est sans perte ou falsesi elle entraîne des pertes en testant le premier caractère de cette entrée pour voir si elle est f, F, Rou T.


Essayez-le

Collez le contenu d'un fichier dans le textarea.

f=
c=>/^[fFRT]/.test(c)
i.addEventListener("input",_=>console.log(f(i.value)))
<textarea id=i></textarea>


Deuxième effort, 81 63 octets

Récupère le contenu d'un fichier à partir d'une URL fournie, qui s'est avérée exagérée.

u=>fetch(u).then(r=>r.text()).then(t=>alert(/^[fFRT]/.test(t)))

Premier effort, 146 116 89 octets

Non valide car les types MIME sont liés aux extensions et, apparemment, les en-têtes de réponse sont considérés comme des entrées supplémentaires.

u=>fetch(u).then(r=>alert(/aiff|flac|tta|wave|wav$/.test(r.headers.get("Content-Type"))))
Hirsute
la source
Les serveurs Web génèrent généralement le MIME en fonction de l'extension de fichier, ce qui est contraire aux règles ici. Avez-vous vérifié si cela fonctionne sur des fichiers servis sans extension? (si c'est le cas, vous devriez probablement inclure le nom du serveur que vous utilisez dans le "langage")
Dave
1
@ Dave Presque sûr qu'ils ne le font pas. MIME et extension ne dépendent pas du tout les uns des autres. Si vous modifiez l'extension d'un fichier et le téléchargez, le type MIME est le MIME du contenu réel du fichier, pas l'extension. Dans l'état actuel des choses, cependant, la saisie d'entrées comme URL n'est probablement pas autorisée. Je ne suis pas sûr.
mbomb007
@ mbomb007 Je ne sais pas pourquoi vous dites cela; Les types MIME sont une chose Internet, pas un système de fichiers / fichiers, et les serveurs que je connais le détermineront en fonction de l'extension en utilisant une recherche configurée (pour la vitesse de diffusion des en-têtes; ils ne veulent pas inspecter chaque fichier avant de servir il). Prenons par exemple Apache AddType <mime> <extension>ou IIS <MimeMap>. Bien sûr, une configuration spécifique ou un outil d'hébergement de fichiers pourrait faire une inspection appropriée, et cela mériterait que le choix du serveur fasse partie de la réponse (puisque c'est le serveur qui détermine le type de fichier!)
Dave
1
J'ai effectué la validation des fichiers avec .NET, et le type MIME correspond au contenu même lorsque l'extension a été modifiée avant le téléchargement.
mbomb007
@ mbomb007, alors le composant .NET que vous avez utilisé doit avoir effectué l'inspection des fichiers pendant le téléchargement ou lors de la diffusion des fichiers (je suppose pendant le téléchargement pour les performances, mais vous ne savez jamais). Donc, pour revenir à mon commentaire d'origine, cela ferait de cette réponse quelque chose comme "JavaScript + .NET SeverLibraryXYZ". En ce qui concerne la saisie d'une URL, je peux voir pourquoi vous êtes hésitant, mais personnellement, je le considérerais valide tant que le choix du serveur est mentionné. Peut-être y a-t-il une méta existante, mais finalement, c'est à Mego.
Dave
1

Puce , 11 octets

~Z~S
t'G~aF

Réplique sans vergogne de Dennis 'Jelly dans Chip.

Retours sans 0x0perte, retours avec perte 0x1.

Essayez-le en ligne , liens dans l'essentiel (merci Dennis pour la stratégie TIO ici)

Explique!

~Z~S
t'

Cette portion est d'ordre administratif: elle S coupe le premier octet et tdisparaît après le second.

G~aF

C'est la chair de la décision. Chaque octet d'entrée est accessible par les bits HGFEDCBA. SiG est défini et Fne l'est pas, cela signifie que l'octet se situe dans la plage 0x40de 0x5f(ce qui équivaut à peu près à «majuscule» et suffisamment bon pour la tâche à accomplir).

Cependant, pour les économies d'octets, j'inverse cette décision de G and (not F)à (not G) or F, car or peut être implicite dans Chip.

Cette valeur vraie / fausse résultante est ensuite placée dans a , qui est le bit le plus bas de la sortie. (Tous les autres bits seront nuls). Dans le TIO, j'exécute la sortie via hexdump afin que les valeurs soient visibles.

De manière équivalente, en C-ish, on dirait quelque chose comme:

out_byte = !(in_byte & 0x40) && (in_byte & 0x20)
Phlarx
la source
1

Cubix, 16 octets

$-!u'HIa'@/1@O<

Forme nette:

    $ -
    ! u
' H I a ' @ / 1
@ O < . . . . .
    . .
    . .

Essayez-le vous-même

Vous devez entrer les valeurs d'octets décimaux du fichier dans une liste séparée. Le séparateur n'a pas d'importance, tout ce qui n'est pas un chiffre ou un signe moins suffit. Le code ne se soucie vraiment que du premier octet, vous pouvez donc laisser de côté le reste du fichier si vous le souhaitez. Le programme génère 0des sorties sans perte et 1avec perte. Essayez-le ici ! L'entrée par défaut utilise un en-tête FLAC.

Explication

La bonne chose à propos des fichiers est que (presque) tous ont une soi-disant magie. Ce sont les premiers octets du fichier. Un bon logiciel ne vérifie pas l'extension du fichier, mais plutôt la magie du fichier pour voir s'il peut gérer un certain fichier.

Dennis a trouvé un moyen d'utiliser cette magie pour trouver le type de compression, mais le fait qu'il ait supprimé le premier octet m'a donné envie d'essayer de trouver une méthode qui utilise le premier octet plutôt que le second. Après tout, cette communauté consiste à économiser des octets.

Voici une liste des premiers octets des différents types de fichiers. Je les ai classés en deux groupes: avec et sans perte. Voici les valeurs de leur premier octet en décimal, hexadécimal et binaire. Vous pourriez déjà voir un motif ...

Lossy:                  Lossless:
255:0xFF:0b11111111     102:0x66:0b01100110
 79:0x4F:0b01001111      84:0x54:0b01010100
 35:0x23:0b00100011      82:0x52:0b01010010
 11:0x0B:0b00001011      70:0x46:0b01000110
  0:0x00:0b00000000

Le motif que j'ai vu était que le deuxième bit (compté de gauche à droite) était toujours activé sur les octets "sans perte" et le cinquième bit était toujours désactivé. Cette combinaison n'apparaît dans aucun des formats avec perte. Pour «extraire» cela, nous ferions simplement un ET binaire (par 0b01001000 (=72)), puis nous comparerions à 0b01000000 (=64). Si les deux sont égaux, le format d'entrée est sans perte, sinon c'est avec perte.

Malheureusement, Cubix n'a pas un tel opérateur de comparaison, j'ai donc utilisé la soustraction (si le résultat est 64, cela donne 0, et il en résulte 8, -56 ou -64 sinon. J'y reviendrai plus tard.

Commençons d'abord par le début du programme. L'ET binaire se fait à l'aide de la acommande:

'HIa
'H   # Push 0b01001000 (72)
  I  # Push input
   a # Push input&72

Ensuite, nous comparons à 64 en utilisant la soustraction (notez que nous avons frappé un miroir qui reflète l'IP vers la face supérieure [première ligne, deuxième caractère, pointant vers le sud] au milieu de cette partie).

'@-
'@  # Push 0b01000000 (64)
  - # Subtract from (input&72)
    # Yields 0 for lossy, non-zero otherwise

Une fois l'IP retournée par le u, nous utilisons un flux de contrôle pour pousser a 1vers la pile si (et seulement si) le haut de la pile n'est pas nul:

!$1
!   # if top = 0:
 $1 #   do nothing
    # else:
  1 #   push 1

Après avoir fait le tour du cube, nous avons frappé l' <instruction, qui pointe l'IP vers l'ouest sur la quatrième ligne. Il ne reste plus qu'à sortir et à terminer.

O@
O  # Output top of the stack as number
 @ # End program

Ainsi, le programme génère 0des sorties sans perte et 1avec perte.

Luc
la source