Rugi atau Rugi?

18

Diberikan file audio, tentukan apakah itu dikodekan dalam format lossy atau format lossless. Untuk keperluan tantangan ini, hanya format berikut yang perlu diklasifikasikan:

Aturan

  • Jika input diambil dalam bentuk nama file, tidak ada asumsi yang harus dibuat tentang nama file (misalnya ekstensi tidak dijamin benar untuk format, atau bahkan ada).
  • Tidak akan ada metadata ID3 atau APEv2 yang ada dalam file input.
  • Dua output unik dan dapat dibedakan dapat digunakan, seperti 0dan 1, lossydan lossless, foodan bar, dll.

Uji Kasus

Kasing uji untuk tantangan ini terdiri dari file zip yang terletak di sini yang berisi dua direktori: lossydan lossless. Setiap direktori berisi beberapa file audio yang semuanya 0,5 detik gelombang sinus 440 Hz, disandikan dalam berbagai format. Semua file audio memiliki ekstensi yang cocok dengan format di atas, dengan pengecualian A440.m4a(yang merupakan audio AAC dalam wadah MPEG Layer 4).

Mego
sumber
" Audio AAC dalam wadah MPEG Layer 4 " menimbulkan pertanyaan: format wadah apa yang harus dijawab?
Peter Taylor
@PeterTaylor Only AAC diberi perhatian khusus karena saya tidak bisa menemukan cara untuk menyediakan audio AAC tanpa menyematkannya dalam wadah MPEG Layer 4 via FFMPEG. Audio Vorbis tertanam dalam wadah Ogg (seperti norma untuk audio Vorbis). Yang lainnya adalah format mandiri.
Mego
Apakah Anda yakin tentang file TTA? Menurut spec , file TTA harus dimulai dengan angka ajaib TTA1 atau TTA2. FFM2 (angka ajaib dari file Anda) tampaknya sesuai dengan aliran FFmpeg. File Linux mengenali header TTA1, tetapi bukan yang FFM2.
Dennis
Juga, dapatkah kita berasumsi bahwa AAC akan selalu berada di header MPEG Layer 4? Jika tidak, apa yang bisa kita asumsikan?
Dennis
Bisakah kita mengambil konten file sebagai input atau kode kita harus mengambilnya?
Shaggy

Jawaban:

18

Jelly , 7 5 byte

ƈƈeØA

Format lossy mengembalikan 0 , format lossless mengembalikan 1 .

Cobalah online! (permalinks dalam Gist)

Latar Belakang

Format yang harus kita dukung memiliki angka ajaib berikut, yakni mulai dengan byte ini.

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

Entri lekukan adalah wadah untuk format sebelumnya yang muncul dalam kasus uji. ?menunjukkan byte variabel. .menunjukkan byte yang tidak dapat dicetak. Semua byte lainnya ditampilkan sebagai karakter ISO 8859-1 mereka.

Dengan hanya melihat byte kedua, kita dapat menentukan format dengan cara yang mudah:

Format lossless memiliki huruf besar sebagai byte kedua, sedangkan format lossy tidak.

Bagaimana itu bekerja

ƈƈ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
sumber
2
Ini adalah solusi yang sangat cerdas.
Mego
10

C, 82 80 32 byte

Terinspirasi oleh jawaban @Dennis , ini dapat dikurangi lebih jauh:

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

Pipa data file ke stdin. Mengembalikan 0 untuk lossless, atau bukan nol untuk lossy.

Atau cek lagi yang asli:

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

Pipa data file ke stdin. Mengembalikan bukan nol (1) untuk lossless, atau 0 untuk lossy.

Dari apa yang bisa saya katakan, semua format yang Anda daftarkan memiliki angka ajaib yang terpisah (kecuali AIFF / WAV, tetapi keduanya sama-sama lossless), jadi ini hanya memeriksa angka ajaib itu untuk nilai lossless yang diketahui. Ini *v&&hanya untuk melindungi file yang cocok yang dimulai dengan byte nol (M4A).

Saya telah memasukkan nilai yang saya temukan di lembar spesifikasi ( fLaC= FLAC, RIFF= WAV / AIFF, TTA1= TTA), dan FORM= AIFF dan FFM2= TTA berasal dari file sampel yang disediakan (Saya hanya bisa menebak ini adalah format pembungkus atau versi yang lebih baru).


Atau alternatif kecurangan yang terasa seperti:

File Bash +, 61 byte

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

Mengambil nama file sebagai argumen. Mengembalikan 0 untuk lossless, atau bukan nol untuk lossy.

