Jeg vil rippe / arkivere hele min musiksamling til et tabsfrit, men komprimeret filformat, dvs. filerne skal alle være perfekte , tabsfri gengivelse af de originale data, men skulle forbruge mindre plads end ukomprimeret WAV (E).
WAV (E) er et no-go, da det er ikke-gratis (proprietære Microsoft-ting), kompression på tværs af platforme er besværlig eller ikke mulig, og filstørrelsen er begrænset til 4 GB. Derfor vælger jeg FLAC (Free Lossless Audio Codec).
Da digitalisering af en hel samling er en enorm opgave, og FLAC tilbyder 9 kompressionsniveauer (0 til 8), kommer det gyldne spørgsmål :
Hvilket komprimeringsniveau skal jeg klogt vælge?
Kommentarer
- dette spørgsmål ' t adresserer lyddesign overhovedet, men det berører et valg, som nogle lyddesignere står over for, hvilket er, hvordan man bedst håndterer vores stadigt voksende optagelsesbiblioteker. Personligt går jeg ' FLAC over WAVE simpelthen på grund af lagringsproblemet, men jeg ' er bange for, at jeg ikke ' ikke har nogen indsigt i komprimeringsniveauet.
- Interessant jeg skrev dette på Musik først, men folkene der anbefalede at flytte det til lyddesign.
Svar
FLAC-komprimeringsniveauer er (kun) en handel mellem kodningstid og filstørrelse . Afkodningstiden er stort set uafhængig af kompressionshastigheden. I det følgende vil jeg henvise til kompressionsniveauerne 0, …, 8 som FLAC-0, …, FLAC-8.
Kort sagt : Jeg anbefaler FLAC-4 !
De lette løsninger
Selvfølgelig:
-
Hvis jeg ikke bryr mig om kodningstid, og da plads er penge, tager jeg det højeste kompressionsniveau FLAC-8 .
-
Hvis jeg ikke er ligeglad med plads, men ønsker at komme bag dette så hurtigt som muligt, tager jeg det laveste komprimeringsniveau FLAC-0 .
Den vanskelige løsning
Hvor er højre midten mellem filstørrelse og kodningstid? Jeg snuble over Nathan Zacharys artikel om dette spørgsmål, men han sammenligner kun to filer, koder dem kun en gang (kodningstiden varierer meget alt efter computerens sidelastning ) og tabeller er svære at læse i forhold til grafer.
Så inspireret af dette rediderede jeg hans målinger med fem komplette album hver i en anden genre og kodede hver fil / spor 10 gange .
Procedure:
- Riv album med
abcde
og korrektcdparanoia
indstillinger til ukomprimeret WAV. - Konverter hver fil 10 gange for hvert komprimeringsniveau (FLAC-0 til FLAC-8) og tag middel kodningstid i forhold til FLAC-0 og filstørrelse i forhold til F LAC-0 .
- Til dette deaktiverede jeg internetforbindelse, alle periodiske job (
cronjobs
) og næsten alt andet, så virkelig komprimeringen kører og så mindre som mulig interferens.
- Til dette deaktiverede jeg internetforbindelse, alle periodiske job (
Denne foranstaltning skal være stort set uafhængig af den anvendte hardware. Jeg brugte flac version 1.3.2 på Arch Linux ved hjælp af flac <infile> --compression-level-X -f -o flacX.flac
.
Effektivitet
Hvis du multiplicerer relativ størrelse med relativ kodning / kompressionstid , får du en værdi for dårligheden . Men da denne dårlighed for det meste styres af den relative tid, ville graferne overlappe hinanden meget. Så for at rydde grafen spejlede jeg bare dårlighed til en godhed jeg kalder effektivitet her.
Resultater
Fra FLAC-4 på eksploderer kompressionstiden, MEN der er to overraskelser:
-
Der er en signifikant reduktion i filstørrelse mellem FLAC-3 og FLAC-4 afhængigt af musikgenren: Klassisk musik har en måde lavere kompression ved hjælp af FLAC-4. Jeg antager, at dette skyldes, at FLAC bruger en lineær forudsigelsesmodel til komprimering, der klarer sig mindre godt med mere kompleks (mindre lineær) musik.
-
For ikke-klassisk musik, FLAC-3 er endda betydeligt dårligere end FLAC-2 i form af filstørrelse.
Anbefalinger
Jeg anbefaler at bruge komprimeringsniveau FLAC-4 .
Hvis du går højere, øges kodningstiden markant med marginal forbedring af filstørrelsesreduktion (middelreduktion fra FLAC-4 til FLAC-8 i denne test er 1,2% med en 182% stigning i gennemsnitlig kompressionstid).
Appendiks
Album
Jeg tog lige de første fem tilfældige cder (angivet nedenfor) at jeg tænkte på repræsenterer forskellige musikfelt. Links går bevidst til Amazon for at give en let mulighed for at få et glimt af musikken / for at få en idé om musikken, da det gør en signifikant forskel i komprimeringen.
- Emil Gilels – Beethoven: Klaversonater nr. 21 “Waldstein”, 26 “Les Adieux” & 23 “Appassionata” ( klassisk)
- Karl Jenkins – Den væbnede mand – En messe for fred (klassisk, masse)
- Unni Wilhelmsen – 7 (pop, jazz, folkemusik)
- Alin Coen Band – We ” re Not the Ones We Thought We Were (indie, folk, singer-songwriter)
- Bukahara – Bukahara Trio ( neofolk , balkanfolk )
Program
Til denne opgave skrev jeg et python
program, der går gennem alle undermapper (albummerne) i en given mappe () for at teste alle .wav-filer og gruppere / plotte dem efter deres undermappens navn.
<folder> Album 1 Album 2 ...
Analysen gemmes i en fil --outfile <file1>
. For at plotte skal du bruge --infile <file1>
og --outfile <file2>
.
#!/usr/bin/python3 #encoding=utf8 import os, sys, subprocess, argparse from datetime import datetime, timedelta from os.path import isfile, isdir, join import numpy as np import matplotlib.pyplot as plt import pickle as pkl parser = argparse.ArgumentParser(description="Analyse flac compression and conversion time") group = parser.add_mutually_exclusive_group() group.add_argument("-d", "--directory", help="Input folder", type=str) group.add_argument("-if", "--infile", help="Plot saved stats (pickle file)", type=str) parser.add_argument("-of", "--outfile", help="Output file", type=str, required=True) parser.add_argument("-c", "--cycles", help="Number of cycles for each file", type=int, default=5) parser.add_argument("-C", "--maxcompression", help="Max compression level", type=int, default=8) args = parser.parse_args() args.maxcompression += 1 ############################################################ xlabel = "FLAC Compression Factor" ylabel_size = "Size Relative to FLAC-0" ylabel_time = "Mean Compression Time\nOver {} Cycles Relative to FLAC-0 [s]".format(args.cycles) ylabel_efficiency = r"Efficiency: $(-1)\cdot$ Fraction Time $\cdot$ Fraction Size $+ 2$" ############################################################ # Analyse and write mode if not args.infile: if isdir(args.directory): mypath = args.directory else: raise ValueError("Folder {} does not exist!".format(args.directory)) folders = [f for f in os.listdir(mypath) if isdir(join(mypath, f))] print("Found folders: {}".format(folders)) # Create temporary working folder temp_folder = "temp_{}".format(os.getpid()) if not os.path.exists(temp_folder): os.makedirs(temp_folder) # Every analysis will be storen in stats stats = {} remove = [] for folder in folders: stats[folder] = {} stats[folder]["files"] = [f for f in os.listdir(mypath+folder) if isfile(join(mypath+folder, f)) and f.endswith(".wav")] if len(stats[folder]["files"]) == 0: print("No .wav files found in {}. Skipping.".format(folder)) remove.append(folder) stats.pop(folder, None) else: stats[folder]["stats"] = np.empty([len(stats[folder]["files"]),args.maxcompression], dtype=object) # Remove empty (no .wav) folders from list for folder in remove: folders.remove(folder) totalfiles = [] for folder in folders: totalfiles += stats[folder]["files"] totalfiles = len(totalfiles) if totalfiles == 0: raise RuntimeError("No .wav files found!") totalcycles = totalfiles * args.cycles * args.maxcompression counter_cycles = 0 time_start = datetime.strptime(str(datetime.now()), "%Y-%m-%d %H:%M:%S.%f") for folder in folders: # i: 0..Nfiles # n: 0..8 files = stats[folder]["files"] for i in range(len(files)): infile = "{}/{}".format(mypath+folder,files[i]) for n in range(args.maxcompression): Dtime = [] for j in range(args.cycles): time1 = datetime.strptime(str(datetime.now()), "%Y-%m-%d %H:%M:%S.%f") subprocess.run(["flac", infile, "--compression-level-{}".format(n), "-f", "-o", "{}/flac{}.flac".format(temp_folder,n)]) time2 = datetime.strptime(str(datetime.now()), "%Y-%m-%d %H:%M:%S.%f") Dtime.append((time2-time1).total_seconds()) counter_cycles += 1 # Percentage of totalcycles status = counter_cycles/totalcycles remain_factor = (1 - status)/status time_current = datetime.strptime(str(datetime.now()), "%Y-%m-%d %H:%M:%S.%f") time_elapsed = (time_current - time_start).total_seconds() print("========================================") print("Status: {} %".format(int(100*status))) print("Estimated remaining time: {}".format(str(timedelta(seconds=int(remain_factor * time_elapsed))))) print("========================================") Dtime = np.mean(Dtime) size = os.path.getsize("{}/flac{}.flac".format(temp_folder,n)) # Array if size (regarded as constat) and mean compression time # (file1, FLAC0)(file1, FLAC1)...(file1, FLACmaxcompression) # (file2, FLAC0)(file2, FLAC1)...(file2, FLACmaxcompression) # ... stats[folder]["stats"][i,n] = (size, Dtime) for folder in folders: # Taking columnwise (for each compression level) means of size... stats[folder]["ploty_size"] = [np.mean([e[0] for e in stats[folder]["stats"][:,col]]) for col in range(np.shape(stats[folder]["stats"])[1])] # (relative to FLAC-0) stats[folder]["ploty_size"] = [i/stats[folder]["ploty_size"][0] for i in stats[folder]["ploty_size"]] # ... and mean time. stats[folder]["ploty_time"] = [np.mean([e[1] for e in stats[folder]["stats"][:,col]]) for col in range(np.shape(stats[folder]["stats"])[1])] # (relative to FLAC-0) stats[folder]["ploty_time"] = [i/stats[folder]["ploty_time"][0] for i in stats[folder]["ploty_time"]] # Rough "effectivity" estimation -size*time + 2 # Expl.: Starts at (0,1), therefore flipping with (-1) requires # + 2. Without (-1) would be "badness" stats[folder]["ploty_eff"] = [ 2 + (-1) * stats[folder]["ploty_size"][i] * stats[folder]["ploty_time"][i] for i in range(len(stats[folder]["ploty_size"]))] with open(args.outfile, "wb") as of: data = {} data["stats"] = stats data["folders"] = folders data["cycles"] = args.cycles data["maxcompression"] = args.maxcompression pkl.dump(data, of, protocol=pkl.HIGHEST_PROTOCOL) if os.path.isdir(temp_folder): subprocess.run(["rm", "-r", temp_folder]) else: with open(args.infile, "rb") as f: data = pkl.load(f) stats = data["stats"] folders = data["folders"] args.maxcompression = data["maxcompression"] args.cycles = data["cycles"] fig = plt.figure() plotx = range(args.maxcompression) pos = range(len(plotx)) ax_size = fig.add_subplot(111) ax_size.set_xticks(pos) ax_size.set_xticklabels(plotx) ax_size.set_title("FLAC compression comparison") ax_time = ax_size.twinx() ax_efficiency = ax_size.twinx() colorfracs = [i / (len(folders)-0.9) if i > 0 else 0 for i in range(len(folders))] # Actual plotting lns = [] for cfrac, folder in zip(colorfracs, folders): color = plt.cm.viridis(cfrac) l_size, = ax_size.plot(plotx, stats[folder]["ploty_size"], color=color, linestyle=":", label="Size Ratio: {}".format(folder)) l_time, = ax_time.plot(plotx, stats[folder]["ploty_time"], color=color, linestyle="--", label="Time Ratio: {}".format(folder)) l_eff, = ax_efficiency.plot(plotx, stats[folder]["ploty_eff"], color=color, linestyle="-", label="Efficiency: {}".format(folder)) lns.append(l_size) lns.append(l_time) lns.append(l_eff) ax_efficiency.spines["right"].set_position(("outward", 60)) ax_size.xaxis.grid(color=".85", linestyle="-", linewidth=.5) ax_size.set_xlabel(xlabel) ax_size.set_ylabel(ylabel_size) ax_efficiency.set_ylabel(ylabel_efficiency) ax_time.set_ylabel(ylabel_time) lgd = ax_time.legend(handles=lns, loc="upper center", bbox_to_anchor=(0.5, -.15), facecolor="#FFFFFF", prop={"family": "monospace","size": "small"}) fig.savefig(args.outfile, bbox_inches="tight", dpi=300)
Kommentarer
- Whoa … dette er en fantastisk kvantitativ analyse, du gjorde der! Jeg sætter stor pris på, at du tog dig tid til at gøre alt dette. Kunne ikke ' t have været hurtige, men virkelig gode resultater. Tak!
Svar
Flac 0. Opbevaring er så billig i disse dage, virker som en no brainer for mig … også Flac 0 er mindre tilbøjelige til at hikke på et langsommere system, da afkodning er mindre krævende at afkode.
Svar
Som opfølgning på Suuuehgis svar vil jeg også gerne tilføje, at hvis du starter fra en CD og rippe det direkte til FLAC, kodningstid betyder muligvis ikke noget, fordi du skal først rippe musikken, hvilket tager tid.
Her er hvad jeg prøvede:
Ved hjælp af dbPowerAmp CD Ripper rev jeg min kopi af Mariah Carey “s " Merry Jul " album. Jeg rev det en gang på FLAC-komprimeringsniveau 8, en gang på niveau 5 (dbPowerAmps standard) og en gang på niveau 0.
Her er i alt gange for hver rip, fra klik på start til slut med alle FLAC-filer udført:
Niveau 0 = 6:19
Niveau 5 = 6:18
Niveau 8 = 6:23
Som du kan se, er variansen mellem alle 3 minimal, inden for < 5 sekunder af hinanden. Da jeg så det rippe og kode, var kodningsstatusen et blitz på skærmen, næsten registreret. Og når man så filsystemet, da det rippede, så det ud til at koder på farten, da det rippede. YMMV på langsommere systemer dog.
Hvad angår filstørrelser, her er de producerede filstørrelser:
Niveau 0 = 278 MB
Niveau 5 = 257 MB
Niveau 8 = 256 MB
Mens den samlede rip og enc ode-tider var stort set de samme, filstørrelserne var dog ikke, men der er bestemt faldende afkast i de senere kompressionsniveauer (som Suuuehgis svar henviser til).
For mig ser det ud til, at hvis du starter fra cder og har en anstændig pc, den tid, det tager at rippe og kode, vil ikke ændre sig meget baseret på FLAC-komprimeringsniveauet. Filstørrelsen ændres dog. Jeg synes, at dbPowerAmps-forslag om FLAC-niveau 5 som standard er godt. Kun 1 MB forskel mellem FLAC 5 og FLAC 8, hvor-som om du går FLAC 0, viser mit eksempel 21 MB i overskud af lagerplads, der kunne gemmes. Det virker måske ikke meget, men når du ripper store samlinger, tilføjer det hurtigt (en enkelt FLAC-sang kan være omkring den størrelse.)
Dette blev gjort på et skrivebord med et USB 2 DVD-drev , ripper i gennemsnit med 7x hastighed. Mine desktop-pc-specifikationer er en Intel Core i5-6500 CPU @ 3,2 GHz, 16 GB RAM og et Samsung 860 EVO Sata SSD-drev.