Com ou sem perdas?

18

Dado um arquivo de áudio, determine se ele está codificado em um formato com ou sem perdas. Para os fins deste desafio, apenas os seguintes formatos precisam ser classificados:

Regras

  • Se a entrada for feita na forma de um nome de arquivo, nenhuma suposição deve ser feita sobre o nome do arquivo (por exemplo, não é garantido que a extensão esteja correta para o formato ou mesmo presente).
  • Não haverá metadados ID3 ou APEv2 presentes nos arquivos de entrada.
  • Quaisquer duas saídas únicas e distinguíveis podem ser usadas, como 0e 1, lossye lossless, fooe bar, etc.

Casos de teste

Os casos de teste para esse desafio consistem em um arquivo zip localizado aqui, que contém dois diretórios: lossye lossless. Cada diretório contém vários arquivos de áudio que são ondas senoidais de 440 Hz a 0,5 segundo, codificadas em vários formatos. Todos os arquivos de áudio têm extensões correspondentes aos formatos acima, com exceção de A440.m4a(que é áudio AAC em um contêiner MPEG Layer 4).

Mego
fonte
" Áudio AAC em um contêiner MPEG Layer 4 " levanta a questão: quais outros formatos de contêiner as respostas precisam lidar?
Peter Taylor
@PeterTaylor Only AAC recebeu uma menção especial porque não consegui encontrar uma maneira de fornecer áudio AAC sem incorporá-lo em um contêiner MPEG Layer 4 via FFMPEG. O áudio Vorbis é incorporado em um contêiner Ogg (como é a norma para o áudio Vorbis). Todos os outros são formatos independentes.
Mego
Você tem certeza do arquivo TTA? De acordo com as especificações , os arquivos TTA devem começar com o número mágico TTA1 ou TTA2. FFM2 (o número mágico do seu arquivo) parece corresponder ao fluxo FFmpeg. O arquivo Linux reconhece o cabeçalho TTA1, mas não o cabeçalho FFM2.
Dennis
Além disso, podemos assumir que o AAC sempre estará em um cabeçalho MPEG Layer 4? Se não, o que pode assumimos?
Dennis
Podemos tomar o conteúdo do arquivo como uma entrada ou nosso código precisa recuperá-lo?
Shaggy

Respostas:

18

Geléia , 7 5 bytes

ƈƈeØA

Formatos com perdas retornam 0 , formatos sem perdas retornam 1 .

Experimente online! (permalinks em Gist)

fundo

Os formatos que temos que suportar têm os seguintes números mágicos, ou seja, começam com esses bytes.

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

Entradas recuadas são contêineres para o formato anterior que aparecem nos casos de teste. ?indica um byte variável. .indica um byte não imprimível. Todos os outros bytes são exibidos como caracteres ISO 8859-1.

Observando apenas o segundo byte, podemos determinar o formato de uma maneira fácil:

Formatos sem perdas têm uma letra maiúscula como segundo byte, enquanto formatos com perdas não.

Como funciona

ƈƈ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
fonte
2
Esta é uma solução muito inteligente.
Mego27 /
10

C, 82 80 32 bytes

Inspirado na resposta de @Dennis ' , isso pode ser reduzido ainda mais:

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

Canalize os dados do arquivo para stdin. Retorna 0 para sem perdas ou diferente de zero para perdas.

Ou a verificação mais longa original:

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

Canalize os dados do arquivo para stdin. Retorna zero (1) para sem perdas ou 0 para perdas.

Pelo que sei, todos os formatos que você listou têm números mágicos separados (exceto AIFF / WAV, mas ambos são sem perdas de qualquer maneira), então isso apenas verifica esse número mágico quanto a um valor sem perdas conhecido. O *v&&é apenas para proteger contra arquivos correspondentes que começam com um byte nulo (M4A).

Incluí os valores que encontrei nas folhas de especificações ( fLaC= FLAC, RIFF= WAV / AIFF, TTA1= TTA) e FORM= AIFF e FFM2= TTA são dos arquivos de amostra fornecidos (só posso supor que sejam formatos de invólucro ou versões posteriores).


Ou uma alternativa mais curta, como se estivesse enganando:

Bash + arquivo, 61 bytes

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