Lakukan persis seperti yang Anda harapkan; bertanya fileapa jenis file itu, kemudian memeriksa pola yang dikenal. Pertandingan TTA : d( : data), pertandingan AIFF / WAV IF, dan FLAC FL. Tak satu pun dari hasil lossless cocok dengan semua ini, dan saya telah menguji bahwa itu masih berfungsi jika nama file dihapus.


Pengujian:

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
sumber
Apakah solusi Bash Anda juga berfungsi jika ekstensi file salah? "ekstensi tidak dijamin benar untuk format", jadi Anda harus dapat memberikan ekstensi file yang salah dan tetap membuatnya berfungsi.
mbomb007
@ mbomb007 Saya baru saja menguji dengan ekstensi dicampur dan masih mengidentifikasi mereka baik-baik saja. Saya pikir bagaimanapun filejuga tidak percaya ekstensi (banyak pengguna mengubah nama png menjadi jpeg sama dengan mengonversinya!)
Dave
7

GS2 , 3 byte

◄5ì

Format lossy mengembalikan 0 , format lossless mengembalikan 1 .

Cobalah online! (permalinks dalam Gist)

Latar Belakang

Format yang harus kita dukung memiliki angka ajaib berikut, yakni mulai dengan byte ini.

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

Entri lekukan adalah wadah untuk format sebelumnya yang muncul dalam kasus uji. ?menunjukkan byte variabel..menunjukkan byte yang tidak dapat dicetak. Semua byte lainnya ditampilkan sebagai karakter ISO 8859-1 mereka.

Dengan hanya melihat byte kedua, kita dapat menentukan format dengan cara yang mudah:

Format lossless memiliki huruf besar sebagai byte kedua, sedangkan format lossy tidak.

Bagaimana itu bekerja

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

JavaScript (ES6), 20 byte

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

Penjelasan

Mengambil isi file sebagai input dan kembali truejika file tersebut lossless atau falsejika lossy dengan menguji karakter pertama dari masukan itu untuk melihat apakah itu adalah f, F, Ratau T.


Cobalah

Rekatkan isi file ke dalam textarea.

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


Upaya kedua, 81 63 byte

Mengambil konten file dari URL yang disediakan, yang ternyata berlebihan.

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

Upaya pertama, 146 116 89 byte

Tidak valid karena tipe mime terkait dengan ekstensi dan, tampaknya, header respons memenuhi syarat sebagai input tambahan.

u=>fetch(u).then(r=>alert(/aiff|flac|tta|wave|wav$/.test(r.headers.get("Content-Type"))))
Shaggy
sumber
server web biasanya menghasilkan MIME berdasarkan ekstensi file, yang melanggar aturan di sini. Sudahkah Anda memeriksa apakah itu berfungsi pada file yang dilayani tanpa ekstensi? (jika ya, Anda mungkin harus memasukkan nama server yang Anda gunakan sebagai bagian dari "bahasa")
Dave
1
@Dave Cukup yakin mereka tidak. MIME dan ekstensi sama sekali tidak bergantung satu sama lain. Jika Anda mengubah ekstensi file dan mengunggahnya, tipe MIME adalah MIME dari konten file yang sebenarnya, bukan ekstensi. Namun, menerima masukan sebagai URL mungkin tidak diizinkan. Saya tidak yakin.
mbomb007
@ mbomb007 Saya tidak yakin mengapa Anda mengatakan itu; tipe mime adalah hal internet, bukan sistem file / file, dan server yang saya ketahui akan menentukannya berdasarkan ekstensi menggunakan pencarian yang dikonfigurasi (untuk kecepatan penyajian header; mereka tidak ingin memeriksa setiap file sebelum melayani Itu). Ambil contoh Apache AddType <mime> <extension>, atau IIS <MimeMap>. Tentu saja alat penyiapan atau penginangan file tertentu dapat melakukan inspeksi yang tepat, dan itu pantas membuat pilihan server menjadi bagian dari jawabannya (karena serverlah yang menentukan jenis file!)
Dave
1
Saya telah melakukan validasi file dengan .NET, dan tipe MIME cocok dengan konten bahkan ketika ekstensi diubah sebelum diunggah.
mbomb007
@ mbomb007 lalu komponen NET mana pun yang Anda gunakan harus telah melakukan pemeriksaan file baik selama upload atau ketika melayani file (saya kira selama mengunggah untuk kinerja, tapi Anda tidak pernah tahu). Jadi kembali ke komentar asli saya, yang akan membuat jawaban ini seperti "JavaScript + .NET SeverLibraryXYZ". Adapun untuk mengambil input dari URL, saya dapat melihat mengapa Anda ragu-ragu tetapi secara pribadi saya akan menganggapnya valid selama pilihan server disebutkan. Mungkin ada meta yang ada di sana, tapi akhirnya tentu saja terserah Mego.
Dave
1

