Univerzita Karlova v Praze Matematicko-fyzikální fakulta
BAKALÁŘSKÁ PRÁCE
Jaroslav Keznikl Zpracování audia - audiofiltry a editace Katedra softwarového inženýrství
Vedoucí bakalářské práce: Mgr. Tomáš Poch Studijní program: Informatika, programování
2008
Děkuji panu Mgr. Tomáši Pochovi za odborné vedení mé práce, za poskytnuté rady, připomínky a za čas, který mi během vypracování této práce věnoval.
Prohlašuji, že jsem svou bakalářskou práci napsal samostatně a výhradně s použitím citovaných pramenů. Souhlasím se zapůjčováním práce a jejím zveřejňováním. V Praze dne 25.5.2008
Jaroslav Keznikl
2
Obsah Úvod
8
Úvod do tématu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
Přehled obsahu práce . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
Rozdělení práce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
1 Digitální audio 1.1
1.2
10
Digitální vs. analogový signál . . . . . . . . . . . . . . . . . . . .
10
1.1.1
Základy vzorkování . . . . . . . . . . . . . . . . . . . . . .
10
1.1.2
Vzorkování teoreticky . . . . . . . . . . . . . . . . . . . . .
12
Reprezentace digitálního audia, WAVE . . . . . . . . . . . . . . .
13
1.2.1
Formát dat . . . . . . . . . . . . . . . . . . . . . . . . . .
13
1.2.2
Struktura . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.2.3
Základní oddíly . . . . . . . . . . . . . . . . . . . . . . . .
14
2 Digitální filtry a efekty
16
2.1
Filtry obecně . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
2.2
Digitální vs. analogové filtry . . . . . . . . . . . . . . . . . . . . .
17
2.3
Rozdělení digitálních filtrů . . . . . . . . . . . . . . . . . . . . . .
17
2.3.1
Typy digitálních filtrů podle frekvenční odezvy . . . . . . .
17
2.3.2
Typy digitálních filtrů podle impulsní odezvy . . . . . . .
18
2.4
2.5
2.6
Filtry založené na zpoždění
. . . . . . . . . . . . . . . . . . . . .
19
2.4.1
Základní filtry . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.4.2
Delay . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.4.3
Vibrato . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.4.4
Flanger . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.4.5
Chorus . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
Filtry založené na modulaci . . . . . . . . . . . . . . . . . . . . .
22
2.5.1
Ring modulace . . . . . . . . . . . . . . . . . . . . . . . .
22
2.5.2
Amplitudová modulace . . . . . . . . . . . . . . . . . . . .
22
2.5.3
Frekvenční a fázová modulace . . . . . . . . . . . . . . . .
24
Dynamické zpracování signálu . . . . . . . . . . . . . . . . . . . .
24
3
2.6.1
Compressor . . . . . . . . . . . . . . . . . . . . . . . . . .
26
2.6.2
Limiter . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
2.6.3
Noise Gate . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
3 Uživatelská dokumentace
28
3.1
Základní informace . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.2
Rozhraní . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.2.1
Hlavní menu . . . . . . . . . . . . . . . . . . . . . . . . . .
30
3.2.2
Zobrazení stopy . . . . . . . . . . . . . . . . . . . . . . . .
30
Editace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
3.3.1
Výběr, základní editace . . . . . . . . . . . . . . . . . . . .
31
3.3.2
Pokročilá editace, aplikace filtrů . . . . . . . . . . . . . . .
31
3.3.3
Undo, Redo . . . . . . . . . . . . . . . . . . . . . . . . . .
32
3.3.4
Přehrávání souboru . . . . . . . . . . . . . . . . . . . . . .
32
Příklady použití . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
3.4.1
Výběr . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
3.4.2
Změna detailu a posun zobrazení . . . . . . . . . . . . . .
33
3.4.3
Změna pozice a kurzoru, přehrávání ve smyčce
. . . . . .
33
3.4.4
Copy, paste, delete . . . . . . . . . . . . . . . . . . . . . .
34
3.4.5
Aplikace equalizeru . . . . . . . . . . . . . . . . . . . . . .
34
3.4.6
Úprava hlasitosti . . . . . . . . . . . . . . . . . . . . . . .
34
3.4.7
Zajímavá nastavení filtrů . . . . . . . . . . . . . . . . . . .
35
3.3
3.4
4 Návrh a implementace 4.1
4.2
4.3
4.4
36
Požadavky na program . . . . . . . . . . . . . . . . . . . . . . . .
36
4.1.1
Funkce pro práci se zvukem . . . . . . . . . . . . . . . . .
36
4.1.2
Grafické prostředí . . . . . . . . . . . . . . . . . . . . . . .
37
Použité technologie . . . . . . . . . . . . . . . . . . . . . . . . . .
37
4.2.1
Platforma a jazyk . . . . . . . . . . . . . . . . . . . . . . .
37
4.2.2
Managed DirectX . . . . . . . . . . . . . . . . . . . . . . .
37
4.2.3
KissFFT . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
Struktura programu . . . . . . . . . . . . . . . . . . . . . . . . . .
38
4.3.1
Moduly . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
4.3.2
Vnitřní struktura aplikace . . . . . . . . . . . . . . . . . .
38
Manipulace s daty
. . . . . . . . . . . . . . . . . . . . . . . . . .
40
4.4.1
Čtení . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
4.4.2
Zápis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
4.4.3
Schránka . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
4
4.5
Zobrazování stopy . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
4.5.1
Vykreslování stopy . . . . . . . . . . . . . . . . . . . . . .
42
4.5.2
Vykreslování pozice přehrávání . . . . . . . . . . . . . . .
42
4.5.3
Posun a změna detailu zobrazení . . . . . . . . . . . . . .
43
4.5.4
Zdroje dat . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
Přehrávání zvuku . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
4.6.1
Streamované přehrávání . . . . . . . . . . . . . . . . . . .
44
4.6.2
Manipulace se streamem . . . . . . . . . . . . . . . . . . .
44
4.6.3
Ovládání přehrávače . . . . . . . . . . . . . . . . . . . . .
45
ApplicationManager . . . . . . . . . . . . . . . . . . . . . . . . .
46
4.7.1
Pomocné manager třídy . . . . . . . . . . . . . . . . . . .
46
4.7.2
Správa generovaných dialogů . . . . . . . . . . . . . . . . .
47
4.7.3
Shrnutí významu třídy . . . . . . . . . . . . . . . . . . . .
47
4.8
Undo, Redo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
4.9
Automatické generování formulářů
. . . . . . . . . . . . . . . . .
48
4.9.1
Definice atributů . . . . . . . . . . . . . . . . . . . . . . .
48
4.9.2
Generování ovládacích prvků . . . . . . . . . . . . . . . . .
48
4.9.3
Real-time náhledy
49
4.6
4.7
. . . . . . . . . . . . . . . . . . . . . .
5 Implementace audio filtrů 5.1
50
Hierarchie filtrů . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
5.1.1
In-Place filtry . . . . . . . . . . . . . . . . . . . . . . . . .
51
5.1.2
Stream filtry . . . . . . . . . . . . . . . . . . . . . . . . . .
51
5.1.3
Feedback-stream filtry . . . . . . . . . . . . . . . . . . . .
51
5.1.4
Block filtry . . . . . . . . . . . . . . . . . . . . . . . . . .
52
5.2
Filtry vázané na grafické rozhraní . . . . . . . . . . . . . . . . . .
52
5.3
Procesy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
5.4
Filtry
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
5.5
Wrapper třídy filtrů . . . . . . . . . . . . . . . . . . . . . . . . . .
56
5.5.1
Hierarchie . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
5.5.2
Definice rozhraní pro generování dialogů . . . . . . . . . .
56
Volání filtrů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
5.6.1
Příklad: Distortion . . . . . . . . . . . . . . . . . . . . . .
57
Rozšíření knihovny . . . . . . . . . . . . . . . . . . . . . . . . . .
58
5.7.1
Implementace nativní třídy filtru . . . . . . . . . . . . . .
59
5.7.2
Implementace wrapper třídy filtru . . . . . . . . . . . . . .
60
5.7.3
Rozšíření grafického rozhraní . . . . . . . . . . . . . . . . .
62
5.6 5.7
5
6 Srovnání
64
6.1
Rozhraní . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
6.2
Filtry a výkon . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
6.3
Shrnutí . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
Závěr
67
Reference
69
Příloha
70
6
Název práce: Zpracování audia - audiofiltry a editace Autor: Jaroslav Keznikl Katedra (ústav): Katedra softwarového inženýrství Vedoucí bakalářské práce: Mgr. Tomáš Poch, Distribued Systems Research Group e-mail vedoucího:
[email protected] Abstrakt: Cílem této práce je rozebrat a implementovat některé metody používané v programech pro zpracování zvuku. Práce se skládá ze dvou částí. Teoretická část obsahuje popis jednotlivých metod, postupů a datových struktur používaných v této oblasti. Popisuje proces vzorkování zvuku, strukturu WAVE formátu a vysvětluje principy základních digitálních audio filtrů. Praktická část je tvořena implementací některých rozebíraných metod v programu pro vizuální editaci zvuku. Vlastní program nazvaný AEditor umožňuje zobrazování editované stopy v hlavním okně aplikace, její přehrávání, editaci a aplikaci digitálních filtrů s možností náhledu nastavení filtru v reálném čase. Klíčová slova: zvuk, editace, filtr
Title: Audio processing - filters and editing Author: Jaroslav Keznikl Department: Department of Software Engineering Supervisor: Mgr. Tomáš Poch, Distribued Systems Research Group Supervisor’s e-mail address:
[email protected] Abstract: The subject of this work is to analyse and implement some of the methods used in programs for sound processing. The work consists of two parts. The theoretical part contains a description of methods, procedures and data structures used in this area. It describes the process of sound sampling, structure of the WAVE format and explains the principles of basic digital audio filters. The practical part is formed from the implementation of some mentioned methods in the visual audio editor. The program, entitled AEditor, allows projection of the track in the main window, its playing, editing and the application of digital filters, with the preview of the filter setting in real time. Keywords: sound, editing, filter
7
Úvod Úvod do tématu V dnešní době je práce s digitálním zvukem nedílnou součástí práce v nahrávacím studiu, rozhlasové nebo televizní redakci. Z toho plyne i narůstající potřeba kvalitních nástrojů na zpracování digitálního zvuku. Existuje mnoho aplikací, od digitálních nahrávacích studií po programy na konečnou úpravu zvukových dat. A právě problematice programů pro úpravu zvuku se věnuje tato práce. Mezi nejznámější programy patří komerční software Sony Sound Forge[10]. V oblasti open-source je známý program Audacity[11]. Oba tyto programy se zaměřují převážně na úpravu digitálního zvuku a manipulaci s ním. Tomu odpovídají dostupné funkce, jako je zobrazování a přehrávání stopy nebo aplikace různých filtrů a efektů. Cílem bakalářské práce je rozebrat a implementovat některé metody používané v programech pro zpracování digitálního zvuku. Práce se skládá ze dvou částí. Teoretická část se zabývá základními principy zpracování digitálního audia a digitálními filtry, praktickou část pak představuje implementace některých postupů probraných v teoretické části programem pro zpracování zvuku, nazvaným AEditor. Snahou praktické části je přiblížit se rozhraním a typem funkcí zmiňovaným programům. Motivací pro vznik této práce je především můj zájem o tuto problematiku, snaha porozumět postupům digitální úpravy zvuku a také snaha vytvořit praktický nástroj pro jeho úpravu a aplikaci digitálních filtrů.
Přehled obsahu práce V teoretické části jsou rozebrány způsoby převodu zvuku do digitální podoby. Dále je zde popsána struktura WAVE formátu pro ukládání vzorkovaného digitálního zvuku. WAVE je nejrozšířenější formát mezi programy pro zpracování zvuku. Rovněž program AEditor z praktické části práce uvedený formát používá. 8
Hlavní náplní teoretické části je popis některých běžně používaných digitálních filtrů a vysvětlení jejich principu. Je uvedeno srovnání digitálních a analogových filtrů a vysvětleny základní pojmy a rozdělení filtrů používaných v této oblasti. Filtry jsou rozděleny do skupin podle svých vlastností. V práci jsou rozebrány filtry založené na zpoždění, modulační filtry a dynamické filtry. Jejich popis je zaměřen na možnou implementaci. Ukázky filtrů založených na zpoždění jsou implementovány v praktické části. Hlavní část bakalářské práce tvoří implementace programu pro digitální zpracování zvuku. Tento program umožňuje uživateli zobrazení editovaného zvukového souboru, manipulaci s ním a jeho přehrávání. Je implementován formou aplikace s hlavním formulářem a pomocnými dialogy, společně s knihovnou pro digitální filtry. Obě části jsou naprogramovány pro platformu Windows. Součástí grafického rozhraní je zobrazení editované stopy způsobem obvyklým u profesionálních programů zabývajících se podobnou problematikou, včetně přibližování a oddalování detailu zobrazení. Nedílnou součástí vizuálního editoru je možnost přehrávání souboru nebo jeho části. Díky grafickému zobrazení program podporuje i vizuální editaci typu kopírování, mazání a vkládání částí souboru. S tím souvisí i možnost výměny dat s ostatními programy prostřednictvím schránky. Program dále poskytuje možnost aplikace běžně užívaných digitálních filtrů. Některé z těchto filtrů jsou popsány v teoretické části práce. V programu je kladen důraz na streamované přehrávání zvuku, které umožňuje přehrávat náhledy zvukových filtrů v reálném čase. Další funkcí spojenou s úpravou zvuku je možnost vracení provedených změn.
Rozdělení práce Teoretickou část tvoří kapitoly 1 a 2, které rozebírají používané metody při digitálním zpracování zvuku a vychází z uvedené literatury. V kapitole 1 je popsáno vzorkování analogového signálu a WAVE formát. V kapitole 2 jsou rozebrány a popsány digitální filtry pro zpracování zvuku. Kapitola 3 se zabývá uživatelským popisem programu AEditor z praktické části, příklady použití a jeho ovládáním. Kapitola 4 a 5 potom rozebírá implementační část programu AEditor. Uvádí řešené problémy, základní strukturu programu a stručně popisuje implementaci programu. V popisu jsou nastíněna možná vylepšení a odůvodnění použitých řešení. V kapitole 6 je uvedeno srovnání s některými známými programy, které se zabývají stejnou problematikou.
9
Kapitola 1 Digitální audio Kapitola se stručně zabývá zvukovým signálem v jeho analogové podobě, metodami a postupy při jeho digitalizaci. Dále popisuje nejčastěji používaný formát pro ukládání digitálního zvukového signálu, kterým je Microsoft WAVE formát.
1.1 1.1.1
Digitální vs. analogový signál Základy vzorkování
Zvuk je obecně chápán jako jednorozměrný signál (vlnění) reprezentující tlak vzduchu v našem uchu. Je to tedy spojitá funkce času. Pro zpracování analogového zvukového signálu se používají elektronické obvody, které tento signál spojitě mění. Zařízení zpracovávající digitální signály, jako například DSP procesory, nemají nekonečný výkon a neomezenou paměť pro práci se spojitými signály. Pro digitální zpracování je tedy potřeba tento signál upravit tak, aby jej bylo možné digitálně měnit a ukládat. Toho se dosáhne pomocí vzorkování (sampling) analogového signálu podél časové osy a kvantováním (quantization) amplitud na jednotlivé vzorky (samples). Pomocí vzorkování se spojitá informace převádí na množinu diskrétních hodnot tím, že v určitých okamžicích je odebrán vzorek vstupního signálu. Zařízení, zpracovávající digitální signály, mohou reprezentovat vzorkované hodnoty jen s určitou přesností a je tedy potřeba upravit i amplitudu jednotlivých vzorků. Protože je možné hodnotu vzorku vyjádřit pouze po určitých kvantech, nazývá se tento proces kvantování. Pro převod z analogového signálu na digitální slouží takzvané ADC převodníky (analog-to-digital converter). Příklad základního schématu digitálního zpracování analogového signálu je ukázán na obrázku 1.1 [1]. Analogový signál x(t) z obrázku 1.1 reprezentuje amplitudu signálu během spojitého časového úseku (v mikrosekundách). Po průchodu
10
Obrázek 1.1: Vzorkování a kvantování analogového signálu pomocí ADC převodníku, použití digitálního efektu a následný zpětný převod na analogový signál pomocí DAC převodníku. [1] přes ADC následuje digitální signál (vzorkovaný a kvantovaný) jako proud vzorků x(n), reprezentovaný číslem v určitém časovém okamžiku s indexem n. Čas mezi dvěma následujícími vzorky se nazývá vzorkovací interval T (sampling period). Její převrácená hodnota se nazývá vzorkovací frekvence fs = 1/T vyjádřená v Hz (sampling frequency, sampling rate). Následně je digitální signál zpracován digitálním efektem (DAFX, digital-audio-effect). V případě obrázku 1.1 je pouze každý vzorek vynásoben 0, 5, čímž vznikne výstupní signál y(n) = 0, 5 · x(n). Ten je poté přiveden do DAC převodníku (digital-to-analog converter), který ze vstupní posloupnosti vzorků y(n) zpětně zrekonstruuje výstupní analogový signál y(t). Výstupní signál y(t) má tedy po úpravě digitálním efektem poloviční amplitudu vzhledem ke vstupnímu signálu x(t). Amplitudy jednotlivých vzorků digitalizovaných signálů se neukládají v původní velikosti, ale jsou normalizovány. Tyto signály se pak mohou lišit použitým způsobem normalizace. Dva z možných způsobů jsou ukázány v [1] a jsou přiblíženy v následujícím odstavci. Na obr. 1.2 jsou ukázány dva různé formáty rozsahů pro digitální audio signál. Amplituda signálu je kvantována na celá čísla v rozsahu od −32768 do 32767 z důvodu 16bitové reprezentace jednoho vzorku (16bitové celé číslo se znaménkem má právě tento rozsah). Obecně pro w-bitovou reprezentaci vzorků je možný rozsah kvantovaných hodnot −2w−1 . . .2w−1 − 1. Tato reprezentace se nazývá celočíselná
11
Obrázek 1.2: Vertikální a horizontální formáty rozsahů pro digitální audio signály. reprezentace. Pokud vydělíme všechny celočíselné hodnoty maximální absolutní hodnotou (např. 32768), získáme takzvanou normalizovanou amplitudovou reprezentaci s rozsahem −1. . .1 − Q, kde Q je kvantovací krok (Q = 2−(w−1) ). Na obrázku 1.2 jsou také znázorněny různé časové osy. Nejprve spojitá, potom diskrétní a nakonec normalizovaná diskrétní časová osa.
1.1.2
Vzorkování teoreticky
Jak již bylo řečeno výše, pro digitální zpracování je třeba spojitý signál převést na diskrétní pomocí vzorkování tak, že jsou brány hodnoty původního signálu v určitých okamžicích, které jsou násobky hodnoty T (vzorkovací interval). K odvození základní vzorkovací věty je důležitý následující poznatek [2]: Vzorkováním v čase spojitého signálu s vzorkovací frekvencí Fs vznikne časově diskrétní signál, jehož frekvenční spektrum je periodickým opakováním spektra originálního signálu s periodou replikace Fs . Na obrázku 1.3 [2] je znázorněné frekvenční spektrum vzorkovaného signálu za použití vzorkovací frekvence Fs . V tomto příkladě měl původní signál frekvenční zastoupení pouze v intervalu −Fb . . .Fb . Kopie originálního spektra bývají nazývány obrazy. Z uvedených poznatků o frekvenčním spektru vzorkovaného signálu snadno vyplývá takzvaná Nyquistova Vzorkovací věta (Sampling Theorem).
12
Obrázek 1.3: Frekvenční spektrum vzorkovaného signálu. V čase spojitý signál x(t), jehož frekvenční spektrum je omezeno na frekvence menší než Fb , může být zpětně získán z jeho vzorkované verze xb(n) = x(nT ), pokud pro vzorkovací frekvenci Fs = 1/T platí: Fs > 2Fb Podrobnější informace z oblasti vzorkování signálu jsou uvedeny například v [1], [2].
1.2
Reprezentace digitálního audia, WAVE
Podle předchozí části je digitalizovaný audio signál reprezentován řadou celých (nebo i reálných) čísel. Pro zpracování na počítači je proto třeba tuto reprezentaci nějak jednotně ukládat. Nejčastěji používanou reprezentací pro PC je takzvaný WAVE formát [3]. Tento formát souborů slouží k ukládání digitálních zvukových dat. Je nativním formátem pro operační systém Windows a stal se velmi rozšířeným a používaným formátem pro celou platformu PC. Je podporován velkým množstvím programů pro zpracování zvuku na této platformě. Dále budou popsány důležité vlastnosti a struktury WAVE formátu, které jsou později využity v programu AEditor. Podrobnější informace o WAWE formátu včetně všech typů oddílů lze nalézt v [3].
1.2.1
Formát dat
Protože je WAVE nativní formát pro Windows (tedy pro procesory Intel), jsou všechny hodnoty uloženy ve formátu Little-Endian. WAVE soubory mohou obsahovat i řetězce (komentáře apod.). Ty jsou uloženy ve formátu, kdy na první pozici je 1bytové číslo, udávající délku řetězce, za ním pak následují jednotlivé ASCII znaky. 13
1.2.2
Struktura
Wave soubory používají takzvanou RIFF (Resource Interchange File Format) strukturu, která sdružuje obsah souborů do uzavřených celků (chunks). Každý z těchto oddílů obsahuje svoji hlavičku a vlastní data. Některé oddíly mohou obsahovat i vnořené oddíly (subchunks). Tento systém uzavřených oddílů pomáhá aplikacím v práci s WAVE soubory. Pokud aplikace neumí interpretovat některý typ oddílů, mohou jej přeskočit a věnovat se dalším.
1.2.3
Základní oddíly
Riff chunk (Riff oddíl) Dle specifikace RIFF formátu obsahuje tento oddíl ID s hodnotou ”RIFF”. Dále následuje velikost souboru (bez úvodních 8 bytů pro hlavičku). Jako první 4 byty datové sekce oddílu je uveden 4znakový řetězec uvádějící formát uložených dat. Pro Wave soubory je to tedy řetězec ”WAVE”. Format chunk (Formátovací oddíl) Formátovací oddíl obsahuje důležité informace o formátu uloženého souboru. ID tohoto oddílu je ”fmt ”. Dále následují jednotlivé informace o formátu. Velikost základní části je 16 bytů plus další nepovinná data. Kód komprese Jde o kódové označení způsobu komprese uložených dat. V [3] jsou ukázány příklady některých užívaných druhů komprese. Nejčastěji se dnes ovšem data ukládají bez komprese a to očekává i program AEditor. Počet kanálů Vyjadřuje počet nezávislých audio signálů uložených v datovém oddílu souboru. Hodnota 1 odpovídá mono signálu, 2 stereo a podobně. Vzorkovací frekvence Udává počet vzorků za sekundu. Její převrácenou hodnotou je takzvaná vzorkovací perioda. Průměrný počet bytů za sekundu Tato hodnota určuje počet bytů, které musí být každou sekundu přeneseny v datovém proudu do DAC převodníku tak, aby bylo možno soubor plynule přehrát.
14
Ostatní data Poslední položkou je velikost speciálních dat a následně data samotná. Pokud je soubor uložen bez komprese, je tato hodnota 0 (respektive prázdná). U ostatních typů komprese jsou zde uloženy informace nutné k dekompresi uložených dat. Data chunk (Datový oddíl) V datovém oddílu jsou uložena samotná data souboru. Oddíl má ID ”data”. Formát umožňuje uložit více různých mono signálů. Pokud je soubor uložen bez komprese (obsahuje tedy přímo jednotlivé vzorky), jsou data v souboru uložena prokládaně. Celá stopa je rozdělena na vzorky (frames), kde jsou v každém z nich za sebou postupně uloženy vzorky jednotlivých kanálů. Tímto je možno efektivně zpracovávat data v proudu. Data jsou (většinou) reprezentovaná jako znaménkové číslo. Jeho velikost je zaznamenána ve formátovacím oddílu (SignificantBitsPerSample). Jedinou výjimkou jsou data uložená v 8bitovém formátu, kde se používá bezznaménková reprezentace.
15
Kapitola 2 Digitální filtry a efekty V kapitole Digitální filtry a efekty jsou nejprve srovnány vlastnosti digitálních a analogových filtrů. Dále jsou popsána některá rozdělení digitálních filtrů a efektů. Hlavní částí kapitoly je potom popis základních principů nejpoužívanějších filtrů a jejich implementace pomocí digitálních metod. Některé filtry (založené na zpoždění) jsou později implementovány v programu.
2.1
Filtry obecně
Filtrem běžně rozumíme něco, co jistým způsobem mění vstupní signál a produkuje nějaký výstupní signál. V zásadě se ovšem dá říci, že libovolné prostředí, kterým signál prochází, je možno považovat za filtr [4]. Se zvukovými filtry se setkáváme velmi často již po dlouhou dobu. Například tvar a rozměry houslí nebo druh dřeva jsou druhem filtru. Intuitivní význam pojmu filtr napovídá, že jeho hlavní činností je ze vstupního signálu oddělovat (odfiltrovat) některé jeho části. Pokud budeme uvažovat vstupní signál jako vlnění, složené z různých dílčích částí s různými frekvencemi a amplitudami, dá se říci že jeho činnost spočívá ve změně amplitudy části signálu v závislosti na frekvenci. Z toho vyplývá, že filtr je vlastně lineární transformace vstupního signálu [1]. Digitální filtr je druh filtru, který pracuje s digitálním signálem, jako je například digitální zvuk. Jde vlastně o výpočet, který z jedné sekvence čísel (vstupní signál) vyprodukuje jinou sekvenci čísel (výstupní signál). Digitální filtr může (s určitou přesností) provádět stejnou modifikaci na digitálním signálu, jako kterýkoli reálný analogový filtr (například akustický) na signálu analogovém. To znamená, že všechny analogové filtry mohou být simulovány digitálně [4]. Digitální filtr je ale pouze postup jak přejít od jednoho digitálního signálu na druhý. Ten
16
pak může existovat v mnoha různých podobách. Ať už jako matematický vzorec, nebo počítačový podprogram, nebo vhodně propojený integrovaný obvod.
2.2
Digitální vs. analogové filtry
Použití digitálních filtrů se liší od analogových v mnoha ohledech. Mnohé z nich vyplývají ze samotné podstaty digitálního signálu. Běžné analogové filtry používají k dosažení daného efektu elektronické obvody složené z různých součástek, jako jsou rezistory, kondenzátory a podobně. Tyto filtry jsou velmi často používány v oblastech jako je například redukce šumu. Vlastnosti analogového filtru lze měnit jen celkovou změnou elektrického obvodu. Navíc jsou citlivé na fyzikální podmínky okolí (teplota, vlhkost). Naproti tomu digitální filtry využívají procesor. Ať už univerzální nebo specializovaný DSP (Digital Signal Processor). Díky tomu je takový filtr programovatelný. Protože je digitální filtr určen programem uloženým v paměti procesoru, lze jej měnit beze změny hardwaru. To umožňuje jednodušší design, implementaci i testování digitálních filtrů.
2.3
Rozdělení digitálních filtrů
Digitální filtry lze dělit mnoha způsoby podle jejich vlivu na vstupní signál. Nejčastější dvě dělení jsou dělení podle vlivu ve frekvenční nebo v časové doméně signálu. To znamená dělení podle takzvané frekvenční odezvy (frequency response) nebo impulsní (neboli časové) odezvy (impulse response).
2.3.1
Typy digitálních filtrů podle frekvenční odezvy
Toto rozdělení klasifikuje vliv digitálních filtrů na frekvenční spektrum vstupního signálu. Základní typy jsou charakterizovány mezní (cut-off) frekvencí fc (případně intervalem), která rozděluje frekvenční pásmo podle chování filtru. • Lowpass filtry propustí pouze nižší frekvence než je zadaná mezní frekvence fc a vyšší utlumí. • Highpass filtry jsou opakem Lowpass filtrů. Propustí pouze vyšší frekvence než je zadaná mezní (tzv. cut-off) frekvence fc . Nižší frekvence jsou naopak utlumeny.
17
Obrázek 2.1: Rozdělení filtrů podle působení ve frekvenční doméně. • Bandpass filtry propouští pouze frekvence v daném rozmezí fcl –fch (dolní/lower a horní/higher cut-off frekvence). Naopak všechny frekvence menší než fcl a větší než fch jsou utlumeny. • Bandreject filtry oproti Bandpass tlumí frekvence v daném rozmezí fcl – fch . Frekvence mimo tento rozsah naopak propouští. • Resonator filtry propouští pouze frekvence v úzkém pásmu kolem zadané frekvence fc . Ostatní frekvence jsou utlumeny. • Notch filtr tlumí pouze frekvence v úzkém pásmu kolem zadané frekvence fc . Ostatní propouští. • Allpass filtry propouští všechny frekvence. Mění fázi vstupního signálu. Působení jednotlivých typů filtrů ve frekvenční doméně zobrazuje obr.2.1 [1]. Ostatní typy filtrů mohou být složeny z těchto základních typů. Všechny tyto druhy mají své využití při úpravě zvukového signálu. Bandpass a bandreject filtry mohou rozdělovat vstupní signál na několik frekvenčně oddělených částí. Notch filtry se dají použít k oddělení nežádoucích frekvencí. Highpass filtry se používají k odstranění velmi nízkých rušivých frekvencí.
2.3.2
Typy digitálních filtrů podle impulsní odezvy
Toto rozdělení definuje typy filtrů na základě vazby výstupního signálu na vstupní signál. Pro klasifikaci je zaveden termín Impulse response [2] (impulsní, časová odezva), což je sekvence nenulových čísel, která odpovídá reakci daného filtru na jednotkový signál (v čase t0 s hodnotou 1 následovaná samými 0).
18
• FIR neboli Finite-impulse-response filtry (filtry s konečnou impulsní odezvou) nebo také nerekurzivní filtry jsou ty, které potřebují ke spočtení aktuální výstupní hodnoty konečný počet vstupních hodnot. Neboli jejich impulsní odezva má konečnou velikost. • IIR neboli Infinite-impulse-response filtry (filtry s nekonečnou impulsní odezvou) nebo také rekurzivní filtry jsou takové filtry, které potřebují ke spočtení aktuální výstupní hodnoty nekonečný počet vstupních hodnot. Jinak řečeno jejich impulsní odezva má nekonečnou odezvu. Podrobnější popis této klasifikace a vlastností jednotlivých typů je k dispozici například v [1], [2].
2.4
Filtry založené na zpoždění
Zpoždění (delay) se v reálném světě vyskytuje velice často. Jde například o ozvěnu, která nastává při odrazu zvuku od vzdáleného objektu, nebo o změnu barvy zvuku při odrazech v malé místnosti.
2.4.1
Základní filtry
FIR comb filtr Základním typem filtru, který produkuje jednoduché zpoždění, je takzvaný FIR comb filter. Vstupní signál je pouze zpožděn o zadaný čas, a poté smíchán s původním signálem v zadaném poměru (smíchání je možné při kombinaci více základních filtrů provést až společně nakonec). Jedinými dvěma parametry tohoto filtru jsou doba zpoždění τ a poměr přimíchání zpožděného signálu k signálu vstupnímu g. Schéma FIR comb filtru je zobrazeno na obrázku 2.2. Matematicky lze daný filtr zapsat jako rovnici: y(n) = x(n) + gx(n − M ) kde M = τ /fs a fs je vzorkovací frekvence. Jako každý akustický filtr i FIR comb filtr má vliv jak ve frekvenční doméně, tak v časové. Člověk ovšem vnímá většinou jenom jeden z obou projevů, podle dané velikosti zpoždění. Pro větší hodnoty zpoždění spíše vnímáme časový projev (tedy spíše vliv v časové doméně). Při nižších hodnotách zpoždění je již časový projev téměř nerozeznatelný, zato vliv na frekvenční spektrum signálu je daleko výraznější. Této vlastnosti se využívá při tvorbě odvozených filtrů (viz dále). 19
Obrázek 2.2: Schéma fungováni FIR comb filtru.
Obrázek 2.3: Schéma fungováni IIR comb filtru. IIR comb filtr Podobně jako FIR comb filtr i IIR comb filtr produkuje zpoždění. Ale oproti FIR filtru má toto zpoždění nekonečnou signálovou odezvu. Vstupní signál prochází smyčkou a po aplikaci zpoždění je opět přimíchán ke vstupnímu signálu. Opět jsou parametry doba zpoždění τ a míra smíchání s původním signálem g. V některých případech se používá ještě zeslabení vstupního signálu jako ochrana před přebuzením, kvůli velkému zesílení uvnitř filtru. Tato míra zeslabení je dále označena jako c. Schéma IIR comb filtru je zobrazeno na obrázku 2.3. Tento filtr může být reprezentován například touto rovnicí: y(n) = cx(n) + gy(n − M ) kde opět M = τ /fs a fs je vzorkovací frekvence. Vliv IIR filtru ve frekvenční doméně je podobný jako u FIR filtru.
2.4.2
Delay
Delay, neboli zpoždění, je velmi často využívaným filtrem. Jde v podstatě o IIR nebo FIR comb filtr. Často se používá i vícenásobné zpoždění, kdy místo přičtení jedné zpožděné kopie použijeme hned několik těchto kopií. Používá i stereo verze tohoto filtru.
20
2.4.3
Vibrato
Tento základní filtr vzniká při spojitých změnách výšky tónu (pitch shifting). Vzniká podobným způsobem jako tzv. dopplerův efekt u jedoucího auta. Filtr je založen na FIR nebo IIR comb filtru, kdy se zpoždění comb filtru plynule a periodicky mění. Zde pouze změnu vzdálenosti zdroje nahradíme změnou zpoždění vstupního signálu. Zpožděný signál již nepřimícháváme k původnímu. Typické hodnoty parametrů filtru jsou 5 až 10 ms pro časové zpoždění a frekvence 5 až 15 Hz, se kterou se bude toto zpoždění měnit.
2.4.4
Flanger
Dalším velice známým efektem je takzvaný flanger. Ten vzniká použitím FIR comb filtru s proměnným časovým zpožděním (podobně jako u vibrata). Oproti vibratu je zpožděný signál přimíchán k původnímu, přičemž toto zpoždění se periodicky mění. U tohoto efektu využíváme fakt, že při velmi malých hodnotách zpoždění není patrný vliv na časové posunutí. Naproti tomu je slyšitelný vliv na frekvence vstupního signálu. Typické hodnoty zpoždění se pohybují od 1 do 10 ms. Dalšími parametry je míra smíchání zpožděného signálu s originálem (depth, mix), frekvence se kterou se bude zpoždění měnit a také typ vlny, podle které se bude toto zpoždění měnit. Tato vlna může být například typu sinusoidy nebo lomené čáry.
2.4.5
Chorus
Tento efekt vzniká například při unisono hře více hudebníků. Ti hrají s drobnými rozdíly v časování jednotlivých tónů, takže mezi jednotlivými tóny je jisté zpoždění. I frekvence daných tónů je u každého nástroje jiná. Díky těmto vlivům chorus efekt vzniká. A přesně tyto vlivy digitální filtr napodobuje. Ke zpoždění je opět možné použít FIR nebo IIR comb filtr (častěji se používá pouze FIR). V základě se jedná o velmi podobný filtr jako je flanger. Hlavní rozdíl je v rozmezí použitého zpoždění. To se pohybuje řádově v rozmezí 20 až 30 ms. Rychlost oscilace velikosti zpoždění se pohybuje většinou pod 3 Hz. Místo pravidelné oscilace velikosti zpoždění je možné toto zpoždění měnit náhodně, což více odpovídá reálné situaci. Stejně jako je měněno zpoždění přidávaného signálu, můžeme měnit i jeho amplitudu. Což se dá opět dělat buď pravidelně, nebo náhodně. Pro zvýšení efektu je možné přidat několik zpožděných signálů, s různou variací tohoto zpoždění. Tím se simuluje vícehlas.
21
2.5
Filtry založené na modulaci
Modulací obecně rozumíme proces, při kterém jsou jednotlivé parametry (amplituda, fáze, frekvence) takzvaného nosného signálu měněny v závislosti na modulovaném vstupním (v našem případě audio) signálu. Například i změny parametrů základních filtrů z předchozí části (2.4) mohou být považovány za amplitudovou nebo fázovou modulaci. Typickými příklady amplitudové modulace jsou například phaser, tremolo. Naopak typickými zástupci fázové modulace jsou již zmíněné filtry jako flanger nebo chorus.
2.5.1
Ring modulace
Jde o jeden z nejzákladnějších typů modulace. Základem ring modulace je přenásobení vstupního audio signálu x(n) signálem tvaru sinusoidy s(n) s nosnou frekvencí fc . Na rozdíl od analogových filtrů je tento typ modulace u digitálních filtrů velmi jednoduše implementovatelný. Vstupnímu signálu x(n) se říká modulátor, druhý signál s(n) se nazývá nosný. Princip filtru lze zapsat rovnicí: y(n) = x(n) ∗ s(n) Tento filtr má zajímavý efekt na frekvenční spektrum vstupního signálu. Jestliže s(n) je nosný signál s frekvencí fc , potom je frekvenční spektrum výstupního signálu složeno ze dvou zrcadlově převrácených kopií frekvenčního spektra vstupního signálu x(n) se středem v fc . Tento efekt ukazuje obrázek 2.4.
Obrázek 2.4: a) Frekvenční spektrum vstupního signálu x(n) ZP (základní pásmo). b) Frekvenční spektrum výstupního signálu y(n) DP, HP (dolní a horní pásmo) po ring modulaci sinusoidou s frekvencí fc .
2.5.2
Amplitudová modulace
Oproti ring modulaci je analogová amplitudová modulace jednodušší na implementaci, proto se také používá již mnohem déle. U amplitudové modulace se ty22
Obrázek 2.5: Tremolo efekt při použití amplitudové modulace picky používá vstupní audio signál jako nosný a nízkofrekvenční signál jako modulátor (ten produkuje takzvaný nízkofrekvenční oscilátor - LFO). Amplituda audio signálu se tedy mění podle frekvence LFO. Princip modulace vyjadřuje následující vzorec: y(n) = [1 + αm(n)] .x(n) Kde signál m(n) má maximální amplitudu 1. Koeficient α určuje velikost modulace (při hodnotě α = 1 je efekt nejvýraznější, zatímco při hodnotě α = 0 se efekt neprojeví). Pokud jako nosný signál použijeme LFO a jako modulátor vstupní audio signál, frekvenční spektrum výstupního signálu je stejné jako u ring modulace. S tím rozdílem, že nosný signál je na výstupu také slyšitelný. Obecně efekt amplitudové modulace je uchem vnímán různě v závislosti na frekvenčním rozsahu použitých signálů. U frekvencí pod 20 Hz je slyšet efekt převážně v časové doméně (tremolo), tento efekt je zobrazen na obrázku2.5. Modulace vyššími frekvencemi se naopak projeví převážně ve frekvenční doméně.
23
2.5.3
Frekvenční a fázová modulace
U této modulace se mění fáze či frekvence vstupního signálu v závislosti na vlastnostech signálu modulačního signálu. Vstupní signál je tedy nosným signálem. Na obrázku 2.6 je ukázán příklad, kdy vstupní signál je v čase spojitá funkce cosinus. Při fázové modulaci je fáze výsledného signálu ω přímo úměrná modulačnímu signálu m(t), kdežto u frekvenční modulace je výstupní fáze úměrná integrálu modulovacího signálu. V prvním případě (a, b)) je modulátor sinusoida a výstupní signál je tedy u obou typů modulace stejný. Ve druhém případě (c, d) je ukázán rozdíl mezi frekvenční a fázovou modulací, pokud je modulátorem bipolární signál. V posledním případě (e, f) je zobrazen rozdíl mezi jednotlivými typy, pokud modulační signál odpovídá lomené čáře. Filtr pro fázovou modulaci signálu zachycuje následující vzorec [1]: y(n) = x(n − m(n)) V praxi se digitální fázová modulace liší od uvedeného příkladu tím, že nosný signál x(n) není spojitý v čase. Modulační signál (modulátor) m(n) je ovšem potenciálně spojitý. To se musí u reálné implementace ošetřit pomocí interpolace vstupního signálu.
2.6
Dynamické zpracování signálu
Zpracování dynamiky se provádí tak, že vstupní signál je zesilován či zeslabován v závislosti na úrovni nějakého určujícího (nejčastěji vstupního) signálu. Všechny filtry mají definovanou takzvanou mezní (treshold) úroveň signálu (mohou jich mít i více). Po jejím překročení se chování filtru jistým způsobem změní (například dojde k zesílení/zeslabení) [7]. Základní schéma všech dynamických filtrů ukazuje obrázek 2.7 [1]. Nejprve je určena aktuální úroveň f(n) vstupního signálu x(n). Následuje výpočet míry zesílení v závislosti g(n) na vstupní úrovni a nakonec je vstupní signál zesílen či zeslaben podle spočtené hodnoty. Jako funkce pro určení aktuální úrovně signálu se ve většině případů používá průměrná hodnota za krátký časový interval. Velmi často jde o výpočet takzvané efektivní hodnoty neboli RMS (root mean square). Může se použít také aktuální vstupní hodnota (například u hard limiteru). Pokud je funkce na určení úrovně vstupního signálu jistým druhem průměru za krátký časový interval, trvá určitou dobu než se míra zesílení (gain) filtru přizpůsobí nové úrovni signálu. Doba, za kterou filtr reaguje na překročení mezní frekvence, se nazývá attack time a bývá 24
Obrázek 2.6: Rozdíly mezi frekvenční (FM) a fázovou (PM) modulací v závislosti na modulačním signálu.
25
Obrázek 2.7: Základní schéma filtru upravující dynamiku vstupního signálu. relativně velmi krátká. Pokud je signál nad mezní úrovní a poté se sníží pod tuto mez, bude opět určitou dobu trvat, než se míra zesílení přizpůsobí tomuto poklesu. Tato doba se nazývá release time a bývá několikrát delší než attack time. U některých filtrů je možné obě tyto hodnoty nastavit jako parametry. Tato zpoždění jsou ukázána na příkladu compressoru na obrázku 2.8.
2.6.1
Compressor
Compressor je dynamický filtr upravující úroveň výstupního signálu v závislosti na úrovni vstupního signálu tak, že pokud je úroveň nižší než zadaná mezní úroveň (treshold level), nejsou hodnoty nijak měněny, zatímco vyšší hodnoty než tato mez jsou částečně utlumeny [7]. Tím se snižuje dynamický rozsah. Úroveň vstupního signálu bývá většinou spočtena jako průměrná hodnota za určitý časový úsek, používá se například takzvaná efektivní hodnota (RMS). Popřípadě se místo průměrné hodnoty může použít, jako odhad aktuální úrovně, momentální vzorek na vstupu (princip detekce u hard limiteru). Při použití průměrné hodnoty je patrný attack a release time. Tento efekt je zobrazen na obrázku 2.8
2.6.2
Limiter
Hlavním úkolem limiteru je kontrolovat a omezovat vysoké úrovně vstupního signálu při co nejmenším ovlivnění dynamiky signálu. Limiter je velmi podobný compressoru. Jde vlastně o agresivnější kompresi vstupního signálu [7]. U limiteru se někdy místo počítání průměrných hodnot používá k určení aktuální úrovně signálu momentální hodnota na vstupu, kvůli potřebě rychle reagovat na změny vstupního signálu. Pokud se použije průměrná hodnota, jsou časy attack time a release time poměrně velmi krátké. 26
Obrázek 2.8: Zpoždění přizpůsobení míry zkreslení při změně vstupního signálu u compressoru.
2.6.3
Noise Gate
Mechanismus fungování noise gate (šumové brány) je podobný jako u všech ostatních filtrů této kategorie. Noise gate funguje ovšem opačným způsobem než compressor nebo limiter. Oproti compressoru, který tlumí příliš vysoké úrovně signálu, funguje noise gate tak, že tlumí signál s nižší úrovní než je zadaná mezní (threshold) úroveň. Attack a release time určují dobu, po kterou trvá úplné zeslabení signálu, respektive návrat na vstupní úroveň. Jako další parametr bývá zadávána doba, po kterou má být detekován pokles úrovně pod mezní hranici před tím, než se noise gate aktivuje (začne tlumit vstupní signál) [1], [7].
27
Kapitola 3 Uživatelská dokumentace V kapitole je popsáno základní ovládání programu AEditor, rozhraní aplikace, jeho chování a formát vstupních dat. Dále jsou zde uvedeny typické způsoby použití programu.
3.1
Základní informace
Program AEditor je grafický editor zvukových souborů typu WAVE. Jedná se o typickou Windows aplikaci s jedním hlavním formulářem a pomocnými dialogy. Aplikace je distribuována ve formě jednoho spustitelného souboru a knihoven. Pro instalaci stačí nakopírovat tyto soubory do stejné složky. Pro spuštění je vyžadováno běhové prostředí Microsoft .NET 2.0 a Managed DirectX 9. Program podporuje WAVE formát vstupních souborů. Podporována je pouze 16bitová verze mono nebo stereo bez komprese. Program také umožňuje používání veřejné schránky Windows, a tedy případně i předávání dat mezi ostatními programy pomocí schránky.
3.2
Rozhraní
Nejdůležitější částí programu je hlavní formulář (obrázek 3.1). Ten se skládá z několika částí. Jednou z nich je hlavní menu aplikace v horní části formuláře. Další důležitá část je zobrazení zvukové stopy v centru formuláře s možností přibližování a výběru. Ve spodní části formuláře potom následuje stavový řádek (obrázek 3.2), kde se zobrazuje aktuální stav vnitřního přehrávače a při provádění editace i progressbar určující velikost již zpracované části (po jejím skončení se zobrazí čas trvání operace). Formulář doplňuje indikátor výstupní úrovně signálu pro kontrolu přebuzení upravovaného souboru. 28
Obrázek 3.1: Rozhraní aplikace. U zobrazení stopy je vyznačena aktuální pozice kurzoru a uživatelský výběr.
Obrázek 3.2: Detail progressbaru při vykonávání operace a po ní.
29
3.2.1
Hlavní menu
Hlavní menu prostřednictvím svých voleb poskytuje všechny dostupné služby spojené s editací a přehráváním souboru. Menu je rozdělené na několik submenu. File Menu File obsahuje volby pro práci se zdrojovým souborem jako je otevření (Open), zavření (Close), uložení (Save), nebo uložení pod novým jménem (Save As). Edit Toto menu obsahuje volby pro kopírování (Copy), vkládání (Paste), mazání (Delete) a další práci s výběrem. Dále obsahuje volby Undo a Redo pro vracení změn. View Menu View obsahuje volby pro změnu zobrazení stopy jako jsou například přiblížení (Zoom In), oddálení (Zoom Out), maximální oddálení (Zoom Out Full) a přiblížení výběru (Zoom to region). Process V tomto menu jsou k dispozici volby pro aplikaci efektů provádějících základní operace. Obsaženy jsou funkce postupné zesílení (Fade In), postupné zeslabení (Fade Out), invertování vzorků (Invert Samples), otočení vybraného úseku (Reverse), vložení prázdného signálu (Insert Silence), normalizace (Normalize), úprava hlasitosti (Volume), utlumení signálu (Mute) a míchání kanálů (Convert Channels). Filter Menu Filter poskytuje pokročilejší filtry. Obsahuje filtry zkreslení (Distortion), ozvěna (Echo), flanger (Flanger), ekvalizér (Equalizer). Player Toto menu obsahuje volby pro přehrávání souboru. Nabízí volby přehrávání ve smyčce (Loop), přehrávání (Play), přehrávání od začátku souboru (Play All), pozastavení (Pause), zastavení přehrávání (Stop), přehrávání/zastavení (Toggle Play/Stop), sledování kurzoru (Track Cursor).
3.2.2
Zobrazení stopy
Základem programu je grafická editace zvukové stopy, která je zobrazována v hlavním formuláři aplikace jako zvuková vlna (v případě vícestopých souborů jsou jednotlivé stopy kresleny pod sebe). U vykreslené stopy je znázorněn uživatelský výběr části editovaného souboru. Dále je zde zobrazena aktuální pozice v přehrávaném souboru. Tu je možné měnit stiskem levého tlačítka myši nad požadovanou 30
Obrázek 3.3: Příklad detailního zobrazení stopy. pozicí. Zobrazení detailu stopy s označeným výběrem a kurzorem zobrazuje obrázek 3.3. Program umožňuje zvětšování, zmenšování zobrazení stopy a posun zobrazované části. Postup pro zvětšení nebo zmenšení zobrazení, výběr a změnu pozice je popsán v sekci 3.4.
3.3 3.3.1
Editace Výběr, základní editace
Program umožňuje vybrat část zobrazované stopy a provádět na ní editaci. S vybranou částí souboru je možné zacházet podobně jako s označenou částí textu v textovém editoru. Pomocí volby Copy z menu Edit je výběr zkopírován do veřejné schránky Windows a může být tedy následně použit v jiných programech používajících stejný formát dat, nebo v dalších instancích programu AEditor. Zvolením položky Delete bude označený úsek souboru smazán a soubor bude odpovídajícím způsobem zkrácen. Další možností je položka Cut, která vyjme označenou část ze souboru a vloží ji do schránky. Pokud jsou ve schránce data odpovídajícího formátu (například i z jiného programu), je možné je vložit na aktuální pozici kurzoru pomocí volby Paste (soubor bude zvětšen). Podobným způsobem lze na výběr aplikovat filtr. Program podporuje přehrávání výběru. Podrobnější informace jsou obsaženy v sekci 3.4.
3.3.2
Pokročilá editace, aplikace filtrů
Program AEditoru umožňuje aplikaci filtrů na vybranou část souboru. Filtry je možné aplikovat výběrem příslušné položky z menu Process nebo Filter. Pokud 31
je výběr prázdný, filtr se aplikuje implicitně na celý soubor. Většina filtrů vyžaduje nastavení parametrů pomocí příslušného dialogu, který je vyvolán vybráním odpovídající položky z menu. Takové filtry jsou aplikovány až po potvrzení dialogu. Většina filtrů nastavovaných pomocí dialogu umožňuje real-time náhled. Náhled lze spustit stiskem tlačítka Preview. V náhledu je přehrán aktuální výběr (včetně implicitního) za současné aplikace aktuální konfigurace filtru. Všechny změny nastavení filtru se při přehrávání náhledu projeví ihned. Dostupné filtry jsou uvedeny v sekci 3.2.1. Příklad aplikace filtru je uveden v sekci 3.4.
3.3.3
Undo, Redo
Po aplikaci libovolného filtru, nebo změně souboru vkládáním a mazáním nebo vyjímáním částí dat, je možné tyto změny vrátit pomocí výběru volby Undo z menu Edit. Program obsahuje maximálně 10 posledních změn, v závislosti na velikosti dostupné paměti. Pro zpětnou aplikaci vrácené změny slouží volba Redo ze stejného menu. Program podporuje Redo pouze pro poslední provedenou Undo operaci. U obou těchto akcí je výběrem automaticky označena ovlivněná část souboru.
3.3.4
Přehrávání souboru
Další důležitou částí editoru je přehrávač editované stopy. Aktuální pozice přehrávání je zobrazena ve formě kurzoru na vykreslené stopě (viz oddíl o zobrazování stopy) a lze ji měnit stiskem levého tlačítka myši nad požadovanou pozicí. Přehrávání je možné zapnout výběrem volby Play z menu Player nebo stiskem mezerníku. Pro zastavení přehrávání slouží volba Stop ze stejného menu nebo opětovný stisk mezery. Ta plní stejnou funkci jako volba Toggle Play/Stop. Výběrem volby Pause je přehrávání pozastaveno. Přehráván je vždy aktuální výběr souboru, případně implicitní výběr. Výjimku tvoří případ, kdy při přehrávání vybereme část souboru tažením proti směru přehrávání. V tomto případě je použit opět implicitní výběr celého souboru. Pomocí zatrhnutí volby Loop z menu Player se zapne přehrávání výběru ve smyčce. Při přehrávání souboru se zvětšením stopy větším, než je aktuální šířka okna, lze zvolit možnost sledování kurzoru pomocí zatržení volby Track Cursor z menu Player. Zobrazovaná stopa je pak automaticky posunována tak, aby byl kurzor vždy viditelný.
32
3.4 3.4.1
Příklady použití Výběr
Vybrání požadované části souboru se provede pomocí tažení kurzoru myši přes cílový úsek zobrazované stopy za současného držení levého tlačítka myši. Pokud má výběr nulovou velikost (například v případě samostatného kliknutí na libovolnou pozici v souboru), je použita implicitní selekce celého souboru (není graficky zvýrazněna). Implicitní selekce je použita jak při určení rozsahu přehrávání, tak pro aplikaci filtrů. Naopak není použita pro kopírování, vkládání nebo mazání. Explicitní výběr celého souboru se provede pomocí volby Select All z menu Edit.
3.4.2
Změna detailu a posun zobrazení
Zvětšení či zmenšení detailu zobrazované stopy se provede otočením kolečka myši, či pomocí volby Zoom Out nebo Zoom In z menu View. Přizpůsobení aktuálně vybrané části1 aktuální velikosti okna se provede stiskem pravého tlačítka myši nebo pomocí volby Zoom To Region. Pro přizpůsobení zobrazení celého souboru aktuální velikosti okna je třeba dvakrát stisknout pravé tlačítko myši nebo použít volbu Zoom Out Full. Posun zobrazení2 lze provést tažením myši nad zobrazovanou stopou za současného držení prostředního tlačítka (kolečka) myši. Další možnost posunu zobrazení je tažením kurzoru za současného držení levého tlačítka myši a klávesy Alt. K posunu lze použít též posuvník.
3.4.3
Změna pozice a kurzoru, přehrávání ve smyčce
Pozici přehrávání změníme kliknutím myši nad požadovanou pozicí v zobrazované stopě. Pozici lze změnit i během přehrávání. Po zastavení se při příštím přehrávání pozice automaticky nastaví na poslední takto vybranou hodnotu. Zrušení uživatelem nastavené výchozí pozice přehrávání a její nastavení na začátek souboru se provede pomocí volby Play All z menu Player. Pro přehrání části souboru ve smyčce nejdříve vybereme požadovanou část pro přehrávání. Poté v menu Player zatrhneme volbu Loop. Po spuštění přehrávání pomocí Play nebo Toggle Play/Stop či stiskem mezery, bude vybraná část přehrávána ve smyčce. Přepínání přehrávání ve smyčce lze provést i během přehrávání. 1 2
Nepočítá se implicitní výběr. K dispozici jen pokud se zobrazovaná stopa nevejde do okna.
33
Pokud chceme sledovat aktuální pozici přehrávání při větším zvětšení, než je aktuální šířka vykreslované plochy, zatrhneme volby Track Cursor z menu Player. Zobrazovaná stopa bude pak automaticky posunována v závislosti na pozici kurzoru pro přehrávání. Automatické posouvání bude pozastaveno při manuálním posunu uživatelem.
3.4.4
Copy, paste, delete
Pro základní editaci pomocí copy/paste/delete z menu Edit je třeba nejdříve označit požadovaný úsek souboru. Poté volbou Copy (nebo její klávesovou zkratkou) můžeme označený úsek vložit do schránky, nebo pomocí volby Delete tento označený úsek smazat, či pomocí Cut vyjmout. Poté přesuneme kurzor na požadovanou pozici a pomocí volby Paste vložíme data ze schránky. Všechny tyto akce lze vrátit pomocí Undo.
3.4.5
Aplikace equalizeru
Pro použití equalizeru na daný soubor opět vybereme požadovanou část, případně pokud chceme filtr aplikovat na celý soubor, ponecháme implicitní výběr, nebo vybereme vše explicitně pomocí volby Select All z menu Edit. Poté zvolíme volbu Equalizer z menu Filter. Objeví se dialog pro nastavení úrovní zesílení pro jednotlivá frekvenční pásma. Úrovně zesílení jsou udávány v decibelech a v procentech. Posunutím ovládacích prvků nastavíme odpovídající konfiguraci filtru. Pro usnadnění konfigurace můžeme použít real-time náhled (tlačítkem Preview), který přehraje označenou část souboru po aplikaci aktuální konfigurace filtru. Aplikace filtru je prováděna za běhu, a tedy všechny změny konfigurace se ihned projeví v přehrávaném náhledu. Permanentní aplikace filtru je provedena po potvrzení dialogu pomocí tlačítka OK. Průběh aplikace filtru je znázorněn progressbarem ve stavovém řádku aplikace, kde je po skončení zobrazen čas trvání operace. Změny lze poté vrátit pomocí volby Undo. Dialog lze zrušit tlačítkem Cancel.
3.4.6
Úprava hlasitosti
Upravení hlasitosti funguje podobně jako aplikace equalizeru z předchozí sekce. Opět nejdříve vybereme požadovanou část souboru, poté zvolíme položku Volume z menu Process. Pomocí konfiguračního dialogu s možností náhledu zvolíme požadovanou úroveň zesílení a potvrdíme dialog.
34
3.4.7
Zajímavá nastavení filtrů
Echo Filter Echo nabízí několik zajímavých konfigurací. Nastavení parametru Delay by se typicky mělo pohybovat v rozmezí 100 – 2000 ms. Při kratším zpoždění přestává být ozvěna slyšitelná a začíná se výrazně projevovat vliv filtru na frekvenční spektrum signálu. Parametr Mix je dobré nastavovat na hodnotu mezi 10% a 60%. Při vyšších hodnotách dochází k přílišnému přebuzení výstupního signálu a ke zkreslení. Základní konfigurací pro lehkou ozvěnu použitelnou například pro zvýraznění vokálů může být Delay=150 a Mix=15. Efektu klasické ozvěny lze dosáhnout například konfigurací Delay=250 a Mix=40. Pro demonstraci vlivu filtru i na frekvenční spektrum může sloužit konfigurace Delay<= 50, Mix=50. Equalizer Aplikace nabízí 12pásmový equalizer s možností regulace frekvencí od 20 Hz do 20 kHz. Možná nastavení jsou stejná jako u běžných programů. Zvýšením úrovně zesílení pro frekvence menší než 160 Hz dojde ke zvýraznění basů, pásmo od 200 do 3000 Hz odpovídá lidskému hlasu. Zesílením vyšších frekvencí než je 3000 Hz se dosáhne projasnění zvukové stopy. Zajímavé výsledky mohou být dosaženy úplným zeslabením některých frekvenčních pásem. Například zeslabení všech frekvencí kromě intervalu 200–3000 Hz připomíná telefonní linku. Při vyšším zesílení pásem může docházet ke zkreslení signálu. Flanger Flanger patří mezi výrazné filtry. Jeho využití záleží hlavně na vkusu uživatele. Pro ilustraci základního efektu tohoto filtru může sloužit například konfigurace Flanger=0,1 Hz, Depth=1000 a Mix=50%. Parametr Flanger by se měl pohybovat v rozmezí 0.1 až 2 Hz. V některých extrémních nastaveních můžeme ovšem také dosáhnout zajímavých výsledků. Parametr Depth je lépe většinou nastavovat na hodnoty menší než 1000. Větší hodnoty zvýrazňují efekt tohoto filtru. Parametr Mix by se měl pohybovat v rozmezí 30% až 60%. Při vyšších hodnotách je efekt příliš výrazný. Zajímavého efektu se dá docílit například použitím konfigurace Depth=100, Flanger=8400 Hz, a Mix=50%.
35
Kapitola 4 Návrh a implementace V kapitole je uvedena programátorská dokumentace programu AEditor pro editaci zvuku. Vlastní program je uložen jako samostatná příloha na přiloženém nosiči CD. Kapitola popisuje strukturu programu, řešené problémy, použité technologie, postupy a návrhy možných úprav a rozšíření. Dále popisuje implementaci jednotlivých částí aplikace včetně důležitých tříd programu. Pro implementaci některých částí programu byly využity postupy popsané v [6].
4.1 4.1.1
Požadavky na program Funkce pro práci se zvukem
Základním požadavkem bylo vypracovat program pro aplikaci digitálních zvukových filtrů a demonstrovat práci s digitálním zvukem. Z toho vyplývá požadavek na práci s některým z používaných hudebních formátů. Byl zvolen formát WAVE, pro způsob uložení dat a pro jeho rozšíření v této oblasti. Kromě samostatné aplikace filtrů by měl program umožňovat i další editaci jako je kopírování, mazání a vkládání. S tím je spojen požadavek na zobrazování stopy v grafickém rozhraní (viz další sekce). Další požadovanou funkcí je možnost přehrávání upraveného souboru. Cílem programu však není implementovat všechny zmiňované efekty z teoretické části, ale pouze ukázat příklad jejich možné implementace a poskytnout ostatní funkce, které jsou s editací zvuku spojené.
36
4.1.2
Grafické prostředí
Některé požadované funkce, jako je kopírování a vkládání, vyžadují grafické zobrazení upravovaného souboru v uživatelském rozhraní. Aplikace by měla nabízet podobné rozhraní, jaké poskytují profesionální programy, zabývající se stejnou problematikou. Rozhraní by mělo umožňovat zobrazování a výběr části upravovaného souboru, přehrávání souboru a mělo by nabízet konfiguraci a aplikaci filtrů pomocí dialogových oken.
4.2 4.2.1
Použité technologie Platforma a jazyk
Aplikace je naprogramována pro běhové prostředí MS .NET 2.0 v jazyce C# a C++ (native i CLI). Pro grafické uživatelské rozhraní je použita knihovna Windows Forms pro .NET. Pro spolupráci se zvukovou kartou je použita knihovna DirectSound z Managed DirectX 9. Filtry pro zpracování samotných audio dat jsou naprogramovány v native C++ pro Win32 a pro práci s nimi jsou součástí programu i wrapper třídy v managed C++. Veškeré pomocné třídy jsou jako součást grafického rozhraní také naprogramovány v jazyce C#. Rozhodujícím faktorem pro volbu platformy byla knihovna pro práci se zvukem. Knihovna DirectSound z Managed DirectX pro platformu .NET poskytuje pohodlnou práci se zvukovým zařízením a nabízí dostatečnou abstrakci. Z tohoto rozhodnutí vyplývá i volba grafické knihovny Windows Forms pro .NET. Další výhodou cílové platformy je možnost použití některých mechanismů jako je například Reflection, který je použit pro automatické generování dialogů filtrů. Zvoleným jazykem pro implementaci programu na platformě .NET je C#, především kvůli jeho integraci na této platformě. Implementace filtrů v native Win32 vyplývá z vyšších nároků na výkon této části aplikace. Knihovna wrapper tříd v managed C++ pak umožňuje použití těchto filtrů z .NET C# kódu. Nevýhodou zvolené platformy a struktury programu je především nižší výkon části kódu, běžícího na platformě .NET, a omezení použití pouze na operační systémy Windows.
4.2.2
Managed DirectX
Aplikace je naprogramována v prostředí MS .NET, a jak bylo řečeno, využívá tento framework i pro práci se zvukovou kartou. K práci se zvukovou kartou v prostředí .NET slouží rozhraní DirectSound z knihovny Managed DirectX, která 37
je součástí DirectX SDK (software development kit). Všechny základní třídy pro práci se zvukem jsou obsaženy v namespace Microsoft.DirectX.DirectSound. Základní třídou pro práci s rozhraním DirectSound je třída Device. Její metody zprostředkovávají práci se zvukovou kartou, inicializaci bufferů a podobně. Další důležitou třídou je třída SecondaryBuffer, která představuje sekundární zvukový buffer s metodami pro čtení a zápis dat a samotné přehrání bufferu s nastavením parametrů přehrávání (hlasitost, přehrávání ve smyčce). Při práci s knihovnou je nejprve vytvořena instance třídy Device. Dále je nastaven takzvaný CooperativeLevel pro daný formulář (způsob komunikace se zvukovou kartou). Následně je vytvořena instance třídy BufferDescription, která určuje vlastnosti příslušného sekundárního bufferu. Nastaví se potřebné vlastnosti (manuální ovládání hlasitosti, upozornění na pozici, umístění bufferu v paměti počítače namísto paměti zvukové karty - LocateInSoftware) a požadovaná velikost. Tato instance se poté předá konstruktoru třídy SecondaryBuffer. Takto vytvořenému bufferu potom můžeme nastavovat všechny zvolené parametry včetně automatických upozornění na procházenou pozici. Další manipulace, závislá na použití v tomto programu, bude probrána později.
4.2.3
KissFFT
Součástí programu je také knihovna pro diskrétní Fourierovu transformaci KissFFT [5]. Tato knihovna je zvolena pro svoje jednoduché použití a dobrý výkon. Je distribuována ve formě zdrojových kódů v C pro Win32 a v programu je obsažena jako součást knihovny implementující filtry.
4.3 4.3.1
Struktura programu Moduly
Základní struktura vychází ze zvoleného rozdělení implementace filtrů a implementace grafického rozhraní. Celá aplikace se skládá ze tří binárních souborů. Hlavní je spustitelný soubor, představující grafické rozhraní. K němu je přidána knihovna pro samotné fitry a knihovna wrapper tříd k těmto filtrům.
4.3.2
Vnitřní struktura aplikace
Celý program se skládá z několika hlavních částí. Jeho strukturu ukazuje obrázek 4.1. Nejdůležitější částí je hlavní formulář s obsluhou uživatelských událostí,
38
Obrázek 4.1: Schema struktury aplikace. Šipky znázorňují směr poskytovaných služeb. který představuje třída MainForm. Ten pro obsluhu těchto událostí využívá služeb, které poskytuje třída ApplicationManager. Důležitou částí třídy MainForm je uživatelský ovládací prvek WaveControl, který zajišťuje zobrazování zvukové stopy a obsluhu událostí, spojených s tímto zobrazením (selekce, změna pozice kurzoru, přibližování apod.). Třída ApplicationManager využívá pro zajištění požadovaných služeb pomocné třídy. Pro práci s daty používá instanci třídy WaveReaderWriter. Tuto společnou instanci poskytuje dalším objektům, které pracují se zvukovými daty. Další pomocnou třídou je třída PlayerManager, která zajišťuje přístup ke zvukovému zařízení a umožňuje přehrávání souboru. Pomocnou třídou pro ukládání změn souboru a umožňující undo/redo operace je třída HistoryManager. Pro práci se schránkou je použita třída ClipboardManager. Filtry, které vyžadují speciální přístup k datům, jsou implementovány třídou DataProcessManager. Pro vykreslování stopy ve třídě WaveControl jsou data této třídě poskytována pomocí přístupové třídy WaveFile. Její společná instance je spravována třídou ApplicationManager. 39
Součástí funkcí poskytovaných třídou ApplicationManager je správa automaticky generovaných formulářů filtrů pomocí třídy FilterFormManager, která zároveň uchovává i reference na wrapper třídy odpovídajících filtrů. Jejich aplikace potom opět probíhá pomocí volání metod třídy ApplicationManager
4.4
Manipulace s daty
Program podporuje zvukové soubory ve formátu WAVE. Podporovaná je 16bitová verze tohoto formátu s jedním nebo dvěma kanály (mono, stereo) bez komprese. Vzorkovací frekvence může být libovolná. S touto frekvencí program nepracuje, pouze ji nastaví jako parametr bufferu pro přehrávání.
4.4.1
Čtení
Čtení ze souboru zajišťuje třída WaveReader. Ta v konstruktoru načte hlavičky daného souboru a jejich obsah zpřístupní pomocí veřejných vlastností. Podporovanými oddíly jsou pouze hlavní Riff oddíl, formátovací a datový oddíl. Ostatní nepodporované oddíly jsou automaticky přeskakovány. Vlastní data jsou uložena ve vnitřní paměti třídy WaveReader. Třída WaveReader dále nabízí metody pro čtení uložených dat. Tato data jsou načítána do bufferu, který je předán jako parametr. Načítání se provádí po bytech, nebo jako pole struktur PCM16Frame či PCM16MonoFrame. Dále tato třída vrací instanci FilterManaged.WaveFormat, která v sobě obsahuje všechny důležité informace o formátu a velikosti souboru. Tato instance se předává wrapper-třídám filtrů, kde je převedena na unmanaged formát, který je využit v koncových filtrech. Pro potřeby třídy WaveFile je ke zrychlení přístupu obsažena metoda pro přímý přístup k uloženým datům. Tato metoda je ovšem přístupná pouze z daného namespace (internal).
4.4.2
Zápis
Pro zápis do souboru slouží třída WaveReaderWriter, která je synovskou třídou WaveReader. Navíc implementuje metody pro zápis do souboru. A to jak zápis parametrů jednotlivých oddílů, které jsou nastavitelné pomocí veřejných vlastností třídy, tak samotných dat (tyto vlastnosti jsou na rozdíl od rodičovské třídy přístupné i pro zápis). Data mohou být zapisována opět jako buffer bytů nebo pole PCM16Frame, respektive PCM16MonoFrame. 40
Tato třída rozšiřuje třídu WaveReader, protože při způsobu práce se soubory v programu AEditor není výhodné mít k dispozici samostatnou třídu jenom pro zápis. Naopak dědičnost zjednodušuje implementaci zapisovacích metod. WaveReaderWriter poskytuje i metody pro editaci souboru, jako je například vkládání bloku dat na určitou pozici, mazání úseku nebo nahrazování bloků dat. Toho využívají takzvané manager-třídy (jmenovitě ApplicationManager), které tyto metody zpostředkovávají grafickému prostředí při editaci souboru.
4.4.3
Schránka
Protože program AEditor umožňuje kopírování a vkládání částí souboru, je nutné mít možnost data ukládat do schránky. V tomto programu je zvoleno ukládání do veřejné schránky Windows. To umožňuje případnou výměnu dat mezi více instancemi programu AEditor, nebo jinými programy, pracujícími v rámci schránky se stejným typem dat. Práci se schránkou zajišťuje manager třída ClipboardManager. Ta data zpřístupňuje prostřednictvím veřejné vlastnosti. Dále obsahuje metodu pro uložení datového bufferu do schránky Windows. Obsahuje i veřejnou vlastnost, která zjišťuje, zda jsou ve schránce data vhodného formátu, a vlastnost určující případně jejich velikost. Třída ClipboardManager ošetřuje i speciální situaci, kdy při chybě (například při nedostatku paměti) volání pro uložení objektu do schránky windows nevyvolá výjimku. Pouze je do schránky uložena null reference. ClipboardManager tuto situaci po každém vkládání a při každém výběru ze schránky kontroluje a případně reaguje vyvoláním vlastní výjimky.
4.5
Zobrazování stopy
Jak již bylo řečeno dříve, data jsou v souboru uložena ve formě vlny, kde je aktuální amplituda vyjádřena 2bytovým celým číslem. Takováto reprezentace usnadňuje samotné vykreslení zvukové vlny. Celá stopa je vykreslována uživatelsky kresleným ovládacím prvkem WaveControl. Tento ovládací prvek se stará o veškeré operace spojené s kreslením stopy, ať už se jedná o posunování nebo zoomování. Navíc ošetřuje uživatelské události spojené s kreslením stopy a informace o nich poskytuje prostřednictvím veřejných vlastností a událostí. Jedná se o události výběru části stopy a změnu aktuální pozice přehrávání. Na změny jsou ostatní objekty upozorňovány prostřednictvím příslušných událostí. Pozice přehrávání, stejně jako začátek a délka selekce, jsou přístupné prostřednictvím 41
vlastností třídy a jejich aktuální hodnoty jsou předávány jako parametry volání těchto událostí.
4.5.1
Vykreslování stopy
Třída WaveControl má předefinovanou metodu Draw, ve které jsou volány procedury pro vykreslení stopy. Podporované jsou pouze mono nebo stereo formáty dat. Třída je ovšem snadno rozšiřitelná, protože každá stopa je vykreslována samostatně stejnou funkcí, pouze s jinými parametry. Na začátku je spočtena pozice v souboru, od které se má začít vykreslovat (nepřekresluje se pokaždé stejná část souboru), a kolik maximálně vzorků dat se má přečíst (to znamená šířka vykreslované plochy). Data jsou procházena ve smyčce, kdy v jedné iteraci je spočtena maximální a minimální hodnota intervalu, který odpovídá počtu vzorků na jeden vykreslený pixel (zvětšení je ukládáno jako počet vzorků na pixel). Následně je nakreslena čára, spojující obě hodnoty. Pokud nemá v příští iteraci nový interval se starým žádný společný horizontální bod, je mezi nimi nakreslena spojovací čára. Při výpočtu minima a maxima jsou pro zrychlení vykreslování některé vzorky přeskakovány v závislosti na aktuálním zvětšení. Součástí vykreslování stopy je i kreslení selekce a vodících čar. Pro vykreslení vodících čar existují samostatné metody. Vykreslování selekce se provádí rozdělením kreslení celé stopy na část před selekcí, selekci a část za selekcí, kdy jsou v části kreslení selekce zadány jiné parametry pro barvy popředí a pozadí.
4.5.2
Vykreslování pozice přehrávání
Vykreslování pozice přehrávání je ošetřováno speciálním způsobem, protože tato pozice se mění v závislosti na vnějších událostech. Ke změně vykreslované pozice přehrávání může dojít dvěma způsoby. Buď od uživatele (vyvoláním události myši), nebo z vlákna pro sledování přehrávání souboru. První možnost je ošetřena přímo hlavním vláknem pomocí vyvolání handleru příslušné události. Druhá možnost nastává při signalizaci časovače pro sledování přehrávání, který je spravován třídou PlayerPositionNotifier. Tento časovač běží v odděleném vlákně a v pravidelných intervalech zjišťuje aktuální pozici v přehrávaném souboru. Vlákno běží jen pokud právě probíhá přehrávání nebo pokud je přehrávání pozastaveno. S ukončením přehrávání je ukončeno i toto vlákno. Pro aktualizaci pozice je potřeba, z důvodu bezpečnostního nastavení Windows Forms, zavolat překreslení ovládacího prvku na vlákně, kde byl tento prvek vytvořen (neboli na 42
vlákně, které je jeho vlastníkem). Pro komunikaci timeru a WaveControl prvku má WaveControl referenci na delegáta třídy PlayerPositionNotifier, který je volán při signalizaci timeru.
4.5.3
Posun a změna detailu zobrazení
Aktuální zvětšení je v programu reprezentováno jako počet vzorků na jeden vykreslovaný pixel. Z této hodnoty potom vychází počítání minimálních a maximálních hodnot při kreslení. Přibližování nebo oddalování potom znamená změnu této hodnoty. Momentální posun zobrazení je reprezentován počtem vzorků od začátku souboru k začátku zobrazovaných dat. Při výpočtu vykreslovaných hodnot se vždy začíná od tohoto místa. Posun potom spočívá ve změně této hodnoty.
4.5.4
Zdroje dat
Zdrojem dat pro třídu WaveControl je třída WaveFile, která poskytuje data pomocí veřejné vlastnosti Data jako pole struktur Pcm16Frame. Vlastnost Data je typu DataStorage, který data poskytovaná třídou WaveReader převádí na vzorky požadovaného typu. Původní záměr pro použití této třídy byl v inteligentním bufferování dat určených pro vykreslení. Tím by se urychlilo zobrazování velkých souborů při větším oddálení zobrazení. Požadované vzorky by byly předpočítány pro požadovanou velikost zvětšení, a proto by se nemusel při velkém oddálení procházet celý soubor. Ostatní třídy k datům přistupují pomocí indexeru, který je na této třídě definován. Kromě dat samotných obsahuje třída WaveFile i údaje o formátu zobrazovaného souboru.
4.6
Přehrávání zvuku
Jednou z důležitých částí programu je přehrávání hudební stopy. Jak již bylo řečeno výše, je využito rozhraní DirectX DirectSound. Základní třídou pro přehrávání je třída BasicSoundBuffer. Ta obsahuje referenci třídy SecondaryBuffer. Synovské třídy potom implementují jednotlivé typy bufferů. Ať už se jedná o statický buffer nebo stream buffer. v této aplikaci je použitá pouze streamovaná varianta, ale statický buffer lze například využít u souborů menší velikosti.
43
4.6.1
Streamované přehrávání
Streamované přehrávání zvuku (přehrávání proudu dat) je implementováno třídou StreamSoundBuffer, která je synovskou třídou BasicSoundBuffer. Obsahuje referenci na instanci třídy WaveReader, která zprostředkovává načítání dat pro přehrávání. Dále obsahuje referenci na instanci třídy SecondaryBuffer. Hlavním úkolem třídy StreamSoundBuffer je plnit tento buffer daty, která poskytne instance třídy WaveReader. Při přehrávání jsou data do bufferu nahrávána v samostatném vlákně. Buffer je přehráván ve smyčce, přičemž je průběžně plněn novými daty z přenosového vlákna. Buffer je rozdělen na několik sektorů. Na konci každého sektoru je nastavena notifikace pro jeho naplnění. Pro signalizaci události naplnění sektoru je použita třída System.Threading.AutoResetEvent.Vlákno pro plnění bufferu čeká ve smyčce, dokud nepřijde požadavek na naplnění dalšího sektoru. Poté jsou načtená data zapsána do tohoto volného sektoru a vlákno se opět uspí při čekání na další událost. Pokud jsou načtena již všechna data, vlákno ukončí smyčku. Po příchodu další události naplní volný sektor prázdnými daty. Tato operace se provádí pro zamezení přehrání starých dat při ukončování vlákna. Následně jsou zrušeny staré události o přehrání dalšího sektoru a je nastavena signalizace na konec dat. Dále vlákno opět čeká ve smyčce, dokud nepřijde tato signalizace konce dat. Ve smyčce se čeká proto, že systém může spící vlákno probudit z jiných důvodů. Jakmile přijde událost o konci dat, zastaví se přehrávání bufferu, a vlákno se ukončí.
4.6.2
Manipulace se streamem
Při manipulaci s třídou StreamSoundBuffer, vyvolanou voláním veřejných metod, je třeba synchronizovat hlavní vlákno a vlákno pro přenos dat do bufferu. Pro synchronizaci jsou použity třídy System.Threading.AutoResetEvent a System.Threading.Mutex. AutoResetEvent slouží k časové synchronizaci obou vláken při změně stavu plnícího vlákna. Třída Mutex zajišťuje exkluzivní přístup k vláknu a zápis do bufferu. Dále je využíván i implicitní zámek, který poskytuje jazyk C#, pro synchronizaci přístupu z vnějších částí programu. Změna pozice přehrávání Při volání funkce pro změnu pozice přehrávání SetPlayerPosition je nejdříve potřeba počkat na vlákno pro přenos dat a zastavit ho. Zastavení se provede pokusem o zamčení zámku pro manipulaci s vláknem. Pokud vlákno právě pracuje, 44
volání se zablokuje. Dále je třeba zastavit přehrávání bufferu. Díky zastavení přehrávání nepřijde další signalizace naplnění bufferu nebo konce přehrávání a přenosové vlákno se uspí při čekání na tuto událost. Po uspání vlákna jsou nastaveny všechny vnitřní řídící proměnné na hodnoty odpovídající nové pozici. Po jejich nastavení je celý buffer naplněn novými daty, přičemž je zvlášť ošetřen případ načtení konce dat. Dále je potřeba dostat přenosové vlákno do stavu, ve kterém by bylo na nové pozici při sekvenčním přehrávání. Ke změně stavu přenosového vlákna slouží metody RestoreDataTransferThread a SetTransferThreadToEndWaitState. První metoda změní stav vlákna, z čekání na konec přehrávání, na výchozí stav (stav pro plnění dat při přehrávání). Druhá metoda zajišťuje opačný proces, tedy stav pro plnění dat změní na stav čekání na konec souboru. Změna selekce Další situací, kdy je třeba měnit obsah bufferu a stav plnícího vlákna, je změna selekce. Pokud je konec vybrané části dostatečně vzdálený, dojde k jeho ošetření normálním způsobem při plnění bufferu. Pokud se ale konec výběru nachází uprostřed aktuálně přehrávaného úseku, je zapotřebí buffer znovu naplnit a nastavit vlákno pro přenos dat do odpovídajícího stavu. To se provádí podobným způsobem jako při změně pozice přehrávání. Přehrávání ve smyčce Poslední speciální situací je přehrávání výběru ve smyčce. Tato situace je ošetřena ve vlákně pro přenos dat. Po příchodu události pro zastavení přehrávání se vlákno místo ukončení samo vrátí do výchozího stavu (stav pro plnění dat při přehrávání).
4.6.3
Ovládání přehrávače
Protože sama třída StreamSoundBuffer poskytuje pouze základní služby pro přehrávání zvuku, je třeba k jejímu ovládání použít přístupovou třídu, která bude nad tímto rozhraním implementovat funkce, požadované grafickým prostředím. Tuto funkci plní třída PlayerManager. Obsahuje a spravuje reference na instance tříd StreamSoundBuffer a Device. Stará se o správnou inicializaci a správu třídy Device (viz oddíl o Managed DirectX). Navíc řídí inicializaci a přístup k instanci třídy StreamSoundBuffer. Dále zajišťuje sledování aktuální pozice přehrávání prostřednictvím separátního vlákna, které je spravováno tří45
dou PlayerPositionNotifier. Toto vlákno v pravidelných intervalech zjišťuje aktuální pozici. Zjištěné hodnoty aktuální pozice jsou pak zpřístupněny pomocí události třídy PlayerManager. Program obsahuje pouze jednu instanci třídy PlayerManager. Ta po vytvoření inicializuje zvukové zařízení pomocí třídy Device a poté pro každý otevřený soubor vytváří samostatnou instanci třídy StreamSoundBuffer. Celá třída PlayerManager je pak přístupná z třídy ApplicationManager prostřednictvím veřejné vlastnosti.
4.7
ApplicationManager
Hlavní funkcí třídy ApplicationManager je zajišťovat komunikaci mezi pomocnými třídami a grafickým rozhraním. Další důležitou funkcí je správa společných instancí pro přístup k datům a řízení toku dat mezi pomocnými třídami. Z těchto důvodů je této třídě a jejím podčástem věnován samostatný oddíl.
4.7.1
Pomocné manager třídy
Třída ApplicationManager využívá pomocné manager třídy ClipboardManager, PlayerManager, HistoryManager, FilterFormManager, DataProcessManager a reference na třídy pro práci s daty WaveReaderWriter a WaveFile. Některé z těchto tříd byly popsány již výše, ostatní budou popsány v dalších sekcích. Třída ApplicationManager poskytuje služby pomocných tříd ve formě vlastních vlastností, metod a událostí, které poté využívá třída MainForm, což je třída pro hlavní formulář. Některé z těchto tříd jsou případně poskytovány přímo prostřednictvím veřejných vlastností. Jak bylo zmíněno na začátku, důležitou úlohou třídy ApplicationManager je správa společných instancí tříd pro práci s daty a řízení toku dat mezi pomocnými třídami. Reference na třídu WaveReaderWriter je distribuována všem pomocným třídám, které potřebují pracovat s daty. Ostatním pomocným třídám jsou data zprostředkována v metodách třídy ApplicationManager. Typickým příkladem je operace vložení části dat, kdy je grafickým rozhraním zavolána metoda třídy ApplicaitonManager pro vkládání vzorků PasteSamples. V této metodě jsou vyzvednuta data ze schránky voláním příslušných metod třídy ClipboardManager, následuje uložení stavu souboru pomocí třídy HistoryManager a nakonec jsou získaná data zapsána pomocí metod třídy WaveReaderWriter.
46
4.7.2
Správa generovaných dialogů
Kromě práce s daty zajišťuje třída ApplicationManager správu vygenerovaných dialogů k jednotlivým filtrům a poskytuje tyto dialogy třídě MainForm. Dialogy jsou uchovány v holder-třídě EffectInfo, společně s referencí na wrapper třídu příslušného filtru, a jsou spravovány třídou FilterFormManager. Po potvrzení dialogu filtru uživatelem je tento filtr předán třídě ApplicationManager. Ta filtr aplikuje na vybranou část souboru prostřednictním volání metod třídy WaveReaderWriter.
4.7.3
Shrnutí významu třídy
Důvodem, proč třída ApplicationManager zajišťuje veškerou funkčnost, vyžadovanou hlavním formulářem (ať už práci s přehrávacím bufferem, nebo práci s datovým souborem či interakci s jednotlivými filtry), je snaha v co největší míře zjednodušit volání z hlavního formuláře při obsluze klientských událostí.
4.8
Undo, Redo
Jednou z dílčích částí služeb, poskytovaných programem, je vracení změn, neboli undo, a s tím související zpětná aplikace vrácených změn, neboli redo. S těmito funkcemi se setkáváme u všech typů editorů. V případě editace zvukových souborů je tento problém složitější v tom, že zvuková data jsou poměrně značně objemná. To může způsobit nedostatek paměti při ukládání předchozích stavů souboru. V programu AEditor je pro undo a redo použito ukládání části souboru, která byla poslední akcí změněna, do paměti. Takto uložené části dat mohou být znovu vloženy na původní místo, čímž se vrátí provedené změny. Správu úseků dat, které reprezentují předchozí stavy souboru, zajišťuje pomocná třída HistoryManager. Tato třída obsahuje referenci na společnou instanci WaveReaderWriter pro přístup k datům. Podle předaných parametrů pak při volání příslušné funkce vytvoří obraz dat, která mají být změněna, a uloží jej do vnitřního seznamu změn. Potom mohou být tyto změny voláním metody Undo vráceny zpět. Při volání Undo je opět vytvořen aktuální obraz dat, který bude použit při případném Redo. Podporovaná je i situace, kdy se liší velikost původní a nové části souboru (používá se například u vracení operace mazání nebo vkládání). Třída si obrazy dat pro redo neukládá do pole, ale pamatuje si pouze poslední. To znamená, že undo operací může být více (dle definovaného maxima),
47
zatímco redo operace je k dispozici pouze jedna. Toto omezení je hlavně z důvodu zjednodušení a rezervace paměti pro případné undo operace.
4.9
Automatické generování formulářů
Protože je kladen důraz na snadnou rozšiřitelnost knihovny filtrů, obsahuje program AEditor rozhraní pro automatické generování ovládacích formulářů k jednotlivým filtrům. Pro automatické generování formulářů je využit mechanismus .NET Reflection. Generování je implementováno pomocí dynamické alokace odpovídajících ovládacích prvků a jejich přidání do struktury formuláře.
4.9.1
Definice atributů
Důležitou funkci plní wrapper třídy jednotlivých filtrů, které, kromě zprostředkování metod nativních filtrů, definují rozhraní pro generování formulářů. Každá wrapper třída definuje pomocí atributů svých vlastností, které z nich jsou parametry filtru a které je tedy potřeba upravovat pomocí generovaného formuláře. Dále jsou pomocí těchto atributů nastaveny i jména daných vlastností, jejich rozsah, inkrement při skokové změně, typ kontrolního prvku, který jim bude přiřazen (viz dále), případně jednotka. Pro přiřazení těchto informací daným vlastnostem je použita speciální třída FxParameterAttribute. Ta tyto informace obsahuje jako položky předávané konstruktorem při definici atributu u položky wrapper třídy. Pomocí mechanismu Reflection jsou pak tyto hodnoty použity při generování samotného formuláře.
4.9.2
Generování ovládacích prvků
Základní třídou pro automatické generování formuláře je FxBasicForm. Tato třída definuje chování společných ovládacích prvků, jako jsou tlačítka pro náhled a přijmutí nebo zrušení dialogu. Dále obsahuje referenci na wrapper příslušného filtru. Z této instance je získán pomocí mechanismu reflection skutečný typ filtru. Z něj je potom stejným mechanismem získán seznam veřejných vlastností třídy, ze kterých jsou vybrány pouze ty, které jsou označeny atributem FxParameterAttribute. Ke každé takovéto vlastnosti je získána odpovídající instance tohoto atributu. Pomocí této instance je pak vyroben nový uživatelský ovládací prvek. Pro potřeby automatického generování dialogů jsou definovány dva uživatelské ovládací prvky. Jsou to třídy FxSliderControl a FxSimpleDbSliderControl. Prní se skládá z komponent TrackBar a NumericBox. Umožňuje relativně jemné 48
nastavení příslušné vlastnosti. Používá se především pro číselné vlastnosti, jako je například doba zpoždění u filtru Echo apod. Druhý ovládací prvek slouží k nastavování relativních vlastností jako je například míra zesílení. Obsahuje pouze TrackBar s popisky, kde je relativní hodnota vyjádřena v procentech a v decibelech. Aktuální hodnoty těchto ovládacích prvků jsou přístupné přes veřejné vlastnosti obou tříd. Události použitých základních prvků jsou zpřístupněny ve formě veřejných událostí třídy. Pro filtr Equalizer je definována speciální třída FxEqualizerForm, která je synovskou třídou FxBasicForm. Třída FxEqualizerForm má předefinovanou metodu pro automatické vytváření uživatelských prvků, protože parametry equalizeru jsou uloženy v seznamu (jedná se o seznam míry zesílení pro jednotlivá frekvenční pásma). Dělat pro každé pásmo zvláštní vlastnost wrapper třídy equalizeru by bylo příliš náročné a málo flexibilní. Proto je tento filtr ošetřen zvlášť.
4.9.3
Real-time náhledy
Třída FxBasicForm obsahuje referenci na instanci StreamSoundBuffer, předanou v konstruktoru, která zajišťuje přehrávání real-time náhledů. Po vytvoření nového ovládacího prvku, výše uvedeným způsobem, musí být tento prvek provázán s atributy filtru. Provázání se provede vytvořením anonymních event-handlerů, které ve svém tělě mění odpovídající vlastnosti filtru. Poté, co jsou data vyzvednuta WaveReadrem, je buffer s daty předán filtru ke zpracování a až teprve pak je nahrán do streamovacího bufferu k přehrání. Pro práci s daty mezi načtením a přehráním slouží událost StreamSoundBuffer.OnDataPreprocessing. Díky tomu, že jsou data zpracována filtrem těsně před přehráním, a díky možnosti v reálném čase měnit parametry tohoto filtru, jsou změny okamžitě slyšet při přehrávání náhledu. Pro přehrávání se využívá nová instance StreamSoundBufferu, která ovšem využívá stejné zdrojové objekty (WaveReader apod.) jako hlavní instance, obsažená ve třídě PlayerManager.
49
Kapitola 5 Implementace audio filtrů Samostatnou částí jsou v rámci aplikace AEditor audio filtry. Jak bylo řečeno v úvodu kapitoly 4, filtry jsou implementovány v C++ jako nativní knihovna pro Win32. Tato implementace byla zvolena proto, že data jsou ve většině případů zpracována po bufferech a práce s poli je v nativním C++ (ovšem stejně jako v managed C++) efektivnější než C#. Kromě toho jsou na tyto filtry kladeny, oproti ostatním částem aplikace, poměrně vysoké nároky na výkon, a tedy i z tohoto důvodu je výhodnější použít nativní kód. Proto i použitá knihovna na FFT (KissFFT) je nativní knihovna pro prostředí Win32. V programu je obsažena ve formě zdrojových souborů a je tedy v binární podobě součástí knihovny s filtry.
5.1
Hierarchie filtrů
Pro zjednodušení implementace jednotlivých filtrů obsahuje program řadu abstraktních tříd. Synovským třídám, implementujícím samotné filtry, stačí zaměřit se pouze na vlastní algoritmický problém. Nevýhodou je nižší efektivita v některých případech. Základní třídou hierarchie je abstraktní třída CFilter. Ta obsahuje pouze formát zpracovávaných dat, reprezentovaných strukturou SWaveFormat, a instanci vnitřní třídy CFeedback, která umožňuje simulovat .NET událost (používá se k určení zpracované části dat). Dále třída CFilter definuje základní společnou metodu pro zpracování dat Process. Z třídy CFilter jsou poté odvozeny další abstraktní třídy, které zajišťují specifické předávání dat a na svých synovských třídách nechávají pouze jejich zpracování. To znamená, že implementují metodu Process a definují dílčí abstraktní metody určené pro specifické zpracování dat u dané třídy filtrů.
50
Obrázek 5.1: Schéma hierarchie filtrů obsažených v nativní knihovně. Abstraktní třídy jsou vyznačeny tmavým pozadím.
5.1.1
In-Place filtry
Tato skupina představuje filtry, které zpracovávají data po jednotlivých vzorcích, bez vazby na svoje okolí. Pro tyto filtry je připravena abstraktní třída CInPlaceFilter. Ta definuje nové abstraktní metody pro oddělené zpracování jednotlivých vzorků, ProcessMono a ProcessStereo. Dále implementuje základní metodu Process tak, že projde předaná data a na každý vzorek zavolá odpovídající abstraktní metodu. To umožňuje synovským třídám zabývat se pouze vlastním algoritmem. Příkladem mohou být filtry Volume nebo Invert.
5.1.2
Stream filtry
Jedná se o filtry, které jsou použity při zpracování proudu dat. Tato skupina je představovaná abstraktní třídou CStreamFilter. Neimplementuje žádné speciální metody. Je v hierarchii obsažena pouze pro vyjádření způsobu použití synovských tříd. V aplikaci AEditor nejsou implementovány žádné její koncové (neabstraktní) synovské třídy. Je zde ovšem ponechána možnost rozšíření. Jedním z nich by například mohlo být naprogramování FIR comb filtru (viz kapitola Digitální filtry a efekty).
5.1.3
Feedback-stream filtry
Jedná se o skupinu filtrů, které zpracovávají proud dat se zpětnou vazbou. Je možné specifikovat délku této zpětné vazby ve vzorcích. Tyto požadované vlastnosti implementuje třída CFeedbackStreamFilter, která je synovskou třídou
51
třídy CStreamFilter. Třída CFeedbackStreamFilter si pak ve speciálním bufferu uchovává data z předchozích volání metody Process. Opět definuje speciální metodu pro specifické zpracování dat a tou je metoda ProcessReverse. Této metodě je pro zpracování v synovské třídě předán buffer, který obsahuje jak aktuální data předaná v metodě Procces, tak data z bufferu pro zpětnou vazbu, spojená za sebe do jednoho pole. Metoda Process je pak implementována odpovídajícím způsobem. Ostatní položky a metody třídy CFeedbackStreamFilter zajišťují práci s bufferem pro zpětnou vazbu. Jde tedy vlastně o klasický IIR comb filtr (viz kapitola Digitální filtry a efekty). Typickým příkladem koncové synovské třídy je například CFilterEcho nebo CFilterFlanger.
5.1.4
Block filtry
Tato skupina filtrů pracuje s daty po blocích definované fixní velikosti. Tato velikost je parametrem daného filtru. Tuto skupinu reprezentuje třída CBlockFilter. Jako ostatní specifické abstraktní třídy, i tato implementuje metody Process podle požadovaných vlastností a definuje novou abstraktní metodu pro zpracování bloku dat ProcessBlock, která se stará o předávání dat po blocích stanovené velikosti. Pokud je blok dat předaných filtru příliš velký, bude rozdělen na několik menších částí. Pokud je menší, je doplněn nulovými vzorky na požadovanou velikost. Příkladem implementovaným v tomto programu je třída CFilterEqualizer, která vyžaduje buffery specifikované velikosti kvůli FFT.
5.2
Filtry vázané na grafické rozhraní
Některé z požadovaných efektů, které program poskytuje, není možné implementovat v kontextu zpracování streamu, ale je třeba kontext celého souboru poskytovaného třídou WaveReaderWriter. Typickým příkladem může být efekt Reverse. Tyto filtry, závislé na grafickém rozhraní, sdružuje třída DataProcessManger, která implementuje dané filtry s využitím třídy WaveReaderWriter, jejíž referenci obsahuje. Všechny její funkce jsou následně přístupné přes veřejné metody třídy ApplicationManager. Toto řešení je zvoleno kvůli způsobu přístupu k datům. Přístup k datům je pro všechny části aplikace zprostředkován třídou WaveReaderWriter, která data načítá do předaného bufferu. Tento přístup je nezávislý na implementaci samotného čtení. Rozhraní pro čtení dat je stejné, ať jsou data čtena přímo z disku, nebo jsou uložena v paměti. 52
Z uvedených důvodů nelze takové filtry implementovat jako součást knihovny nativních filtrů. Potřebné rozhraní by vyžadovalo předávání ukazatele na celá data. Tato data, i když jsou ve stávající implementaci v paměti uložena, nejsou přístupná ostatním částem programu přímo (z důvodu oddělení implementace čtení dat od ostatních částí programu). Díky tomu by rozhraní muselo tyto data načítat explicitně znovu. Taková alokace další paměti by byla značně neefektivní. Dalším možným řešením by mohla být implementace závislých filtrů v rámci knihovny wrapper tříd. Těmto filtrům by musela být předávána reference na třídu pro práci s daty WaveReaderWriter. Toto řešení by ovšem způsobilo závislost knihovny na implementaci grafického rozhraní. Posledním řešením by mohla být implementace těchto filtrů v rámci rozhraní aplikace, ve formě samostatných tříd. Těmto třídám by byla opět předána reference na WaveReaderWriter, tato reference by ovšem byla předávána pouze v rámci implementace vlastní aplikace, což by nezpůsobilo závislost ostatních filtrů.
5.3
Procesy
Efekty, které je možné na zvukovou stopu aplikovat, jsou rozděleny do dvou skupin, z nichž první tvoří takzvané Processes (procesy). Jde o skupinu filtrů, která pracuje přímo se zvukovými vzorky a mění pouze jejich amplitudu nebo je přesunuje. Nemění ovšem další zvukové charakteristiky jako je frekvence, časový posun apod. Implementace většiny koncových filtrů využívá rozhraní, které nabízí abstraktní třídy popsané v předchozí části. Toto využití pak značně zjednodušuje jejich implementaci. Convert Channels Jedná se o přesun hodnot vzorků mezi jednotlivými kanály s možností přimíchání původních hodnot. Tento filtr reprezentuje třída CFilterConvertChannels, která je synovskou třídou CInPlaceFilter. Implementace metod pro zpracování je díky rodičovské třídě přímočará. Třída FilterConvertChannels je odpovídající wrapper. Volume Třída CFilterVolume upravuje hlasitost vstupního signálu. Jde tedy o přenásobení jednotlivých vzorků hodnotou, která je parametrem filtru. Tato třída je
53
synovskou třídou CInPlaceFilter. FilterVolume představuje příslušný wrapper. Invert Aplikace filtru reprezentovaného třídou CFilterInvert neguje hodnoty vstupních vzorků, kde FilterInvert je její wrapper. Díky abstrakci, kterou poskytuje rodičovská třída CInPlaceFilter, je implementace opět přímočará. Reverse Tento filtr nemá reprezentaci mezi wrapper třídami, protože nevyužívá generování dialogu. Samotný filtr je implementován jako metoda třídy DataProcessManager. Insert Silence Třída FilterInsertSilence je pouze managed třídou bez ekvivalentu mezi unmanaged filtry. Definuje rozhraní pro generování formuláře. Vlastní implementace je obsažena ve třídě DataProcessManager a využívá služeb přístupu k celému souboru. Normalize Třída FilterNormalize je dalším případem managed třídy bez ekvivalentu mezi unmanaged filtry. Slouží pouze pro generování dialogu, vlastní filtr je implementován třídou DataProcessManager. Fade In, Fade Out Filtry Fade In a Fade Out nemají reprezentaci ani mezi managed filtry, protože nevyžadují generování dialogu. Oba filtry jsou implementovány jako součást třídy DataProcessManger. Reverse Samples Jako u Fade filtrů i tento nemá reprezentaci mezi wrapper třídami a využívá plně služeb přístupu k souboru, který poskytuje třída WaveReaderWriter. Vlastní filtr je opět implementován ve třídě DataProcessManager.
54
Mute Tento filtr nevyžaduje grafické prostředí. Jedná se o volání filtru Volume s nulovým parametrem zesílení.
5.4
Filtry
Druhou skupinu tvoří takzvané Filters (filtry). V této skupině jsou obsaženy komplexnější filtry upravující i některé další charakteristiky vstupního signálu, jako je frekvenční spektrum nebo časové zpoždění. Opět využívají rozhraní poskytované rodičovskými třídami. Distortion Distortion neboli zkreslení je implementováno ve třídě CFilterDistortion s rodičovskou třídou CInPlaceFilter a wrapperem FilterDistortion. Filtr funguje na principu přebuzení a následné komprese vstupního signálu, čímž se dosáhne požadovaného efektu. Implementace pokročilejších algoritmů pro zkreslení by byla příliš náročná. Echo Třída CFilterEcho je synovskou třídou CFeedbackStreamFilter. Implementace odpovídá popisu v kapitole 2: Digitální filtry a efekty. Díky rodičovské třídě je implementace přímočará. FilterEcho je odpovídající wrapper. Equalizer Třída CFilterEqualizer s rodičovskou třídou CBlockStreamFilter využívá pro změnu frekvenčního spektra FFT transformaci bloku signálu. Funkce pro FFT poskytuje knihovna KissFFT [5]. Poté, co je pomocí fourierovy transformace získáno frekvenční spektrum[1], je toto spektrum upraveno podle parametrů filtru a zpětnou transformací vznikne výstupní signál. Podobný postup používá například program Audacity[11]. Wrapper třídou k tomuto filtru je třída FilterEqualizer. Flanger Flanger je implementován podle popisu z kapitoly 2.4.4 třídou CFilterFlanger. Ta je synovskou třídou CFeedbackStreamFilter. Metody rodičovské třídy umožňují přímočarou implementaci tohoto filtru. Třída FilterFlanger je odpovídající wrapper. 55
5.5
Wrapper třídy filtrů
Protože jsou třídy filtrů naprogramovány pro Win32, je potřeba pro jejich volání z C# vytvořit wrapper třídy v managed C++, které umí pracovat jak s native, tak s managed referencemi a ukazateli. Tyto třídy obsahují ukazatel na instance odpovídajících filtrů. Vybrané metody a položky jsou přístupné pomocí veřejných metod a vlastností wrapper tříd.
5.5.1
Hierarchie
Hierarchie wrapper tříd nekopíruje hierarchii tříd pro filtry. Pouze definuje základní abstraktní rodičovskou třídu Filter, která implementuje některé univerzální metody pro práci s nativním kódem, jakou je například metoda pro zpracování samotných dat Process (ta obsahuje i samotnou konverzi z managed pole na standartní C++ pole). Dále definuje metody vlastnosti, pomocí kterých se následně nastavují či vracejí vnitřní proměnné jednotlivých filtrů. Ostatní synovské třídy již implementují pouze vlastnosti, které pracují se specifickými parametry vnitřního filtru. S tím souvisí například i metoda na ověření kompatibility filtru s formátem dat Connect.
5.5.2
Definice rozhraní pro generování dialogů
Druhou důležitou funkcí wrapper tříd, kromě umožnění volání metod native filtrů z C#, je definice rozhraní filtrů pro automatické generování formulářů. Každá specifická třída určuje klíčové parametry filtru, jejich jméno, rozsah apod. Na základě těchto informací je poté automaticky vygenerován formulář, umožňující svými ovládacími prvky přímo měnit vlastnosti odpovídajícího filtru. Přímé provázání ovládacích prvků s filtrem se uplatní hlavně při real-time náhledech efektů. Princip generování byl podrobně rozebrán v sekci o automatickém generování formulářů 4.9. Existuje jedna výjimka mezi potomky třídy Filter. Jedná se o abstraktní třídu ApplicationFilter. Potomci této třídy jsou implementováni, na rozdíl od ostatních wrapperů, v grafickém rozhraní a neobsahují instanci native filtru. To z toho důvodu, že je potřeba provádět některé procesy na celém souboru najednou. K tomu je potřeba přístup k metodám tříd, které manipulují se souborem přímo. Důvodem, proč je taková editace začleněna do hierarchie managed filtrů, je využití automatického generování dialogů i pro tyto filtry. A to i za cenu, že metoda wrapperu Process není volána. Typickým příkladem je třída FilterInsertSilence. 56
Základní zacházení s filtry je možné upravit i opačným způsobem. Tedy tak, že synovská třída nebude definovat žádné rozhraní a zakáže vytváření dialogu pro tuto třídu, což se hodí v případě, že sice nechceme generovat formulář, ale potřebujeme jednotné zacházení se všemi typy filtrů uvnitř grafického rozhraní. Typickým zástupcem je například třída FilterInvert.
5.6
Volání filtrů
Filtry jsou aplikovány grafickým rozhraním pomocí wrapper tříd voláním metody Process. Této metodě je předán buffer dat pro přehrávání (například při přehrávání náhledu nebo při permanentní aplikaci filtru). V metodě je managed reference na pole fixována a převedena na unmanaged ukazatel na klasické C++ pole. Takto získaný ukazatel na data je poté předán unmanaged třídě, jejíž referenci buffer obsahuje, ke zpracování. Data jsou zpracována abstraktními třídami a předána koncovým třídám v požadované podobě.
5.6.1
Příklad: Distortion
Obrázek 5.2 ukazuje vzájemná volání tříd při vytváření dialogu a následná volání při přehrávání náhledu filtru Distortion. 1, 2 V handleru události výběru volby Distortion z menu Filter je nejdříve získána reference na odpovídající dialog pomocí volání metody GetFilterGUI třídy ApplicationManager. V této metodě je volána stejnojmenná metoda pomocné třídy FilterFormManager, která vrátí referenci na holder třídu EffectInfo s odpovídajícím dialogem. 3, 4 Pokud objekt EffectInfo pro daný filtr neexistuje, je vytvořena instance příslušného filtru a zavolána metoda ApplicationManager.AddFilter s tímto filtrem v parametru volání. ApplicationManager vytvoří novou instanci přehrávacího bufferu a referenci na něj, společně s referencí na nově vytvořený filtr, předá třídě FilterFormManager. Tato třída uloží obě reference do EffectInfo objektu a ten přidá do vnitřního seznamu generovaných dialogů. Pokud generovaný dialog existuje, volání vrátí existující referenci. V opačném případě je po přidání vrácena reference na nový dialog. 5, 6 Poté, co je získána reference na odpovídající holder objekt dialogu, je zavolána metoda ProcessDialog. V této metodě je získána reference na nový 57
Obrázek 5.2: Schéma struktury volání při aplikaci filtru. dialog z holder třídy EffectInfo a dialog je zobrazen uživateli. 7 Po stisku volby pro přehrávání náhledu je, při obsluze události vnitřního bufferu dialogu OnDataPreprocessing, aplikován filtr Distortion. Aplikace se provede voláním metody Process na instanci wrapperu daného filtru. 8, 9 V metodě Process abstraktní třídy Filter je předaná reference na managed pole fixována a převedena na unmanaged ukazatel. Takto získaný ukazatel je předán ke zpracování unmanaged filtru, který je ve wrapperu reprezentován svou rodičovskou třídou CFilter. 10 Data jsou díky polymorfismu tříd filtrů předána metodě Process abstraktní třídy CInPlaceFilter. 11 CInPlaceFilter poté předává data koncové třídě CFilterDistortion ve volání metody ProcessMono nebo ProcessStereo. V těchto metodách je provedena samotná aplikace filtru na předaná data.
5.7
Rozšíření knihovny
Aplikace AEditor nabízí možnost poměrně jednoduchého rozšíření knihovny filtrů. Samotné zásuvné moduly aplikace ovšem nepodporuje. Jak bylo řečeno v části věnované hierarchii, základní třídy jsou navrženy tak, aby umožňovaly koncovým třídám soustředit se hlavně na algoritmus jako takový. Popis je doplněn příkladem implementace filtru Volume.
58
5.7.1
Implementace nativní třídy filtru
Pro vytvoření nového filtru je třeba, aby třída implementující daný filtr byla potomkem třídy CFilter, případně některé z rozšiřujících abstraktních tříd, které definují potřebné rozhraní. Pro příklad je nejprve uvedena definice třídy CFilterVolume. Definice obsahuje virtuální metodu pro zpracování jednotlivých vzorků ProcessMono. U metody ProcessStereo je využita předdefinovaná implementace, která volá mono metodu na oba vzorky. Další zajímavou částí je definice konstruktoru s parametrem typu CFeedback. Jedná se o callback třídu, jejíž metody simulují .NET události (volání je převedeno na událost ve wrapperu). Filtr má jeden parametr, kterým je míra zesílení vstupního signálu. namespace FilterUnmanaged { class UNMANAGED API CFilterVolume: public CInPlaceFilter { public: CFilterVolume(); CFilterVolume(CFeedback∗ feedback); void SetParams(double gain); private: double m Gain; /∗∗ ∗ Default implementation of Stereo method is used ∗ (double usage of ProcessMono on both channels) ∗/ virtual void ProcessMono( int16 &value); }; }
Následuje přímočará implementace konstruktorů. V těle konstruktoru jsou pouze inicializovány parametry filtru, ostatní inicializace je přenechána rodičovské třídě. CFilterVolume::CFilterVolume(): CInPlaceFilter(0) { m Gain = 0; } CFilterVolume::CFilterVolume(CFeedback∗ feedback): CInPlaceFilter(feedback) { m Gain = 0; }
59
Nakonec zbývá implementovat metodu pro změnu parametrů a metodu pro zpracování signálu. Implementace obou metod je z důvodu jednoduchosti filtru přímočará. Je zde použita pomocná metoda check overflow pro detekci přetečení hodnot, která je definována v souboru utils.h. void CFilterVolume::SetParams(double gain) { m Gain = gain; } void CFilterVolume::ProcessMono( int16 &value) { value = check overflow( floor(m Gain ∗ value)); }
5.7.2
Implementace wrapper třídy filtru
Dále je zapotřebí implementovat wrapper třídu pro tento filtr. Ta musí být potomkem třídy FilterManaged.Filter nebo některé synovské abstraktní třídy. Dále by měla zveřejňovat všechny požadované parametry ve formě veřejných vlastností. Vlastnosti, které chceme zpřístupnit pomocí automaticky generovaných formulářů, je třeba označit atributem třídy FxParameterAttribute s odpovídajícími hodnotami konstruktoru (viz část o generování formulářů 4.9). Třída neimplementuje metodu Process, která je již implementována v rodičovské třídě. #include ”Filter.h” #include ”../FilterUnmanaged/filter volume.h” using namespace System; namespace FilterManaged { [System::ComponentModel::Description(”Volume”)] public ref class FilterVolume: public Filter { public: FilterVolume(); FilterVolume(WaveFormat format); /∗∗ ∗ True, if the current file format is supported. ∗/ virtual bool Connect() override; virtual void Reset() override;
60
[FxParameter( ”Gain”, FxParameterAttribute::ParameterType::DECIBELL, 0, 20.0f, 0.05f )] property double Gain { double get() { return m Gain;} void set(double value) { m Gain = value; SetFilterParams(); } } protected: virtual void SetFilterParams() override; private: double m Gain; }; }
Z implementačních důvodů jsou základním rozhraním podporovány pouze dva typy vlastností, a to int a double. Pokud označíme, pro automatické generování, vlastnost jiného typu, bude při generování formuláře vyvolána specializovaná výjimka FxPropertyTypeException. Pro podporu generování dialogů pro jiné typy vlastností je třeba definovat novou třídu pro jejich generování, která bude synovskou třídou FxBasicForm. V této nové třídě je potom třeba předefinovat metodu CreateFxControls, která provádí samotné generování. Následuje příklad implementace důležitých metod, uvedených v definici třídy. Nejprve je uvedena implementace konstruktorů. V každém konstruktoru je inicializována vnitřní proměnná pro parametr zesílení a vytvořena instance nativního filtru typu CFilterVolume. Po vytvoření instance nativního filtru jsou nastaveny jeho parametry voláním příslušné funkce. V konstruktoru, kde je předáván formát souboru, je tento formát předán i do nativní třídy. #define INIT GAIN 1.0 using namespace FilterManaged; FilterVolume::FilterVolume(): Filter() { m Gain = INIT GAIN; m pFilter = new CFilterVolume(m pFeedback); ((CFilterVolume ∗) m pFilter)−>SetParams(m Gain); }
61
FilterVolume::FilterVolume(WaveFormat format): Filter(format) { m Gain = INIT GAIN; m pFilter = new CFilterVolume(m pFeedback); m pFilter−>SetFormat(format.GetUnmanagedFormat()); ((CFilterVolume ∗) m pFilter)−>SetParams(m Gain); }
Dále je uvedena implementace ostatních metod třídy FilterVolume. Metoda Connect využívá zděděné vlastnosti Format, která vrací formát souboru uložený v nativní třídě. Pokud není v nativní třídě formát specifikován, vrací inicializovanou instanci. using namespace FilterUnmanaged; void FilterVolume::SetFilterParams() { ((CFilterVolume∗)m pFilter)−>SetParams(m Gain); } bool FilterVolume::Connect() { WaveFormatˆ format = this−>Format; if (format−>BlockAlign == 2) { return true; } else { return false; } } void FilterVolume::Reset() { m Gain = INIT GAIN; }
5.7.3
Rozšíření grafického rozhraní
Nakonec zbývá vytvořit novou položku v menu a v handleru události OnClick získat (případně vyrobit) novou instanci třídy EffectInfo pro daný typ filtru. Pak stačí zavolat metodu ProcessDialog s odpovídajícími parametry, program zobrazí formulář a ošetří další uživatelské akce. Typická implementace handleru je uvedena v následujícím příkladu. 62
/∗ get the EffectInfo reference ∗/ EffectInfo info = m ApplicationManager.GetFilterGUI( typeof(FilterManaged.FilterVolume)); /∗ if doesn’t exist, add new one ∗/ if (info == null) { /∗ create appropriate filter ∗/ FilterManaged.Filter filter =
new FilterManaged.FilterVolume(
m ApplicationManager.ManagedWaveFormat); /∗ create new EffectInfo instance for current filter ∗/ info = m ApplicationManager.AddFilter(filter); } /∗ handle the filter dialog and optionally apply the filter ProcessDialog(info);
63
∗/
Kapitola 6 Srovnání Pro editaci digitálního audia prostřednictvím vizuální editace s možností aplikace filtrů existuje velké množství aplikací, ať už komerčních nebo open-source. Mezi známé komerční programy patří například Sound Forge[10] nebo Steinberg Wavelab[12]. Mezi známé open-source programy patří například Audacity[11]. Problematika implementovaná v programu AEditor se nejvíce blíží programu Audacity nebo Sound Forge. V této kapitole je uvedeno srovnání implementovaného programu AEditor a těchto profesionálních programů. Součástí srovnání je i návrh možných vylepšení.
6.1
Rozhraní
AEditor, stejně jako oba zmiňované programy, nabízí možnosti zobrazování zvukové stopy s možností přibližování. Hlavní rozdíl ovšem spočívá v kvalitě a rychlosti implementace. Zatímco program AEditor vykresluje stopu pouze v omezeném detailu, u zbylých dvou programů je stopa vykreslována mnohem detailněji s aplikací interpolace při vysokém zvětšení. Výkon při zobrazování je u aplikace AEditor nižší, protože při velkém oddálení výpočet pro vykreslení stopy prochází celý soubor (některé vzorky jsou pro zrychlení přeskakovány). Rychlost vykreslování by se dala zvýšit rozšířením třídy pro přístup k datům při vykreslování (DataStorage). Ta by při otevření spočítala zobrazované hodnoty pro určitý stupěň zvětšení, čímž by se počet procházených hodnot při velkém oddálení zmenšil. Audacity i Sound Forge aplikují pravděpodobně podobný způsob optimalizace vykreslování. Další společnou částí programů AEditor, SoundForge a Audacity je možnost přehrávání zobrazované stopy či její části. V tomto případě jsou možnosti všech programů víceméně rovnocené i co se týká přehrávání ve smyčce či sledování
64
kurzoru při přehrávání. Jedním z dalších společných prvků je možnost kopírování, vkládání a mazání označené části souboru. AEditor se od obou ostatních aplikací liší ve způsobu ukládání těchto změn. Zatímco AEditor ukládá všechny změny do paměti procesu, Audacity a Sound Forge je ukládají buď na disk, nebo si pamatují vnitřní seznam všech změn, který slouží pro případné vracení změn dopočítáním z původního souboru, nebo používají mapování vstupních a odkládacích souborů do paměti (jde o pozorování, které vyplývá z jejich chování). Z toho plyne také rozdíl v možnostech operací undo a redo, kdy si musí program AEditor ukládat části, které budou změněny, do paměti. Počet undo operací je potom omezen její velikostí. Naproti tomu obě další aplikace pracují pouze s vnitřní reprezentací změn, případně odloží změněné části na disk. Na rozdíl od obou srovnávaných programů, AEditor podporuje pouze WAVE formát souborů (konkrétně jeho 16bit verzi mono a stereo). Programy Audacity i Sound Forge podporují velké množství ostatních formátů, včetně komprimovaných, jako jsou například mp3, a umožňují měnit jejich parametry, nebo je převádět na jiné podporované formáty. Případně nabízí možnost importování MIDI apod.
6.2
Filtry a výkon
Stejně jako Sound Forge nebo Audacity, i AEditor podporuje různé typy filtrů, jako jsou základní volume, normalize, fade in apod. Dále AEditor poskytuje několik pokročilejších filtrů jako je echo, flanger nebo equalizer. Sound Forge a Audacity obsahují větší množsví filtrů. Sound Forge kromě opravdu velkého množství filtrů obsahuje například i podporu pro DirectX pluginy. Srovnání rychlosti jednotlivých programů je znázorněno na obrázku 6.1. Programy byly srovnávány podle času běhu složitějšího filtru (Equalizer), jednoduššího filtru (Volume) a přímé práce se vzorky (Fade Out). V naměřených časech se projevilo snížení efektivity, z důvodu zaměření programu na algoritmickou část (předávání dat v hierarchii filtrů), a pomalejší rychlost managed kódu běžícího na platformě .NET.
6.3
Shrnutí
Oba programy Audacity i Sound Forge nabízí větší množství funkcí, filtrů, podporovaných formátů a větší výkon, než srovnávaný AEditor. Odpovídající srovna65
Obrázek 6.1: Srovnání vykonosti programů. telné výsledky ovšem převyšují možnosti dané rozsahem bakalářské práce. Naopak možnosti zobrazování stopy, její přehrávání a náhledy filtrů v reálném čase jsou srovnatelné. Program AEditor se soustředí hlavně na demonstraci práce s digitálním zvukem. Implementuje několik pokročilejších filtrů a definuje rozhraní pro případná rozšíření. Celkový cíl programu je přiblížit se těmto profesionálním programům jak funkčně, tak rozhraním.
66
Závěr Úkolem bakalářské práce bylo shrnout základní principy a postupy při zpracování digitálního zvuku na počítači a implementovat některé z nich v programu pro editaci audia. V teoretické části jsou shrnuty postupy při převodu a ukládání digitálního audia, digitální filtry a popis programu AEditor, jehož implementace byla předmětem praktické části této práce. Teoretická část popisuje základy vzorkování zvuku a nejčastěji používaný zvukový formát pro ukládání digitálního zvuku WAVE. Je zde vysvětleno základní dělení a terminologie používané v literatuře o digitálních filtrech. Teoretická část práce obsahuje i stručný popis principů některých digitálních filtrů, používaných v programech pro zpracování audia, z nichž některé jsou potom implementovány v programu. Praktickou část tvoří program AEditor pro editaci audia. Umožňuje nejen aplikaci zvukových filtrů a efektů, ale i přehrávání a zobrazování editované stopy a také funkce kopírování, vkládání či mazání. Tyto další funkce jsou běžně k dispozici u programů s podobným zaměřením. Program AEditor je tedy komplexní nástroj pro editaci zvuku. AEditor implementuje některé základní filtry pro práci se zvukem a některé pokročilejší filtry popsané v teoretické části práce. Cílem programu není implementovat všechny filtry z teoretické části, ale ukázat možné způsoby zpracování digitálního zvuku a možné způsoby implementace digitálních filtrů. Program také nabízí možnost snadného rozšíření o další filtry. K tomuto účelu obsahuje hierarchii abstraktních tříd, které zajišťují manipulaci s daty, a tím umožňují koncovým třídám filtrů soustředit se hlavně na algoritmickou část. Pro snadné rozšíření programu o další digitální filtry a jejich oddělení od grafického rozhraní obsahuje program AEditor systém automatického generování dialogů pro konfiguraci těchto filtrů. K tomu je využit mechanismus Reflection platformy .NET. Důležitou částí programu je přehrávač editovaných souborů. Přehrávání je prováděno streamovaným způsobem, což umožňuje jednak šetřit paměť procesu,
67
a jednak dovoluje aplikaci vybraného filtru za běhu, bez nutnosti měnit zdrojová data. Díky tomu je možné přehrát náhled vybraného filtru před jeho aplikací a sledovat projevy změn nastavení filtru v reálném čase. Program může být rozšířen o další digitální filtry na základě poskytnutého rozhraní. Dalším rozšířením by mohla být lepší správa zvukových dat a jejich změn. Například ukládání změny do vnitřní struktury a případné vracení těchto změn provádět dopočítáním z původního souboru pomocí této struktury. Další možností by bylo mapování zdrojových i pomocných souborů do paměti. Pro zrychlení zobrazování stopy by bylo možné předpočítat si zobrazované hodnoty vzorků pro dané zvětšení dopředu a použít tyto spočtené hodnoty při velkém oddálení souboru. Možným rozšířením by mohlo být také doplnění podpory pro další zvukové formáty. Program AEditor nenabízí všechny funkce komerčních zvukových editorů, ale ilustruje možnou implementaci takového programu.
68
Reference [1] Zolzer U.: DAFX - Digital Audio Effects, John Wiley & Sons, 2002. [2] Rocchesso D.: Introduction to Sound Processing, GNU licence, http://www.scienze.univr.it/∼rocchess. [3] The Sonic Spot: WAVE file format, http://www.sonicspot.com/guide/wavefiles.html. [4] Smith J.O.: Introduction to digital filters, http://ccrma.stanford.edu/∼jos/filters/filters.html. [5] Mark Borgerding: KissFFT knihovna, http://sourceforge.net/projects/kissfft/. [6] CodeProject: Audio and Video, http://www.codeproject.com/KB/audio-video/. [7] Harmony Central: Effects Explained, http://www.harmony-central.com/Effects/effects-explained.html. [8] Harmony Central: Audio Programming, http://www.harmony-central.com/Computer/Programming/. [9] Wikipedia: Audio filter, http://en.wikipedia.org/wiki/Audio filter. [10] Sony: Sound Forge, v. 8.0b, http://www.sonycreativesoftware.com/soundforge. [11] Audacity, v. 1.2.6, GNU GPL, http://audacity.sourceforge.net/. [12] Steinberg: WaveLab, v. 6, http://www.steinberg.net/128 1.html.
69
Příloha K práci je přiloženo CD s digitální verzí práce. CD dále obsahuje zdrojové soubory vypracovaného programu, zkompilovanou verzi programu a vygenerovanou dokumentaci k projektu. Součástí přílohy jsou i zkušební vstupní soubory. • /bc - text bakalářské práce ve formátu pdf • /bin - zkompilovaná verze vypracovaného programu. Součástí jsou i instalační balíčky používaných knihoven. • /doc - vygenerovaná dokumentace k vypracovanému projektu – /aeditor - dokumentace ke gracifkému rozhraní aplikace – /filter - dokumentace knihovny wrapper tříd – /filter unmanaged - dokumentace nativní knihovny filtrů • /sample - ukázkové vstupní soubory • /src - zdrojové soubory vypracovaného programu – /aeditor - zdrojové soubory gracifkého rozhraní aplikace – /filter - zdrojové soubory knihovny wrapper tříd – /filter unmanaged - zdrojové soubory nativní knihovny filtrů
70