FLAC, le format audio est-il vraiment sans perte ?

On nous dit que le format audio FLAC est sans perte. Faut-il prendre la chose littéralement ou bien « c’est presque pareil mais de toute façon tes oreilles n’entendront pas la différence ».

Je n’ai ni la feuille ni le vocabulaire de l’ingénieur du son ou de l’audiophile, on va plutôt raisonner à partir de mesures. On partira d’un fichier wav linéaire qu’on encodera en FLAC puis qu’on redécodera en linéaire, on verra alors si on retrouve le même fichier source au bit près… ou pas.

🏋️ Flexion / Extension

Notre fichier audio d’origine a les caractéristiques suivantes :

$ mediainfo sample-src.wav
General
Complete name                            : sample-src.wav
Format                                   : Wave
File size                                : 24.6 MiB
Duration                                 : 2 min 14 s
Overall bit rate mode                    : Constant
Overall bit rate                         : 1 536 kb/s

Audio
Format                                   : PCM
Format settings                          : Little / Signed
Codec ID                                 : 1
Duration                                 : 2 min 14 s
Bit rate mode                            : Constant
Bit rate                                 : 1 536 kb/s
Channel(s)                               : 2 channels
Sampling rate                            : 48.0 kHz
Bit depth                                : 16 bits
Stream size                              : 24.6 MiB (100%)

Maintenant encodons le en FLAC à l’aide d'ffmpeg :

$ ffmpeg -i sample-src.wav sample-tmp.flac

Regardons la place gagnée :

$ ls -l sample-* | awk '{print $5,$9}'
25754856 sample-src.wav
18271243 sample-tmp.flac

Le ratio est de 70.94%, on a gagné presque un tiers, avec la promesse de ne rien perdre, pas si mal si ça se confirme 👌 .

mediainfo nous confirme la validité du nouveau fichier audio compressé :

$ mediainfo sample-tmp.flac
General
Complete name                            : sample-tmp.flac
Format                                   : FLAC
Format/Info                              : Free Lossless Audio Codec
File size                                : 17.4 MiB
Duration                                 : 2 min 14 s
Overall bit rate mode                    : Variable
Overall bit rate                         : 1 090 kb/s
Writing application                      : Lavf58.76.100

Audio
Format                                   : FLAC
Format/Info                              : Free Lossless Audio Codec
Duration                                 : 2 min 14 s
Bit rate mode                            : Variable
Bit rate                                 : 1 089 kb/s
Channel(s)                               : 2 channels
Channel layout                           : L R
Sampling rate                            : 48.0 kHz
Bit depth                                : 16 bits
Compression mode                         : Lossless
Stream size                              : 17.4 MiB (100%)
Writing library                          : Lavf58.76.100

Reconvertissons le en wav :

$ ffmpeg -i sample-tmp.flac sample-dst.wav

Note: il existe un paramètre -compression_level compris entre 0 et 12, par défaut à 5. Une étude montre qu’une forte compression ne réduit pas tant que ça la taille mais augmente significativement le temps d’encodage. Bref laissons la valeur par défaut.

Comparons maintenant les fichiers wav source et destination :

$ diff sample-src.wav sample-dst.wav
Binary files sample-src.wav and sample-dst-test.wav differ

Aille, c’est un échec, les fichiers diffèrent 🤔.

$ ls -l sample-*.wav | awk '{print $5,$9}'
25754890 sample-dst.wav
25754856 sample-src.wav

Effectivement il y a 34 octets de différence en taille 🤏.

Regardons de plus près si les données audio sont réellement différentes ou si c’est juste une histoire de métadonnées ajoutées dans l’entête par nos conversions successives…

Dump des premiers octets du fichier source 🤓 :