Chip , 11 byte

~Z~S
t'G~aF

Tanpa malu-malu meniru jawaban Dennis 'Jelly di Chip.

Returnless loss 0x0, returny lossy 0x1.

Cobalah online , tautan di intisari (terima kasih Dennis untuk strategi TIO di sini)

Menjelaskan!

~Z~S
t'

Porsi ini adalah housekeeping: ia Smengambil byte pertama, dan tberkembang setelah byte kedua.

G~aF

Ini adalah daging keputusan. Setiap byte input diakses oleh bit HGFEDCBA. Jika Gdiatur, dan Ftidak, itu berarti byte berada dalam kisaran 0x40ke0x5f (yang kira-kira setara dengan 'huruf besar', dan cukup baik untuk tugas yang dihadapi).

Namun, untuk penghematan byte, saya membalikkan keputusan ini dari G and (not F)menjadi(not G) or F , karena atau dapat tersirat dalam Chip.

Nilai true / false yang dihasilkan ini kemudian ditempatkan ke dalam a , yang merupakan bit terendah dari output. (Semua bit lainnya akan menjadi nol). Di TIO, saya menjalankan output melalui hexdump sehingga nilainya terlihat.

Secara ekuivalen, dalam C-ish, orang akan mengatakan sesuatu seperti:

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

Cubix, 16 byte

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

Bentuk bersih:

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

Cobalah sendiri

Anda harus memasukkan nilai byte desimal file dalam daftar yang terpisah. Pemisah tidak masalah, apa pun yang bukan angka atau tanda minus sudah cukup. Kode ini benar-benar hanya peduli pada byte pertama, sehingga Anda dapat meninggalkan sisa file jika Anda mau. Output program 0untuk lossless, dan 1lossy. Coba di sini ! Input default menggunakan header FLAC.

Penjelasan

Yang menyenangkan tentang file adalah (hampir) semuanya memiliki keajaiban. Itu adalah beberapa byte pertama dari file. Perangkat lunak yang baik tidak memeriksa ekstensi file, tetapi sihir file untuk melihat apakah ia dapat menangani file tertentu.

Dennis telah menemukan cara untuk menggunakan sihir ini untuk menemukan tipe kompresi, tetapi fakta bahwa ia membuang byte pertama membuat saya ingin mencoba membuat metode yang menggunakan byte pertama, bukan yang kedua. Bagaimanapun, komunitas ini adalah tentang cara menyimpan byte.

Berikut adalah daftar byte pertama dari berbagai jenis file. Saya memesannya dalam dua kelompok: lossy dan lossless. Berikut adalah nilai byte pertama mereka dalam desimal, heksadesimal, dan biner. Anda mungkin sudah melihat pola ...

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

Pola yang saya lihat, adalah bahwa bit kedua (dihitung dari kiri ke kanan) selalu menyala pada byte "lossless" dan bit kelima selalu mati. Kombinasi ini tidak muncul dalam format lossy mana pun. Untuk "mengekstrak" ini, kita cukup melakukan biner AND (oleh 0b01001000 (=72)) dan kemudian membandingkannya dengan 0b01000000 (=64). Jika keduanya sama, format input adalah lossless, jika tidak lossy.

Sayangnya, Cubix tidak memiliki operator pembanding seperti itu, jadi saya menggunakan pengurangan (jika hasilnya 64, ini menghasilkan 0, dan hasilnya 8, -56 atau -64 sebaliknya. Saya akan kembali ke sini nanti.

Pertama, mari kita mulai dari awal program. Biner AND dilakukan dengan menggunakan aperintah:

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

Kemudian, kami membandingkan dengan 64 menggunakan pengurangan (perhatikan kami menabrak cermin yang mencerminkan IP ke wajah atas [baris pertama, karakter kedua, menunjuk ke selatan] di tengah bagian ini).

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

Setelah IP diputar oleh u, kami menggunakan beberapa aliran kontrol untuk mendorong a 1ke tumpukan jika (dan hanya jika) bagian atas tumpukan tidak nol:

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

Setelah kami membungkus kubus, kami menekan <instruksi, yang menunjuk IP barat di baris keempat. Yang harus dilakukan hanyalah output dan terminasi.

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

Jadi, output program 0untuk lossless, dan 1untuk lossy.

Luke
sumber