Chci zkopírovat / archivovat celou svou hudební sbírku do bezztrátového, ale komprimovaného formátu, tj. Všechny soubory by měly být dokonalé , bezztrátová reprezentace původních dat, ale měla by zabírat méně místa než nekomprimovaný WAV (E).
WAV (E) je zakázán, protože je nesvobodný (proprietární obsah společnosti Microsoft), multiplatformní komprese je těžkopádná nebo není možná a velikost souboru je omezeno na 4 GB. Proto volím FLAC (Free Lossless Audio Codec).
Protože digitalizace celé kolekce je mamutí úkol a FLAC nabízí 9 úrovní komprese (0 až 8), přichází zlatá otázka :
Kterou úroveň komprese bych měl moudře zvolit?
Komentáře
- tato otázka vůbec ' neřeší zvukový design, ale dotýká se volby, které někteří zvukoví designéři čelí, což je, jak nejlépe zacházet s našimi stále rostoucími knihovnami nahrávek. Osobně jdu ' m FLAC přes WAVE jednoduše kvůli problému s ukládáním, ale ' bojím se ' nemám žádný přehled o úrovni komprese.
- Zajímavé je, že jsem zveřejnil nejprve na hudbě , ale lidé tam doporučili přesunout ji do Sound Design.
Odpovědět
Úrovně komprese FLAC jsou (pouze) obchodem mezi časem kódování a velikost souboru . Doba dekódování je do značné míry nezávislá na rychlosti komprese. V následujícím textu budu označovat úrovně komprese 0, …, 8 jako FLAC-0, …, FLAC-8.
Zkrátka : doporučuji FLAC-4 !
Snadná řešení
Je zřejmé:
-
Pokud se nestarám o kódování času a protože prostor jsou peníze, používám nejvyšší úroveň komprese FLAC-8 .
-
Pokud se nestarám o prostor, ale chci se za to dostat co nejrychleji, použiji nejnižší úroveň komprese FLAC-0 .
Obtížné řešení
Kde je pravý střed mezi velikostí souboru a časem kódování? Na tuto otázku jsem narazil na článek Nathana Zacharyho , ale porovnává jen dva soubory, kóduje je jen jednou (doba kódování se značně liší podle bočního zatížení počítače ) a tabulky se ve srovnání s grafy těžko čtou.
Takže, inspirován tím, provedl jsem jeho měření pomocí pěti kompletních alb každý v jiném žánru a každý soubor / stopa zakódoval 10krát .
Postup:
- Zkopírujte album pomocí
abcde
a správnécdparanoia
nastavení nekomprimovaného formátu WAV. - Každý soubor převeďte 10krát pro každou úroveň komprese (FLAC-0 na FLAC-8) a vezměte průměrný čas kódování ve srovnání s FLAC-0 a velikost souboru vzhledem k F LAC-0 .
- Z tohoto důvodu jsem zakázal připojení k internetu, všechny pravidelné úlohy (
cronjobs
) a téměř vše ostatní, takže skutečně většinou probíhá komprese a co nejméně ruší.
- Z tohoto důvodu jsem zakázal připojení k internetu, všechny pravidelné úlohy (
Toto opatření by mělo být do značné míry nezávislé na použitém hardwaru. Použil jsem flac verzi 1.3.2 na Arch Linuxu pomocí flac <infile> --compression-level-X -f -o flacX.flac
.
Účinnost
Pokud znásobíte relativní velikost s relativním časem kódování / komprese , získáte hodnotu za špatnost . Ale protože tato špatnost je většinou řízena relativním časem, grafy by se nesmírně překrývaly. Abych tedy graf vyčistil, jen jsem zrcadlil špatnost na dobrotu , říkám zde účinnost .
Zjištění
Od FLAC-4, doba komprese exploduje, ale existují dvě překvapení:
-
Došlo k významnému zmenšení velikosti souboru mezi FLAC-3 a FLAC-4 v závislosti na hudebním žánru: Klasická hudba má díky FLAC-4 mnohem nižší kompresi. Předpokládám, že je to proto, že FLAC používá pro kompresi lineární predikční model, který je při složitější (méně lineární) hudbě méně dobrý.
-
U neklasické hudby FLAC-3 je z hlediska velikosti souboru dokonce výrazně horší než FLAC-2.
Doporučení
Doporučuji použít úroveň komprese FLAC-4 .
Vyšší hodnota výrazně prodlužuje čas kódování s nepatrným snížením velikosti souboru (průměrná redukce z FLAC-4 na FLAC-8 v tomto testu je 1,2% s 182% zvýšení průměrné doby komprese).
Dodatek
Alba
Právě jsem vzal prvních pět náhodných CD (uvedených níže) o kterém jsem si myslel, že představuje jinou hudební oblast. Odkazy záměrně směřují na Amazon, aby poskytly snadnou možnost nahlédnout do hudby / získat představu o hudbě, protože v komprimaci významně mění.
- Emil Gilels – Beethoven: Klavírní sonáty č. 21 „Waldstein“, 26 „Les Adieux“ & 23 „Appassionata“ ( klasický)
- Karl Jenkins – Ozbrojený muž – mše za mír (klasická, hromadná)
- Unni Wilhelmsen – 7 (pop, jazz, folk)
- Alin Coen Band – We “ re Not the Ones We Thought We Were (indie, folk, písničkář)
- Bukahara – Bukahara Trio ( neofolk , balkanfolk )
Program
Pro tento úkol jsem napsal python
program, který prochází všemi podadresáři (alba) v dané složce () k testování všech souborů .wav a jejich seskupení / vykreslení podle názvu podsložky.
<folder> Album 1 Album 2 ...
Analýza bude uložena v souboru --outfile <file1>
. K vykreslení použijte --infile <file1>
a --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)
Komentáře
- Kdepak … toto je úžasná kvantitativní analýza, kterou jste tam provedli! Opravdu si vážím, že jste si na to všechno udělal čas. Nelze ' dosáhnout rychlých, ale opravdu skvělých výsledků. Děkuji!
Odpověď
Flac 0. Úložiště je dnes tak levné, zdá se mi jako myšlenka … také Flac 0 je méně pravděpodobné, že škytne na pomalejším systému, protože dekódování je méně náročné na dekódování.
Odpověď
V návaznosti na odpověď Suuuehgi bych rád dodal, že pokud vycházíte z CD a jeho kopírování přímo na FLAC, čas kódování nemusí vůbec vadit, protože musíte nejdříve hudbu zkopírovat, což nějakou dobu trvá.
Zde je to, co jsem vyzkoušel:
Pomocí programu dbPowerAmp CD Ripper jsem roztrhl kopii " Merry Mariah Carey Vánoční " album. Roztrhl jsem to jednou na úrovni komprese FLAC 8, jednou na úrovni 5 (výchozí dbPowerAmps) a jednou na úrovni 0.
Zde je celkem časy pro každé ripování, od kliknutí na start, do konce se všemi soubory FLAC hotovými:
Úroveň 0 = 6:19
Úroveň 5 = 6:18
Úroveň 8 = 6:23
Jak vidíte, rozptyl mezi všemi 3 je minimální, v < 5 sekund od sebe. Jak jsem sledoval, jak kopíruje a kóduje, stav kódování byl pouhým zábleskem na obrazovce, stěží zaregistrováno. A při sledování kopírování systému souborů se zdálo, že kóduje za běhu kopírování. YMMV v pomalejších systémech.
Pokud jde o velikosti souborů, zde se produkují velikosti souborů:
Úroveň 0 = 278 MB
Úroveň 5 = 257 MB
Úroveň 8 = 256 MB
Zatímco celkový rip a enc časy ód byly v zásadě stejné, velikosti souborů nebyly, nicméně v pozdějších úrovních komprese určitě klesá návratnost (jak zmiňuje odpověď Suuuehgi).
Podle mě se zdá, že pokud začínají na discích CD a mají slušné PC, čas potřebný pro ripování a kódování se příliš nezmění na základě úrovně komprese FLAC. Velikost souboru se však změní. Myslím, že návrh dbPowerAmps na FLAC úroveň 5 jako výchozí je dobrý. Pouze 1 MB rozdíl mezi FLAC 5 a FLAC 8, kde – jako kdybyste šli na FLAC 0, můj příklad ukazuje 21 MB přebytečného úložiště, které by bylo možné uložit. To se nemusí zdát moc, ale při kopírování rozsáhlých sbírek se to rychle sčítá (jedna skladba FLAC může mít takovou velikost.)
Toto bylo provedeno na ploše s USB 2 DVD mechanikou , kopírování v průměru 7x rychlostí. Moje specifikace pro stolní počítače jsou procesor Intel Core i5-6500 @ 3,2 GHz, 16 GB RAM a jednotka Samsung 860 EVO Sata SSD.