$ hexdump -C sample-src.wav | head -n 8
00000000  52 49 46 46 02 fd 88 01  57 41 56 45 66 6d 74 20  |RIFF....WAVEfmt |
00000010  10 00 00 00 01 00 02 00  80 bb 00 00 00 ee 02 00  |................|
00000020  04 00 10 00 4c 49 53 54  1a 00 00 00 49 4e 46 4f  |....LIST....INFO|
00000030  49 53 46 54 0e 00 00 00  4c 61 76 66 35 38 2e 37  |ISFT....Lavf58.7|
00000040  36 2e 31 30 30 00 64 61  74 61 bc fc 88 01 70 0d  |6.100.data....p.|
00000050  93 0f a2 12 fe 08 d7 15  d2 00 df 18 80 fc 46 20  |..............F |
00000060  5c ff 46 29 40 04 a5 29  70 06 c6 20 51 07 8b 17  |\.F)@..)p.. Q...|
00000070  27 08 6b 10 61 08 5e 0b  7b 09 be 0b 44 0c 36 0e  |'.k.a.^.{...D.6.|

Dump des premiers octets du fichier destination 🤓 :

$ hexdump -C sample-dst.wav | head -n 8
00000000  52 49 46 46 e0 fc 88 01  57 41 56 45 66 6d 74 20  |RIFF....WAVEfmt |
00000010  10 00 00 00 01 00 02 00  80 bb 00 00 00 ee 02 00  |................|
00000020  04 00 10 00 64 61 74 61  bc fc 88 01 70 0d 93 0f  |....data....p...|
00000030  a2 12 fe 08 d7 15 d2 00  df 18 80 fc 46 20 5c ff  |............F \.|
00000040  46 29 40 04 a5 29 70 06  c6 20 51 07 8b 17 27 08  |F)@..)p.. Q...'.|
00000050  6b 10 61 08 5e 0b 7b 09  be 0b 44 0c 36 0e 1c 0c  |k.a.^.{...D.6...|
00000060  62 0c a1 06 7d 09 3a 03  06 0a b8 05 52 09 c4 06  |b...}.:.....R...|
00000070  43 04 c1 02 c0 01 b4 fa  2b 06 51 ec f4 0a 80 dd  |C.......+.Q.....|

L’entête diffère avec le chunk LIST qui est présent dans le fichier destination mais pas le source, l’hypothèse de la réécriture de l’entête par ffmpeg se confirme. Les données audio brutes (après le data) semblent être les mêmes.

Précisons maintenant au convertisseur de ne pas générer de métadonnées particulières :

$ ffmpeg -i sample-tmp.flac -fflags +bitexact sample-dst.wav

Un rapide contrôle de la taille des fichiers :

$ ls -l sample-*.wav | awk '{print $5,$9}'
25754856 sample-dst.wav
25754856 sample-src.wav

De bon augure, refaisons la comparaison binaire 🤞 :

$ diff sample-src.wav sample-dst.wav

🏆 C’est bon, on a bien retrouvé notre fichier d’origine, au bit près ! 🏆

Je ne prends donc même pas la peine de faire une analyse spectrale ou autre, les données sont rigoureusement les mêmes, « ça sonnera pareil ».

Mais on aurait pas pu le zipper ?

Il existe d’autres types de compression générique, sans pertes, comme zip ou gzip, pourquoi ne pas les avoir utilisés ?

$ zip sample-src.zip sample-src.wav
  adding: sample-src.wav (deflated 1%)
$ ls -l sample-src.zip | awk '{print $5,$9}'
25425169 sample-src.zip

Ratio 98.72% 😞

$ tar zfcv sample-src.tar.gz sample-src.wav
a sample-src.wav
$ ls -l sample-src.tar.gz | awk '{print $5,$9}'
25436294 sample-src.tar.gz

Ratio 98.76% 😞

Le gain est quasi nul 😮 ! De plus le temps de décompression préalable à la lecture augmente proportionnellement avec la taille et la durée du fichier. On comprend mieux l’intérêt des formats de compression spécifiques aux fichiers media.

Conclusion

Le format FLAC est bien sans perte ✅. Ses spécifications étant libres et ouvertes, c’est finalement un bon candidat pour l’archivage sonore de votre discothèque 💿.

Ressources

comments powered by Disqus