Leva o nome do arquivo como argumento. Retorna 0 para sem perdas ou diferente de zero para perdas.

Faz exatamente o que você esperaria; pergunta filequal é o tipo de arquivo e verifica padrões conhecidos. Correspondências TTA : d( : data), AIFF / WAV IFe FLAC FL. Nenhum dos resultados sem perdas corresponde a nenhum deles, e eu testei que ainda funcionará se os nomes de arquivos forem removidos.


Teste:

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
fonte
Sua solução Bash também funciona se a extensão do arquivo estiver incorreta? "não é garantido que a extensão esteja correta para o formato", portanto, você poderá atribuir uma extensão incorreta a um arquivo e ainda assim fazê-lo funcionar.
mbomb007
@ mbomb007 Acabei de testar com as extensões misturadas e ainda as identifica bem. Eu acho que filenão confia em extensões de qualquer maneira (muitos usuários coisa renomear um png para um jpeg é o mesmo que convertê-lo!)
Dave
7

GS2 , 3 bytes

◄5ì

Formatos com perdas retornam 0 , formatos sem perdas retornam 1 .

Experimente online! (permalinks em Gist)

fundo

Os formatos que temos que suportar têm os seguintes números mágicos, ou seja, começam com esses bytes.

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

Entradas recuadas são contêineres para o formato anterior que aparecem nos casos de teste. ?indica um byte variável. .indica um byte não imprimível. Todos os outros bytes são exibidos como caracteres ISO 8859-1.

Observando apenas o segundo byte, podemos determinar o formato de uma maneira fácil:

Formatos sem perdas têm uma letra maiúscula como segundo byte, enquanto formatos com perdas não.

Como funciona

     (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
fonte
2

JavaScript (ES6), 20 bytes

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

Explicação

Toma o conteúdo do arquivo como entrada e retorna truese o arquivo é sem perdas ou falsese é lossy testando o primeiro caractere de que a entrada para ver se ele é um f, F, Rou T.


Tente

Cole o conteúdo de um arquivo no arquivo textarea.

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


Segundo esforço, 81 63 bytes

Busca o conteúdo de um arquivo a partir de uma URL fornecida, que acabou sendo um exagero.

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

Primeiro esforço, 146 116 89 bytes

Inválidos, pois os tipos MIME estão vinculados a extensões e, aparentemente, os cabeçalhos de resposta se qualificam como entrada adicional.

u=>fetch(u).then(r=>alert(/aiff|flac|tta|wave|wav$/.test(r.headers.get("Content-Type"))))
Shaggy
fonte
servidores da Web geralmente geram o MIME com base na extensão do arquivo, que é contra as regras aqui. Você verificou se funciona em arquivos veiculados sem extensão? (se isso acontecer, então você provavelmente deve incluir o nome do servidor que você está usando como parte da "linguagem")
Dave
1
@ Dave Tem certeza que não. MIME e extensão não são dependentes um do outro. Se você alterar a extensão de um arquivo e enviá-lo, o tipo MIME é o MIME do conteúdo real do arquivo, não a extensão. No entanto, receber entrada como URL provavelmente não é permitido. Não tenho certeza.
precisa saber é o seguinte
@ mbomb007 Não sei por que você diz isso; tipos mime são uma coisa da Internet, não um sistema de arquivos / arquivo, e os servidores que eu conheço determinarão isso com base na extensão usando uma pesquisa configurada (para velocidade de veiculação de cabeçalhos; eles não desejam inspecionar todos os arquivos antes de veicular isto). Tomemos, por exemplo, do Apache AddType <mime> <extension>ou IIS <MimeMap>. É claro que uma configuração específica ou arquivo ferramenta de hospedagem poderia fazer uma inspeção adequada, e que mereceria fazer a escolha servidor ser parte da resposta (uma vez que é o servidor que está determinando o tipo de arquivo!)
Dave
1
Fiz a validação de arquivos com o .NET e o tipo MIME correspondia ao conteúdo, mesmo quando a extensão foi alterada antes do upload.
precisa saber é o seguinte
@ mbomb007, o componente .NET que você usou deve ter executado a inspeção de arquivos durante o upload ou ao veicular os arquivos (eu acho que durante o upload para desempenho, mas você nunca sabe). Então, voltando ao meu comentário original, isso tornaria essa resposta algo como "JavaScript + .NET SeverLibraryXYZ". Quanto à entrada de uma URL, posso ver por que você está hesitante, mas pessoalmente consideraria válido desde que a escolha do servidor seja mencionada. Talvez exista uma meta existente, mas, no final das contas, depende de Mego.
26417 Dave
1

Chip , 11 bytes

~Z~S
t'G~aF

Replicou descaradamente a resposta de Dennis 'Jelly em Chip.

Retornos sem 0x0perdas, retornos com perdas 0x1.

Experimente on-line , links em essência (obrigado Dennis pela estratégia TIO aqui)

Explicar!

~Z~S
t'

Essa parte é de limpeza: ele Sdispara o primeiro byte e tdepois desaparece.

G~aF

Esta é a carne da decisão. Cada byte de entrada é acessado pelos bits HGFEDCBA. Se Gestiver definido e Fnão estiver, isso significa que o byte está dentro do intervalo 0x40para 0x5f(que é aproximadamente equivalente a 'maiúsculas' e bom o suficiente para a tarefa em questão).

No entanto, para economia de bytes, inverto essa decisão de G and (not F)para (not G) or F, pois ou's podem estar implícitos no Chip.

Esse valor verdadeiro / falso resultante é colocado em a, que é o bit mais baixo da saída. (Todos os outros bits serão zero). No TIO, executo a saída através do hexdump para que os valores sejam visíveis.

Equivalentemente, em C-ish, alguém poderia dizer algo como:

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

Cubix, 16 bytes

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

Formulário líquido:

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

Tente você mesmo

Você deve inserir os valores de bytes decimais do arquivo em uma lista separada. O separador não importa, qualquer coisa que não seja um dígito ou sinal de menos é suficiente. O código realmente se importa apenas com o primeiro byte, para que você possa deixar de fora o restante do arquivo, se quiser. O programa gera 0para sem perdas e 1com perdas. Experimente aqui ! A entrada padrão usa um cabeçalho FLAC.

Explicação

O bom dos arquivos é que (quase) todos eles têm a chamada mágica. Esses são os primeiros bytes do arquivo. Um bom software não verifica a extensão do arquivo, mas a mágica do arquivo para ver se ele pode lidar com um determinado arquivo.

Dennis encontrou uma maneira de usar essa mágica para encontrar o tipo de compactação, mas o fato de ele ter descartado o primeiro byte me fez querer tentar criar um método que usasse o primeiro byte, e não o segundo. Afinal, essa comunidade tem tudo a ver com salvar bytes.

Aqui está uma lista dos primeiros bytes dos diferentes tipos de arquivos. Ordenei-os em dois grupos: com e sem perdas. Aqui estão os valores do primeiro byte em decimal, hexadecimal e binário. Você já pode ver um padrão ...

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

O padrão que vi foi que o segundo bit (contado da esquerda para a direita) estava sempre ligado nos bytes "sem perdas" e o quinto bit estava sempre desligado. Essa combinação não aparece em nenhum dos formatos com perdas. Para "extrair" isso, nós simplesmente fazemos um AND binário (by 0b01001000 (=72)) e depois comparamos com 0b01000000 (=64). Se ambos são iguais, o formato de entrada é sem perdas, caso contrário, é com perdas.

Infelizmente, o Cubix não possui um operador de comparação, então usei a subtração (se o resultado for 64, isso gera 0 e resulta em 8, -56 ou -64, caso contrário, voltarei a isso mais tarde.

Primeiro, vamos começar no início do programa. O AND binário é feito usando o acomando:

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

Em seguida, comparamos com 64 usando subtração (observe que atingimos um espelho que reflete o IP na face superior [primeira linha, segundo caractere, apontando para o sul] no meio desta parte).

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

Depois que o IP é revertido pelo u, usamos algum fluxo de controle para enviar a 1para a pilha se (e somente se) a parte superior da pilha for diferente de zero:

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

Depois de envolvermos o cubo, atingimos a <instrução, que aponta o IP para oeste na quarta linha. Tudo o que resta a fazer é produzir e terminar.

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

Portanto, o programa gera 0sem perdas e 1com perdas.

Lucas
fonte