103
SVEU ˇ CILI ˇ STE U ZAGREBU FAKULTET ELEKTROTEHNIKE I RA ˇ CUNARSTVA DIPLOMSKI RAD br. 1776 DINAMI ˇ CKA OBRADA AUDIO SIGNALA Ante Grgat Zagreb, sijeˇ canj 2019.

bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

  • Upload
    others

  • View
    13

  • Download
    0

Embed Size (px)

Citation preview

Page 1: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

SVEUCILISTE U ZAGREBUFAKULTET ELEKTROTEHNIKE I RACUNARSTVA

DIPLOMSKI RAD br. 1776

DINAMICKA OBRADA AUDIO SIGNALA

Ante Grgat

Zagreb, sijecanj 2019.

Page 2: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala
Page 3: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Dinamicka obrada audio signala ii

Page 4: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Sadrzaj

Popis slika v

Popis tablica vi

Popis kratica vii

1 Uvod 1

2 Osnovni pojmovi u obradi audio signala 3

2.1 Uzorkovanje signala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2 Decibel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.3 Dinamicka obrada signala . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.3.1 Detekcija razine signala . . . . . . . . . . . . . . . . . . . . . . . . 7

2.3.2 Izracun pojacanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.3.3 Dinamicka kompresija razine . . . . . . . . . . . . . . . . . . . . . 12

2.3.4 Dinamicka ekspanzija razine . . . . . . . . . . . . . . . . . . . . . 15

2.3.5 Regulacija . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3 Metode 19

3.1 Graficko korisnicko sucelje . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.2 Cython wrapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.3 DSP algoritmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3.3.1 Topologija dinamickog procesora . . . . . . . . . . . . . . . . . . 30

3.3.2 Detekor razine signala . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.3.3 Izracun pojacanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

4 Rezultati 36

5 Zakljucak 44

Dinamicka obrada audio signala iii

Page 5: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Literatura 45

Sazetak 48

A Programski kod grafickog korisnickog sucelja - Python 49

B Programski kod detektora razine signala - C++ 68

C Programski kod dinamickog procesora - C++ 75

D Cython wrapper funkcije za klasu EnvelopeFollower 89

E Cython wrapper funkcije za klasu DynamicProcessor 92

Page 6: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Popis slika

2.1 Prikaz vremenski kontinuiranog signala njegovim uzorcima u diskret-

noj domeni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.2 Karakteristike pojacanja uredaja za regulaciju dinamickog raspona . . . 6

2.3 Blok dijagram detektora razine signala . . . . . . . . . . . . . . . . . . . 7

2.4 Poluvalni detektor razine signala (detektira vrsnu vrijednost signala) . . 10

2.5 Strujno-naponska karakteristika idealne diode . . . . . . . . . . . . . . . 10

2.6 Feedback topologija dinamickog regulatora razine . . . . . . . . . . . . . 11

2.7 Feedforward topologija dinamickog regulatora razine . . . . . . . . . . . . 12

2.8 Karakteristika pojacanja kompresora . . . . . . . . . . . . . . . . . . . . . 13

2.9 Karakteristika pojacanja limitera . . . . . . . . . . . . . . . . . . . . . . . 14

2.10 Karakteristika pojacanja silaznog ekspandera . . . . . . . . . . . . . . . . 15

2.11 Karakteristika pojacanja uzlaznog ekspandera . . . . . . . . . . . . . . . 16

2.12 Karakteristika pojacanja noise gate uredaja . . . . . . . . . . . . . . . . . . 17

2.13 Karakteristike staticke kompresije . . . . . . . . . . . . . . . . . . . . . . 18

3.1 Dijagram toka programa za dinamicku obradu audio signala . . . . . . 19

3.2 GUI sustava za dinamicku obradu audio signala . . . . . . . . . . . . . . 21

3.3 Algoritam za dinamicku obradu podataka . . . . . . . . . . . . . . . . . 26

3.4 Feedforward topologija programski izvedenog dinamickog procesora . . 30

4.1 Dinamicka obrada signala - kompresor (guitar noise.wav datoteka) . . . 36

4.2 Dinamicka obrada signala - limiter (guitar noise.wav datoteka) . . . . . . 37

4.3 Dinamicka obrada signala - silazni ekspander (guitar noise.wav datoteka) 38

4.4 Dinamicka obrada signala - noise gate (guitar noise.wav datoteka) . . . . 39

4.5 Dinamicka obrada signala - kompresor (guitar clean.wav datoteka) . . . 40

4.6 Dinamicka obrada signala - limiter (guitar clean.wav datoteka) . . . . . . 41

4.7 Dinamicka obrada signala - silazni ekspander (guitar clean.wav datoteka) 42

4.8 Dinamicka obrada signala - noise gate (guitar clean.wav datoteka) . . . . 43

Dinamicka obrada audio signala v

Page 7: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Popis tablica

3.1 Parametri dinamicke obrade audio signala . . . . . . . . . . . . . . . . . 22

3.2 Opis varijabli i metoda klase Ui MainWindow . . . . . . . . . . . . . . . . 23

3.3 Opis varijabli i metoda klase PlotWidget . . . . . . . . . . . . . . . . . . . 24

3.4 Opis varijabli i metoda klase DynamicProcessor . . . . . . . . . . . . . . . 27

3.5 Opis varijabli i metoda klase EnvelopeFollower . . . . . . . . . . . . . . . . 30

Dinamicka obrada audio signala vi

Page 8: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Popis kratica

B Bel - jedinica kojom se izrazava logaritamski odnos dvaju istovrsnih velicina

dB Decibel - 1/10 Bela

DCA Digitalno upravljano pojacalo (engl. Digitally Controlled Amplifier)

DRC Dinamicka kompresija razine (engl. Dynamic Range Compression)

DSP Digitalna obrada signala (engl. Digital Signal Processing)

GUI Graficko korisnicko sucelje (engl. Graphical User Interface)

IIR Rekurzivni filtar (engl. Infinite Impulse Response)

I/O ulazno/izlazna jedinica (engl. Input/Output)

MS Kvadrat srednje vrijednosti signala(engl. Mean Square)

RMS Efektivna vrijednost signala (engl. Root Mean Square)

VCA Naponski kontrolirano pojacalo (engl. Voltage Controlled Amplifier)

wav engl. Waveform Audio File Format

τa Vrijeme reakcije (engl. Attack Time)

τr Vrijeme otpustanja (engl. Release Time)

Dinamicka obrada audio signala vii

Page 9: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 1. Uvod

POGLAVLJE 1

Uvod

U danasnje doba postoje razlicite situacije u kojima je razina odredenog signala preve-

lika ili premala za prijenos preko medija ili pohranjivanje tog istog signala na odredeni

medij. Govorni signali, primjerice, cesto imaju komponente koje su pretihe za prijenos

preko telefonske linije. Pri izvodenju glazbe uzivo, ”meksi” prijelazi cesto su pretihi

da bi se culi iznad buke publike ili ventilacijskog sustava. Pri slusanju glazbe u autu

ili zrakoplovu, buka motora moze potpuno maskirati ”mekse” dionice odredenog

signala. U ovakvim situacijama moze se koristiti digitalna obrada signala u stvarnom

vremenu upotrebom dinamickih procesora kako bi se smanjila razina odredenog sig-

nala i tako ucinila sve dijelove ili vecinu dijelova signala prikladnim za prijenos [1].

Dinamicki procesori se dizajniraju tako da se automatski kontrolira amplituda ili

pojacanje audio signala i dijele se na dvije vrste: kompresori i ekspanderi. Di-

namicka kompresija razine, uvedena tridesetih godina proslog stoljeca, koristila se

za pojacavanje razine tihih dijelova govornih signala preko telefonske linije. Otada,

razvile su se razlicite inacice topologija kompresora koje se u sirokoj primjeni koriste i

danas. S tehnickog stajalista, kompresori i ekspanderi mijenjaju pojacanje signala na-

kon sto razina tog istog signala prijede neku predodredenu razinu praga. Kompresor

smanjuje pojacanje signala nakon sto njegova razina prijede zadanu razinu praga, dok

ekspander povecava pojacanje signala nakon sto razina signala prijede zadanu razinu

praga. Medutim, pravi ekspanderi su rijetki s obzirom na to da unose nestabilnosti i

distorzije. Ono sto se danas naziva ekspanderom je ustvari silazni ekspander. Silazni

ekspander smanjuje pojacanje signala nakon sto njegova razina padne ispod predefi-

niranog praga [2].

U ovom radu opisan je rad dinamickih procesora, te koristenjem Python [3] i C++ [4]

programskih jezika razvijen je program za dinamicku obradu audio signala u stvar-

Dinamicka obrada audio signala 1

Page 10: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 1. Uvod

nom vremenu. Program omogucuje citanje 2-kanalne, 16-bitne wav (engl. Waveform

Audio File Format - wav) datoteke, te njenu obradu i reprodukciju u stvarnom vremenu.

Korisnickim suceljem upravlja se svim parametrima dinamicke kompresije/ekspan-

zije razine te je ostvaren prikaz audio signala prije i poslije dinamicke obrade audio

signala.

Prilog A sadrzi programski kod pisan u Python programskom jeziku. U Pythonu je

razvijen front-end dio programa, odnosno stvaranje grafickog korisnickog sucelja te

povezivanje parametara korisnickog sucelja s back-end dijelom programa, tj. dijelom

programa zaduzenim za dinamicku obradu signala.

Prilozi B i C sadrze programski kod pisan u C++ programskom jeziku. U C++-u

je razvijen back-end dio programa, odnosno, funkcije za dinamicku obradu signala u

stvarnom vremenu. Prilog B sadrzi funkcije za detekciju razine signala, dok su u Pri-

logu C opisane funkcije dinamickog procesora.

Sucelje koje povezuje Python i C++ programske jezike je Cython . Cython je staticki

kompajler koji omogucuje pozivanje C ili C++ funkcija iz Python programskog jezika

[5]. Cython wrapper funkcije za detekciju razine signala prikazane su u Prilogu D, dok

su u Prilogu E prikazane Cython wrapper funkcije dinamickog procesora.

Dinamicka obrada audio signala 2

Page 11: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala

POGLAVLJE 2

Osnovni pojmovi u obradi audio

signala

2.1 Uzorkovanje signala

Pod odredenim uvjetima, kontinuirani vremenski signal moze se prikazati i rekons-

truirati ako su poznati njegovi uzorci (engl. Sample) u tocno odredenim ekvidistantnim

trenutcima u vremenu. Navedeno svojstvo naziva se teorem uzorkovanja (engl. Sam-

pling Theorem) [6]. Obrada vremenskih diskretnih signala je fleksibilnija, jednostavnija

i jeftinija od obrade vremenskih kontinuiranih signala sto je posljedica drasticnog ra-

zvoja digitalnih tehnologija posljednjih nekoliko desetljeca [7].

Ako je signal ogranicen u frekvenciji, odnosno, Fourierova transformacija signala jed-

naka je nuli izvan odredenog pojasa frekvencija i ako su uzorci uzeti dovoljno blizu

u odnosu na najvecu frekvenciju prisutnu u signalu, tada uzorci jednoznacno opisuju

signal i moguca je rekonstrukcija takvog signala iz njegovih uzoraka. Jednadzbe (2.1)

- (2.4) opisuju uzorkovanje vremenski kontinuiranog signala kako je prikazano Slikom

2.1 [7]:

xp(t) = x(t)p(t) (2.1)

gdje je

p(t) =n=+∞

∑n=−∞

δ(t− nT) . (2.2)

Mnozenje signala x(t) s impulsom uzorkuje taj signal na mjestu gdje se impuls nalazi.

Dinamicka obrada audio signala 3

Page 12: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.1. Uzorkovanje signala

x(t)δ(t− t0) = x(t0)δ(t− t0) (2.3)

Primjenom jednadzbe (2.3) u jednadzbu (2.1) slijedi da je signal x(t) jednak slijedu

impulsa cije su amplitude proporcionalne amplitudama signala x(t) na mjestu uzor-

kovanja tog istog signala:

xp(t) =n=+∞

∑n=−∞

x(nT)δ(t− nT) . (2.4)

Slika 2.1: Prikaz vremenski kontinuiranog signala njegovim uzorcima u diskretnoj domeni

Signal je moguce potpuno rekonstruirati iz njegovih uzoraka ako je frekvencija uzor-

kovanja najmanje dva puta veca od najvise frekvencije signala (Nyquistov teorem

uzorkovanja) [6]. Stoga, najcesce koristena frekvencija uzorkovanja audio signala je

44100 Hz sto je dva puta vise od najvece frekvencije koje ljudsko uho moze percipirati

(20000 Hz) [8].

Dinamicka obrada audio signala 4

Page 13: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.2. Decibel

2.2 Decibel

Vazna mjerna jedinica kod obrade audio signala koja sluzi za prikaz logaritamskog

odnosa dvaju velicina je decibel (dB). Razlog koristenja decibela lezi u cinjenici da

dobro prikazuje odnos dvaju velicina velikog dinamickog raspona. Nadalje, s obzi-

rom na to da je osjetljivost ljudskog uha logaritamska, decibeli bolje prikazuju cujnost

nego apsolutne vrijednosti [8, 9].

Decibel je zapravo 1/10 Bela (jedinica nazvana po A.G. Bellu); Bel predstavlja loga-

ritamski odnos dvaju istovrsnih velicina koje su proporcionalne snazi ili energiji kao

sto je prikazano jednadzbom (2.5) [9].

Bel = log(P1

P0) . (2.5)

S obzirom na to da je decibel 1/10 Bela, iz jednadzbe (2.5) proizlazi:

dB = 10 log(P1

P0) . (2.6)

Decibeli se mogu koristiti kako bi se izrazio odnos napona [9]. S obzirom na to da

vrijedi:

P =U2

R(2.7)

primjenom jednadzbe (2.7) u jednadzbu (2.6) dobivamo:

dB = 10 logU2

1R1

U22

R2

. (2.8)

Uz pretpostavku da su impedancije na ulazu i izlazu sustava jednake (R1 = R2 = R),

jednadzba (2.8) poprima oblik:

dB = 10 log(U1

U2)2 = 20 log(

U1

U2) . (2.9)

Cesto se razine snage signala ili razine napona signala prikazuju u omjeru prema ne-

koj poznatoj referentnoj velicini, primjerice 1mW ili 1uV, pa tako razlikujemo velicine

dBm i dBu, cije su formule dane jednadzbama (2.10) i (2.11) [9].

dBm = 10 log(P

1 ∗ 10−3W); dBu = 20 log(

URMS

0.775VRMS) . (2.10)

Dinamicka obrada audio signala 5

Page 14: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

2.3 Dinamicka obrada signala

Dinamicki raspon odreden je razlikom najglasnijih i najtisih dionica signala, uz uvjet

malih izoblicenja i jedan je od najvaznijih parametara u audiotehnici. S obzirom na to

da su najtise dionice ogranicene razinom suma, dinamicki raspon predstavlja odnos

izmedu najglasnije dionice signala i razine suma [9, 10].

Svaki audio sustav ima ogranicen dinamicki raspon za reprodukciju audio signala.

Audio signali cesto sadrzavaju intervale niskih amplituda s kratkim periodima visokih

amplituda. Primjerice, glazba s tihim vokalom i kratkim intervalima perkusije. Takva

vrsta glazbe unosi probleme digitalnim audio sustavima s obzirom na to da je tehnicki

zahtjevno akomodirati cijeli dinamicki raspon tih audio signala [11]. Kao rjesenje

namecu se uredaji za dinamicku regulaciju razine. Za regulaciju dinamike koriste se

cetiri osnovna uredaja: kompresor, limiter, ekspander i noise gate (Slika 2.2) [10].

−45 −40 −35 −30 −25 −20 −15 −10 −5 0−45

−40

−35

−30

−25

−20

−15

−10

−5

0

xG(dB)

y G(d

B)

linearna karakteristikanoise gate

ekspanderlinearna karakteristika

kompresorlimiter

Slika 2.2: Karakteristike pojacanja uredaja za regulaciju dinamickog raspona

Dinamicka obrada audio signala 6

Page 15: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

Princip rada svih uredaja temelji se na tome da reguliraju pojacanje ulaznog signala

na osnovi njegove detektirane razine [10].

2.3.1 Detekcija razine signala

Stupanj regulacije pojacanja uredaja za upravljanje dinamickim rasponom signala

ovisi o procjeni razine ulaznog signala. Procjena razine koristan je nacin kako bi

se odredilo trenutno ponasanje ulaznog signala. Stoga, u svim uredajima za regu-

laciju dinamicke razine, izracun pojacanja u medusobnom je odnosu s detektiranom

razinom signala [12].

Detekcija razine signala moze se temeljiti na mjerenju vrsne (engl. Peak) vrijednosti,

mjerenju kvadrata srednje vrijednosti (engl. Mean Square - MS) ili mjerenju efektivne

vrijednosti (engl. Root Mean Square - RMS) signala [13].

Slika 2.3 prikazuje blok dijagram sustava za detekciju razine signala. Rad prikazanog

detektora razine signala temelji se na poluvalnom ispravljacu iza kojeg slijedi nisko-

propusni filtar ciji je ulaz skaliran prema vremenima reakcije i otpustanja, ovisno o

tome je li signal raste iznad ili ispod trenutne vrijednosti anvelope signala [2].

Vrsna vr.:|x|

RMS:√|x|2

∑ τa ili τr ∑

z−1

x(n) y(n)

Slika 2.3: Blok dijagram detektora razine signala

Blok dijagram sa Slike 2.3 predstavlja digitalni filtar s jednim polom cija je jednadzba

diferencija prikazana formulom (2.12):

y[n] = (y[n− 1]− x[n])α + x[n] (2.11)

y[n] = αy[n− 1] + (1− α)x[n] (2.12)

gdje y[n] oznacava izlaz iz sustava ili trenutnu vrijednost anvelope signala, x[n] oznacava

ulaz u sustav ili trenutnu estimaciju razine signala, a α oznacava koeficijent filtra koji

Dinamicka obrada audio signala 7

Page 16: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

moze biti τa ili τr ovisno o tome je li trenutna razina signala veca od razine anvelope.

Iz jednadzbe (2.13) vidljivo je da su radna svojstva detektora razine signala odredena

njegovom prijenosnom funkcijom na koju izravno utjecu parametri vremena reakcije

i otpustanja [14]. Vrijeme reakcije, τa, za analogne sustave definira se kao vrijeme

potrebno da se kondenzator napuni na 63,2% vrijednosti svog punog kapaciteta (ili

priblizno 4dB vrijednosti signala). Za digitalne sustave, vrijeme reakcije definira se

kao vrijeme potrebno da signal bude unutar 99% svoje pune vrijednosti. Vrijeme

otpustanja, τr, za analogne sustave definira se kao vrijeme potrebno da se kondenza-

tor isprazni na 36,8% vrijednosti svog punog kapaciteta; dok se za digitalne sustave

vrijeme otpustanja definira kao vrijeme potrebno da signal bude unutar 1% svoje pune

vrijednosti [2, 14].

Odziv filtra sa Slike 2.3 na step signal je [13]:

y[n] = 1− αn; za x[n] = 1; n ≥ 1 . (2.13)

Vremenska konstanta τ definira se kao vrijeme potrebno da sustav dosegne 1− 1/e

svoje pune vrijednosti, odnosno

y[τ fs] = 1− 1/e (2.14)

gdje fs oznacava frekvenciju uzorkovanja signala. Za digitalne sustave vrijedi:

0.9 = 1− ατ fs (2.15)

iz cega proizlazi da je:

α = exp(ln(0.1)

τ fs) . (2.16)

Slicno se dobije i izraz koji vrijedi za analogne sustave:

α = exp(ln(0.368)

τ fs) . (2.17)

Odnosno, iz jednadzbi (2.16) i (2.17) proizlazi:

τa = exp(TC

reakcijaMs ∗ fs ∗ 0.001) (2.18)

Dinamicka obrada audio signala 8

Page 17: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

τr = exp(TC

otpustanjeMs ∗ fs ∗ 0.001) (2.19)

gdje su TCanalog = ln(0.368) i TCdigital = ln(0.01) [2].

Detekcija efektivne razine signala

Efektivna vrijednost signala moze se izracunati po jednadzbi (2.20) [13]:

y2[n] =1M

M/2−1

∑m=−M/2

x2[n−m] (2.20)

Efektivna vrijednost signala odgovara ljudskoj percepciji glasnoce, a korisna je kada

je potrebna izgladena vrijednost prosjeka nekog signala. Medutim, RMS detektor

nije adekvatan za primjenu u sustavima s dinamickom obradom signala u stvarnom

vremenu s obzirom da unosi kasnjenje od M/2 uzoraka. Stoga se za primjene u

stvarnom vremenu koristi niskopropusni IIR (engl. Infinite Impulse Response - IIR) filtar

prvog reda kako je prikazano Slikom 2.3. Jednadzba diferencija (2.12) tada poprima

oblik [13]:

y2[n] = αy2[n− 1] + (1− α)x2[n] (2.21)

odnosno,

y2[n] =

τay2[n− 1] + (1− τa)x2[n]; x[n] > y[n− 1]

τry2[n− 1] + (1− τr)x2[n]; x[n] ≤ y[n− 1](2.22)

Dinamicka obrada audio signala 9

Page 18: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

Detekcija vrsne vrijednosti signala

Rad digitalnih detektora razine signala temelji se na radu njihovih analognih dvojnika

[2]. Slika 2.3 prikazuje analogni poluvalni detektor vrsne vrijednosti signala.

Uul

D1Rreakcije

C1 Rotpustanja

Uizl

Slika 2.4: Poluvalni detektor razine signala (detektira vrsnu vrijednost signala)

Sklop sa Slike 2.4 sastoji se od diode, kondenzatora i dva potenciometra. Uz iz-

mjenicni napon na ulazu pozitivne poluperiode (Uul > 0) dioda (D1) je propusno po-

larizirana i kondenzator (C1) se puni preko potenciometra Rreakcije. Rreakcije odreduje

brzinu kojom ce se kondezator puniti. U slucaju negativne poluperiode signala na

ulazu (Uul < 0), dioda (D1) je zaporno polarizirana i kondenzator (C1) se izbija preko

potenciometra Rotpustanja spojenog na masu. Izlazni napon (Uizl) prati pozitivnu po-

luperiodu ulaznog napona ovisno o RC spoju.

Uz pretpostavku da je dioda idealna, cija je strujno-naponska karakteristika prikazana

Slikom 2.5, odnosno da je otpor idealne diode jednak nuli (Rdioda = 0) kada je ona

propusno polarizirana ili da u slucaju zaporne polarizacije dioda ima beskonacno ve-

lik otpor (Rdioda = ∞); jednadzba diferencija (2.12) za digitalne sustave tada poprima

oblik [13, 15]:

y[n] =

τay[n− 1] + (1− τa)x[n]; x[n] > y[n− 1]

τry[n− 1] + (1− τr)x[n]; x[n] ≤ y[n− 1](2.23)

u(t)

i(t)

Slika 2.5: Strujno-naponska karakteristika idealne diode

Dinamicka obrada audio signala 10

Page 19: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

2.3.2 Izracun pojacanja

Dvije su moguce topologije kod izvedbi sustava za regulaciju dinamicke razine sig-

nala i to: feedback topologija i feedforward topologija. U feedback topologiji (Slika 2.6),

ulaz u bocni lanac je izlaz iz sustava y[n] nad kojim VCA sklop primjeni odgovarajuce

pojacanje. Feedback topologija koristila se u ranim limiterima, a prednost ovakve topo-

logije lezi u cinjenici da povratna veza moze ispraviti moguce pogreske pri izracunu

kontrolnog napona [13].

VCA

x[n] y[n]

Izracun

pojacanja

Detektor

razinez−1

c[n]G[n]

Slika 2.6: Feedback topologija dinamickog regulatora razine

Jednadzba diferencija za sustav sa Slike 2.6 poprima oblik:

y[n] = x[n] ∗ G[n]; G[n] = f (c[n]) (2.24)

gdje je kontrolni napon dan izrazom:

cdB[n] = (1− ρ)(ydB[n− 1]− T); xdB[n] > T (2.25)

gdje ρ oznacava omjer kompresije/ekspanzije, a T granicnu razinu u decibelima.

Medutim, feedback topologijom nije moguce projektirati sustav s funkcijom za gledanje

unaprijed (engl. Look-ahead) stanje signala. Nadalje, uporabom feedback topologije nije

moguce projektirati ni idealni limiter, ciji je omjer kompresije ∞ : 1 s obzirom na to da

bi u tom slucaju za izracun kontrolnog napona bilo potrebno beskonacno negativno

pojacanje [13].

Kod feedforward topologije, ulaz u bocni lanac je ulazni signal x[n] (Slika 2.7) [13]. De-

tektor razine generira kontrolni signal c[n] koji upravlja pojacanjem G[n] VCA sklopa.

Ovisno o tipu dinamickog regulatora razine, kontrolni signal moze biti: trenutna

vrsna vrijednost signala, srednja kvadratna vrijednost ili efektivna vrijednost signala

[16].

Dinamicka obrada audio signala 11

Page 20: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

VCA

x[n]

Detektor

razine

Izracun

pojacanja

c[n]G[n]

y[n]

Slika 2.7: Feedforward topologija dinamickog regulatora razine

Jednadzba diferencija za sustav sa Slike 2.7 glasi [16]:

y[n] = x[n] ∗ G[n] (2.26)

Izlaz iz sklopa za izracun pojacanja G[n] je nelinearna funkcija kontrolnog signala

c[n], odnosno:

G[n] = f (c[n]) . (2.27)

Za kompresor, funkcija pojacanja jednaka je:

f (c) =

(c/c0)ρ−1; c ≥ c0

1; c < c0

(2.28)

gdje je c0 vrijednost predefinirane granicne razine i vrijedi da je ρ < 1. Za ekspander,

vrijedi da je ρ > 1, a funkcija pojacanja jednaka je:

f (c) =

1; c ≥ c0

(c/c0)ρ−1; c ≤ c0

(2.29)

Jednadzba diferencija za kontrolni signal c[n] glasi [16]:

c[n] = λc[n− 1] + (1− λ)|x[n]| (2.30)

sto je ekvivalentno jednadzbi (2.12).

2.3.3 Dinamicka kompresija razine

Dinamicka kompresija razine (engl. Dynamic Range Compression - DRC) je proces re-

dukcije dinamickog raspona audio signala [13]. Kompresori se obicno sastoje od

Dinamicka obrada audio signala 12

Page 21: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

kontrolnog uredaja koji je funkcija ulaznog signala i uredaja za primjenu izracunatog

pojacanja. Kompresor je moguce izvesti u dvije topologije i to: feedforward i feedback

topologiji.

Sustav sa Slike 2.7 nadgleda razinu ulaznog signala u sklop i kada njegova razina

poraste iznad predefinirane granicne razine (engl. Threshold), pojacanje naponski kon-

troliranog pojacala (engl. Voltage Controlled Amplifier - VCA) se smanji u ovisnosti

o omjeru kompresije, te razlici detektirane razine signala i predefinirane granicne

razine. Razina preslikavanja dinamickog raspona signala odredena je parametrima

kompresora (Slika 2.8).

−45 −40 −35 −30 −25 −20 −15 −10 −5 0−45

−40

−35

−30

−25

−20

−15

−10

−5

0

xG(dB)

y G(d

B)

linearna karakteristikakompresija 1:1kompresija 5:1

kompresija 10:1granicna razina

Slika 2.8: Karakteristika pojacanja kompresora

Kompresija se moze namjestiti u nekoliko razina, uz dvije ili vise granicnih razina.

Ispod prve granicne razine izlazni signal prati ulazni, odnosno omjer kompresije iz-

nosi 1 : 1. Ako ulazni signal prijede 1. granicnu razinu, kompresor ce uzrokovati

promjenu izlaznog signala u omjeru 5 : 1. Ako signal prijede 2. granicnu razinu,

Dinamicka obrada audio signala 13

Page 22: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

kompresor ce uzrokovati promjenu signala u omjeru 10 : 1. Na taj se nacin dinamika

izlaznog signala smanjuje s porastom ulaznog signala u odnosu na linearnu karakte-

ristiku [10].

Osim za ogranicavanje dinamike signala, kompresori se cesto koriste i za poboljsanje

kvalitete reprodukcije s obzirom na to da se odabirom granicnih razina i omjera kom-

presije moze dosta utjecati na kvalitetu sviranja [10].

Limiter

Limiter je krajnji oblik kompresora koji sprijecava daljnji porast signala nakon sto on

dosegne predefiniranu granicnu razinu [10, 16]. Moguce ga je izvesti u feedback i feed-

forward topologiji. U feedback topologiji, rad limitera nije idealan s obzirom na to da

bi u tom slucaju bilo potrebno beskonacno negativno pojacanje [13]. Karakteristika

pojacanja dana je Slikom 2.9. Ako signal poraste iznad granicne razine (-20dB), kom-

presor limitira signal s omjerom kompresije ∞ : 1, odnosno, izlazni signal ne raste s

promjenom ulaznog signala nego ostaje konstantan.

−45 −40 −35 −30 −25 −20 −15 −10 −5 0−45

−40

−35

−30

−25

−20

−15

−10

−5

0

xG(dB)

y G(d

B)

linearna karakteristikalimiter (∞ : 1)

granicna razina

Slika 2.9: Karakteristika pojacanja limitera

Dinamicka obrada audio signala 14

Page 23: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

Limiteri se koriste u elektroakusticnom lancu kako bi se sprijecila distorzija ili rezanje

signala.

2.3.4 Dinamicka ekspanzija razine

Ekspander, za razliku od kompresora, povecava razinu signala nakon sto taj isti

prijede razinu predefiniranog praga (engl. Upward Expander). Medutim, pravi eks-

panderi su rijetki s obzirom na to da unose nestabilnosti i distorzije. Ono sto se

danas naziva ekspanderom je zapravo silazni ekspander (engl. Downward Ekspan-

der). Silazni ekspander smanjuje razinu signala nakon sto ona padne ispod vrijednosti

praga [2]. Stoga, tihim dionicama signala dodatno se smanjuje amplituda sto rezultira

povecanjem dinamickog raspona signala. Karakteristike pojacanja silaznog i uzlaznog

ekspandera dane su Slikama 2.10 i 2.11.

−45 −40 −35 −30 −25 −20 −15 −10 −5 0−45

−40

−35

−30

−25

−20

−15

−10

−5

0

xG(dB)

y G(d

B)

liearna karakteristikaekspanzija 1:5

granicna razina

Slika 2.10: Karakteristika pojacanja silaznog ekspandera

Dinamicka obrada audio signala 15

Page 24: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

−45 −40 −35 −30 −25 −20 −15 −10 −5 0−45

−40

−35

−30

−25

−20

−15

−10

−5

0

xG(dB)

y G(d

B)

linearna karakteristikaekspanzija 1:5ekspanzija 1:1

granicna razina

Slika 2.11: Karakteristika pojacanja uzlaznog ekspandera

Noise gate

Noise gate je krajnji oblik ekspandera koji beskonacno atenuira signale male razine

i stoga se koristi kako bi se uklonio pozadinski sum [10, 16]. Moguce ga je izvesti

u feedforward i feedback topologiji. Karakteristika pojacanja noise gate uredaja dana je

Slikom 2.12. Nakon sto trenutna vrijednost signala padne ispod predefinirane razine

praga, pojacanje noise gate uredaja padne na nulu.

Dinamicka obrada audio signala 16

Page 25: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

−45 −40 −35 −30 −25 −20 −15 −10 −5 0−45

−40

−35

−30

−25

−20

−15

−10

−5

0

xG(dB)

y G(d

B)

linearna karakteristikanoise gate (1:∞)granicna razina

Slika 2.12: Karakteristika pojacanja noise gate uredaja

2.3.5 Regulacija

Nacin na koji uredaji za dinamicku regulaciju razine reagiraju na ulazni signal znatno

utjece na kvalitetu reprodukcije, odnosno, stupanj i kvaliteta regulacije ovisni su o

parametrima dinamicke obrade signala [10] (Slika 2.13).

Prag ili granicna razina (engl. Threshold) definira razinu signala iznad koje nastupa

kompresija/ekspanzija. Omjer kompresije/ekspanzije (engl. Ratio) definira u kojem

razmjeru ce se razina signala povecati ili smanjiti u odnosu na ulazni signal. Vrijeme

reakcije (engl. Attack Time) i vrijeme otpustanja (engl. Release Time) signala su vre-

menske konstante koje odreduju koliko je vremena potrebno kompresoru da smanji

razinu signala ako je razina signala bila veca od razine praga. Izlaznim pojacanjem

(engl. Make-up Gain) povecava se razina signala nakon dinamicke obrade. Sirina ko-

ljena (engl. Knee Width) odreduje hoce li pregib karakteristike nakon praga biti strm

ili blag. Strma promjena razine signala naziva se hard knee, dok se blaga promjena ra-

Dinamicka obrada audio signala 17

Page 26: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 2. Osnovni pojmovi u obradi audio signala 2.3. Dinamicka obrada signala

zine signala naziva soft knee. Ako se zeli postici neocigledna promjena razine signala

koristi se blagi pregib koljena [13]. Uz omjer kompresora jednak ∞ : 1, kompresor

postaje limiter i razina izlaznog signala se ne mijenja bez obzira na promjene ulaznog

signala.

−45 −40 −35 −30 −25 −20 −15 −10 −5 0−45

−40

−35

−30

−25

−20

−15

−10

−5

0

xG(dB)

y G(d

B)

linearna karakteristikahard knee kompresija 5:1soft knee kompresija 5:1

limiter (∞:1)

Slika 2.13: Karakteristike staticke kompresije

Dinamicka obrada audio signala 18

Page 27: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode

POGLAVLJE 3

Metode

U prethodnom poglavlju opcenito je opisan nacin rada dinamickih regulatora razine.

Medutim, za razvoj algoritama za dinamicku obradu signala u stvarnom vremenu,

specificna svojstva se moraju uzeti u obzir i ta svojstva opisana su u ovom poglavlju.

Programske biblioteke te koristene metode takoder su objasnjene kao dio ovog po-

glavlja.

Programski jezici u kojima je razvijeno rjesenje su Python i C++. Isprva je cijelo rjesenje

zamisljeno u Python programskom jeziku. Medutim, pokazalo se kako su dinamicke

osobine navedenog programskog jezika neadekvatne za razvoj sustava s dinamickom

obradom signala u stvarnom vremenu. Stoga su algoritmi za digitalnu obradu sig-

nala (engl. Digital Signal Processing - DSP) razvijeni u C++ programskom jeziku, dok

su funkcije grafickog korisnickog sucelja razvijene u Pythonu. Kako bi se funkcije

digitalne obrade signala mogle pozivati iz Python programskog jezika, potrebno je

napisati odgovarajuce wrapper funkcije u Cythonu. Dakle, Cython je sucelje izmedu

C++ i Python programskih jezika; preciznije, Cython je ekstenzija C programskog je-

zika u Pythonu. Tijek izvodenja programa prikazan je Slikom 3.1.

Python

GUI

Cython

wrapper

C++

DSP algoritmi

Slika 3.1: Dijagram toka programa za dinamicku obradu audio signala

Dinamicka obrada audio signala 19

Page 28: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode

Glavni razlog koristenja Python programskog jezika lezi u velikom broju biblioteka

(engl. Library) za obradu i analizu podataka, te sirokoj programskoj zajednici. Nada-

lje, sirok spektar tutorijala cine Python dostupnim i relativno jednostavnim.

Programsko rjesenje realizirano je uporabom dretvi (engl. Thread). Dretve omogucuju

paralelno izvrsavanje naredbi na razini jednog procesa. Nadalje, sve dretve unu-

tar jednog procesa dijele zajednicku memoriju sto omogucava efikasnu komunikaciju

izmedu razlicitih dretvi [17]. Graficko korisnicko sucelje (engl. Graphical User Interface

- GUI) i dinamicka obrada audio signala odvijaju se u zasebnim dretvama kako akcije

dinamicke obrade audio signala ne bi blokirale promjene korisnickog sucelja. U na-

rednim potpoglavljima opisan je nacin implementacije te akcije specificne za pojedinu

dretvu.

Dinamicka obrada audio signala 20

Page 29: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.1. Graficko korisnicko sucelje

3.1 Graficko korisnicko sucelje

QT Creator programskim alatom (Slika 3.2) kreirano je graficko korisnicko sucelje za

aplikaciju dinamicke obrade audio signala. GUI se sastoji od trake izbornika (engl.

Menu Bar), trake s alatima, te trake za prikaz valnih oblika signala.

Slika 3.2: GUI sustava za dinamicku obradu audio signala

Traka izbornika omogucuje ucitavanje 2-kanalne, 16-bitne wav datoteke, pokretanje

ili prekidanje izvodenja dinamicke obrade signala, spremanje valnih oblika signala

prije i nakon dinamicke obrade za daljnju analizu, te izlaz iz aplikacije. Traka s ala-

tima omogucuje korisniku podesavanje parametara dinamicke obrade audio signala

u stvarnom vremenu. Opis parametara dinamicke obrade audio signala prikazani su

u Tablici 3.1. Traka za prikaz valnih oblika audio signala omogucuje prikaz signala

prije i poslije digitalne obrade.

Dinamicka obrada audio signala 21

Page 30: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.1. Graficko korisnicko sucelje

Tablica 3.1: Parametri dinamicke obrade audio signala

Parametar Jedinica Raspon Opis

Input Gain dB [-12,20] Ulazno pojacanje

Output Gain dB [0,20] Izlazno pojacanje

(engl. make-up

gain)

Threshold dB [-60,0] Prag detekcije sig-

nalaAttack Time ms [1,300] Vrijeme porasta u

milisekundamaDelay Line ms [0,300] Linija za kasnjenje

(look-ahead di-

namicki procesor)

Release Time ms [20,5000] Vrijeme pada u mi-

lisekundamaRatio \ [1,20] Razmjer propor-

cija kompresi-

je/ekspanzije

Knee Width dB [0,20] Sirina koljena

Time constant \ Analog

Digital

Vremenska kons-

tanta (poglavlje

3.3.1)Processor \ COMPRESSOR

LIMITER

EKSPANDER

GATE

Tip dinamickog

procesora

Detection Type \ DETECT PEAK

DETECT MS

DETECT RMS

Tip detekcije ra-

zine signala

Funkcija main ulazna je tocka svakog Python programa. Zadatak main funkcije u ovom

slucaju je kreirati klasu Ui MainWindow koja sluzi za prikaz i manipulaciju grafickim

korisnickim suceljem. Klasa Ui MainWindow instancira klasu PlotWidget koja azurira

valne oblike signala prije i nakon dinamicke obrade. Varijable i metode svojstvene

Dinamicka obrada audio signala 22

Page 31: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.1. Graficko korisnicko sucelje

navedenim klasama prikazane su Tablicama 3.2 i 3.3.

Tablica 3.2: Opis varijabli i metoda klase Ui MainWindow

Ui MainWindow

Privatne (member) varijable Opis

fileLoaded True - ako je wav datoteka ucitana

streamStart True - ako je zapoceta dinamicka obrada

signala

streamCompleted True ako je zavrsena dinamicka obrada

signala

dynamicProcessor Cython wrapper klasa

Privatne (member) metode Opis

init () Inicijalizacijska funkcija; postavlja pri-

vatne varijable u pocetne vrijednosti

setupUi(MainWindow) Postavlja izgled i velicinu GUI-a te po-

vezuje gumbe s odgovarajucim aktiva-

cijskim funkcijama

actionOpenFile() Ucitava wav datoteku za obradu

userInterfaceChanged() Azurira promjene korisnickog sucelja

callPlay(void) Ukoliko je wav datoteka ucitana, otvara

audio stream te zapocinje dinamicku

obradu audio signala

closeFile() Zatvara ucitanu wav datoteku

exitApp() Zatvara program

closeStream() Zatvara audio stream

audioCallback() Poziva funkcije za dinamicku obradu

signala

Dinamicka obrada audio signala 23

Page 32: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.1. Graficko korisnicko sucelje

Tablica 3.3: Opis varijabli i metoda klase PlotWidget

PlotWidget

Privatne (member) varijable Opis

signalWAVEFORM Graf signala prije dinamicke obrade

DSPwaveform Graf signala nakon dinamicke obrade

captureSampleCountSignal Broj uzoraka signala

captureSampleCountDSP Broj uzoraka DSP signala

dataCaptureSignal Lista uzoraka signala

dataCaptureDSP Lista uzoraka DSP signala

Privatne (member) metode Opis

init () Inicijalizacijska funckija

normalizeData() Funkcija za normalizaciju podataka

captureAddData() Funkcija za spremanje uzoraka signala

savePlotsToFile() Spremanje uzoraka signala

update() Azuriranje valnih oblika signala

Kako bi se povezalo graficko korisnicko sucelje radeno u QT Creator programskom

alatu s Python kodom, potrebno je ukljuciti PyQt5 biblioteku. PyQt5 sadrzi preko 620

klasa koje opisuju graficko korisnicko sucelje, manipuliranje podatcima u XML for-

matu, mrezne komunikacije, SQL baze podataka, te ostale tehnologije [18].

Za prikaz valnih oblika signala prije i poslije dinamicke obrade koristena je PyQtGraph

biblioteka. Biblioteka je namijenjena za programe sa zahtjevnim matematickim ope-

racijama i odlikuje ju velika brzina, te je time prikladna za koristenje u programima s

obradom signala u stvarnom vremenu [19].

Kao sto je vec spomenuto, program omogucuje dinamicku obradu 2-kanalne, 16-bitne

wav datoteke. Za manipulaciju podatcima wav datoteke koristena je Wave biblioteka.

Wave modul dio je standardne Python biblioteke i predstavlja korisno sucelje prema

wav formatu zvuka [20].

S obzirom na to da se podatci iz wav datoteke spremaju u obliku jednodimenzionalnog

polja, koristena je numpy biblioteka. Numpy omogucuje ucinkovitu i brzu manipula-

ciju podatcima koji se nalazi u jedno ili visedimenzionalnom polju [21]. Nadalje, u

programu se koristi kako bi se blokovi audio uzoraka proslijedili na DSP analizu i

Dinamicka obrada audio signala 24

Page 33: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.2. Cython wrapper

obradu.

Pyaudio biblioteka omogucuje povezivanje Pythona s PortAudio bibliotekom (audio I/O

biblioteka otvorenog koda). Kako bi bilo moguce koristiti Pyaudio biblioteku, potrebno

ju je najprije instancirati. Zatim se na zeljenom uredaju otvori audio [stream] kako bi

bila omogucena reprodukcija zvuka. Ako se zeli raditi obrada audio podataka u stvar-

nom vremenu koristi se callback nacin rada. U callback nacinu rada potrebno je spe-

cificirati callback funkciju koja se poziva u zasebnoj dretvi [22] (dretva za dinamicku

obradu audio signala).

3.2 Cython wrapper

Logika za dinamicku obradu signala razvijena je u C++ programskom jeziku. Medutim,

kako bi bilo moguce pozvati funkcije dinamicke obrade signala iz Python program-

skog jezika, potrebno je redefinirati C++ header datoteku dinamickog procesora u Cyt-

hon sintaksi. U ovom programu, zadatak Cython klase PyDynamicProcessor je tocno

preslikati sve funkcije Python programskog jezika u odgovarajuce ekvivalentne funk-

cije C++ programskog jezika.

Nakon sto je napisan Cython wrapper za C++ klasu DynamicProcessor, potrebno je napi-

sati odgovarajucu sriptu (datoteka setup.py) za njeno prevodenje u pyd format koji se

moze unijeti naredbom import u Python programski jezik. Prevodenje Cython modula

odvija se naredbom:

python setup.py build ext –inplace

Sve funkcije Cython modula dostupne su Python programu nakon sto je kreirana pyd

datoteka unesena u Python program.

Dinamicka obrada audio signala 25

Page 34: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

3.3 DSP algoritmi

Programska inacica petlje za dinamicku obradu audio signala prikazana je Slikom 3.3.

Cekaj poziv

DSP funkcije

Obrada

audio

signala?

Promjena

GUI-a?

Citaj ulazne

podatke

Citaj kontrolne

podatke

Obrada audio

podataka

Kreiranje izlaznih

podataka

Podesi podatke

za sljedecu petlju

Upisi izlazne

podatke

ne

da da

ne

Slika 3.3: Algoritam za dinamicku obradu podataka

Dinamicka obrada audio signala 26

Page 35: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

Po uzoru na [2], u C++ programskom jeziku razvijen je dinamicki procesor. Metode

koristene za detekciju razine signala i izracun pojacanja kao i pomocne funkcije defi-

nirane su kao dio klase DynamicProcessor i prikazane su Tablicom 3.4.

Tablica 3.4: Opis varijabli i metoda klase DynamicProcessor

DynamicProcessor

Privatne (member) varijable Opis

sampleRate Frekvencija uzorkovanja

inputGain Ulazno pojacanje (dB)

outPutGain Izlazno pojacanje (dB)

threshold Granicna razina (dB)

attackTimeMs Vrijeme reakcije (ms)

releaseTimeMs Vrijeme otpustanja (ms)

ratio Omjer kompresije/ekspanzije

kneeWidth Sirina koljena (dB)

delayLine Kasnjenje ulaznog signala (ms)

timeConstant 0 - Digitalna vremenska konstanta

1 - Analogna vremenska konstanta

processorType 0 - COMRESSOR

1 - LIMITER

2 - EXPANDER

3 - NOISE GATEdetectionType 0 - DETECT PEAK

1 - DETECT MS

2 - DETECT RMSEnvelopeFollower leftEnvelopeFollower Detektor razine signala za lijevi kanal

EnvelopeFollower rightEnvelopeFol-

lower

Detektor razine signala za desni kanal

Privatne (member) metode Opis

DynamicProcessor() Konstruktor klase

˜DynamicProcessor() Destruktor klase

Dinamicka obrada audio signala 27

Page 36: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

initialize() Funkcija za inicijalizaciju klase; postav-

lja privatne varijable klase u vrijednosti

odredene korisnickim suceljem

prepareForPlay() Funkcija za inicijalizaciju klase Envelo-

peFollower

processAudioFrame() Glavna funkcija za obradu uzoraka iz

meduspremnika

normalizeInputData() Funkcija za normalizaciju ulaznih poda-

takadenormalizeOutputData() Funkcija za denormalizaciju izlaznih

podataka

calculateCompressorGain() Funkcija za izracun pojacanja u slucaju

da je dinamicki procesor tipa COMPRE-

SSOR ili LIMITERcalculateExpanderGain() Funkcija za izracun pojacanja u slucaju

da je dinamicki procesor tipa EXPAN-

DER ili NOISE GATElagrangeInterpolate() Funkcija za racunanje Langranzovog in-

terpolata 2. stupnja

userChangedData() Funkcije azuriranje varijabli nakon pro-

mjene parametara GUI-a

Nakon sto se instancira klasa DynamicProcessor i nakon sto se napravi inicijalizira te

iste klase pritiskom na tipku Play, otvori se audio stream i program ude u audioCall-

back() funkciju. Kad se pozove funkcija za obradu signala, najprije se procitaju ulazni

podatci iz meduspremnika, nad tim podatcima radi se DSP analiza i obrada, kreiraju

se izlazni podatci, te se ti podatci salju na I/O jedinicu, sto je u ovom slucaju zvucnik

racunala. Glavna funkcija za obradu audio signala (processAudioFrame()) prikazana je

algoritmom 1. U suprotnom, odnosno, ako nije pozvana funkcija za obradu audio

podataka, ispituje se je li korisnik promijenio jedan od parametara GUI-a, u kojem

slucaju se poziva odgovarajuca funkcija za azuriranje parametara dinamicke obrade

audio signala kao sto je to prikazano dijagramom na Slici 3.3.

Dinamicka obrada audio signala 28

Page 37: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

Algoritam 1: processAudioFrame() - funkcija za dinamicku obradu signalaInput: inData, size, outData

1 envelopeValue← 0.0

2 gain← 1.0

3 if (!normalizeInputData(&inData[0],size) then

4 return false

5 end

6 for (int i = 0; i < size; i++) do

7 gain← 1.0

8 if (i % 2) then

9 envelopeValue← rightEnvelopeFollower.detectEnvelope(inData[i] *

pow(10.0, inputGain / 20))

10 else

11 envelopeValue← leftEnvelopeFollower.detectEnvelope(inData[i] *

pow(10.0, inputGain / 20))

12 end

13 if (processorType == COMPRESSOR or processorType == LIMITER) then

14 gain← calculateCompressorGain()

15 end

16 else if (processorType == EXPANDER or processorType == NOISE GATE)

then

17 gain← calculateExpanderGain()

18 end

19 outData[i] = gain * inData[i] * outputGainLin

20 end

21 if (!denormalizeOutputData(&outData[0], size)) then

22 return false

23 end

24 return true

Dinamicka obrada audio signala 29

Page 38: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

3.3.1 Topologija dinamickog procesora

Slika 3.4 prikazuje feedforward topologiju programski izvedenog dinamickog proce-

sora. Signal nad kojim se vrsi dinamicka regulacija dovodi se na dva ulaza. Jedan

ulaz je digitalno kontrolirano pojacalo (engl. Digitally Controlled Amplifier/Attenuator -

DCA), a drugi je sklop za detekciju razine signala i izracun pojacanja. Detektor ra-

zine analizira ulazni signal i na osnovu detektirane razine sklop za izracun pojacanja

odreduje redukciju pojacanja koja ce se primijeniti na ulazni signal. Sklopovi za de-

tekciju razine signala i izracun pojacanja leze u bocnom lancu sklopa [2].

DCA β

x(n)

α

Detektor

razine

Izracun

pojacanja

y(n)

Slika 3.4: Feedforward topologija programski izvedenog dinamickog procesora

3.3.2 Detekor razine signala

Signal na ulazu bocnog lanca se najprije pojacava (blok oznacen s α na Slici 3.4) kako

bi se ”okinuo” detektor razine signala u slucaju da je ulazni signal niske amplitude.

Nakon ulaznog pojacala, signal se dovodi na detektor anvelope (razine signala) koji

se sastoji od detektora vrsne, srednje kvadratne ili efektivne vrijednosti signala i bloka

za logaritamsku konverziju.

Po uzoru na [2], u C++ programskom jeziku izveden je digitalni sustav za detekciju

razine signala. Detektor razine signala u programskom jeziku izveden je kao klasa

EnvelopeFollower. Metode koji su svojstvene navedenoj klasi opisane su u Tablici 3.5.

Tablica 3.5: Opis varijabli i metoda klase EnvelopeFollower

EnvelopeFollower

Privatne (member) varijable Opis

envelopeValue Trenutna vrijednost anvelope signala

sampleRate Frekvencija uzorkovanja

attackTimeMs Vrijeme reakcije u ms

attackTime Vrijeme reakcije

Dinamicka obrada audio signala 30

Page 39: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

releaseTimeMs Vrijeme otpustanja u ms

releaseTime Vrijeme otpustanja

detectionType 0 - Detekcija vrsne vrijednosti signala

1 - Detekcija srednje kvadratne vrijed-

nosti signala

2 - Detekcija efektivne vrijednosti sig-

nalatimeConstant 0 - Digitalna vremenska konstanta

1 - Analogna vremenska konstanta

logDetector True ako se radi o logaritamskoj detekciji

Privatne (member) metode Opis

EnvelopeFollower() Konstruktor klase

˜EnvelopeFollower() Destruktor klase

init() Inicijalizacija funkcija; poziva se jednom

prije obrade signala

setTimeConstant() Postavlja vremensku konstantu detek-

tora razine signala

setAttackTime() Postavlja vrijeme napada ovisno o pro-

mjeni korisnickog sucelja

setRelaseTime() Postavlja vrijeme otpustanja ovisno o

promjeni korisnockog sucelja

setDetectionType() Postavlja nacin detekcije ovisno o pro-

mjeni korisnickog sucelja

setSampleRate() Postavlje frekvenciju uzorkovanja sig-

nalasetLogDetector() Postavlja logaritamsku ili linearna de-

tekciju

detectEnvelope() Funckija detekcije, za dani ulazni uzo-

rak x(n) vraca vrijednost anvelope sig-

nala

Iako nisu dane u Tablici 3.5, klasa EnvelopeFollower sadrzi i funkcije za dohvacanje

svih privatnih varijabli. Funkcija za detekciju razine signala dana je Algoritmom 2.

Ovisno o tome je li trenutna vrijednost uzorka veca od anvelope, primjenjuje se odgo-

Dinamicka obrada audio signala 31

Page 40: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

varajuci faktor mnozenja τa ili τr kako bi se izracunala trenutna vrijednost anvelope za

zadani uzorak. Trenutnu vrijednost anvelope je zatim potrebno ograniciti na interval

[0,1] te pretvoriti dobivenu vrijednost anvelope iz linearne u logaritamsku skalu ako

je omogucena logaritamska detekcija.

Algoritam 2: Algoritam detekcije razine signalaInput: sample

1 if detectionType == 0 then

2 sample← fabs(sample)

3 else

4 sample← fabs(sample) * fabs(sample)

5 end

6 sample← detectionType(sample)

7 currentEnvelope← 0.0

8 if sample > envelopeValue then

9 currentEnvelope← (envelopeValue - sample) * attackTime + sample

10 else

11 currentEnvelope← (envelopeValue - sample) * releaseTime + sample

12 end

13 currentEnvelope← limitEnvelope(currentEnvelope)

14 if detectionType == 2 then

15 currentEnvelope← pow(currentEnvelope, 0.5)

16 end

17 if logDetector then

18 return 20*log10(currentEnvelope)

19 end

20 return currentEnvelope

Dinamicka obrada audio signala 32

Page 41: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

3.3.3 Izracun pojacanja

Nakon detektiranja razine audio signala, signal se dovodi na ulaz sklopa za izracun

pojacanja (Slika 3.4). Zadatak sklopa za izracun pojacanja je racunanje redukcije

pojacanja koje ce se primijeniti na ulazni signal. Redukciju pojacanja odreduju para-

metri: prag, omjer kompresije/ekspanzije, sirina koljena te trenutna vrijednost anve-

lope [13]. Po uzoru na [2], za izracun redukcije pojacanja koriste se dodatne varijable

CS i ES koje se racunaju iz omjera kompresije/ekspanzije. Kod kompresora, CS varira

izmedu [0,1], dok omjer kompresije (engl. Ratio) varira izmedu [1,+∞]. Kod silaznog

ekspandera, parametar ES varira izmedu [-1,0], dok omjer ekspanzije (engl. Ratio)

varira izmedu [+∞,1] [2].

Pojacanje kompresora (dB) dano je jednadzbom (3.1) [2]:

G(n) = f (d(n)) (3.1)

gdje je

CS =

1− (1/ρ); za kompresor

1.0; za limiter(3.2)

f =

CS ∗ (d0 − d(n)); ako je d(n) ≥ d0

0.0; ako je d(n) < d0

(3.3)

gdje CS oznacava strminu kompresora, ρ oznacava omjer kompresije, d(n) izlaz iz

detektora razine signala, a d0 vrijednost praga (engl. Threshold).

Pojacanje silaznog ekspandera dano je jednadzbom (3.4) [2]:

G(n) = f (d(n)) (3.4)

gdje je

ES =

(1/ρ)− 1; za silazni ekspander

−1.0; za noise gate(3.5)

f =

ES ∗ (d0 − d(n)); ako je d(n) < d0

0.0; ako je d(n) ≥ d0

(3.6)

Dinamicka obrada audio signala 33

Page 42: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

gdje ES oznacava strminu ekspandera, ρ oznacava omjer ekspanzije, d(n) izlaz iz de-

tektora razine signala, a d0 vrijednost praga (engl. Threshold).

Tocka u kojoj signal dosegne razinu praga i aktivira rad kompresora/ekspandera

naziva se koljeno. Uz ostri prijelaz (hard knee), signal moze biti iznad ili ispod ra-

zine praga. Blagi prijelaz (soft knee) uzrokuje da se promjena pojacanja odvija poste-

peno preko predefinirane sirine koljena oko vrijednosti praga. Kako bi se izgenerirala

krivulja blagog prijelaza koristi se interpolacija putem Langranzovih polinoma [2].

Funkcije za izracun pojacanja dinamickih regulatora razine prikazani su algoritmima

3 i 4.

Algoritam 3: Funkcija za izracun pojacanja kompresoraInput: envelopeValue, threshold, ratio, kneeWidth, limiter

Result: gain

/* Jednadzba (3.2) */

1 cs← 1.0 - (1.0 / ratio)

2 if limiter then

3 cs← 1.0

4 end

5 if kneeWidth > 0 && envelopeValue > (threshold - kneeWidth / 2.0) &&

envelopeValue < (threshold + kneeWidth / 2.0) then

6 cs← interpolateLangrange()

7 end

/* Jednadzba (3.3) */

8 gain← cs * (threshold - envelopeValue)

9 return convertDB2float(gain)

Dinamicka obrada audio signala 34

Page 43: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 3. Metode 3.3. DSP algoritmi

Algoritam 4: Funkcija za izracun pojacanja ekspanderaInput: envelopeValue, threshold, ratio, kneeWidth, gate

Result: gain

/* Jednadzba (3.5) */

1 es← (1.0 / ratio) - 1.0

2 if gate then

3 es← -1.0

4 end

/* Ako je blagi prijelaz aktivan primjeni Lang. interpolaciju */

5 if kneeWidth > 0 && envelopeValue > (threshold - kneeWidth / 2.0) &&

envelopeValue < (threshold + kneeWidth / 2.0) then

6 es← interpolateLangrange()

7 end

/* Jednadzba (3.6) */

8 gain← es * (threshold - envelopeValue)

9 return convertDB2float(gain)

Dinamicka obrada audio signala 35

Page 44: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

POGLAVLJE 4

Rezultati

Rezultati metode za dinamicku obradu audio signala prikazani su Slikama 4.1 - 4.8.

Audio datoteke (2-kanalne, 16-bitne wav datoteke) osigurala je The Storm Productions

Studio produkcijska kuca. Dinamicka obrada signala za audio datoteku koja prikazuje

zvuk gitare s efektom distorzije prikazani su na Slikama 4.1 - 4.4; dok su rezultati

dinamicke obrade signala za zvuk gitare bez efekta distorzije prikazani Slikama 4.5 -

4.8.

Slika 4.1: Dinamicka obrada signala - kompresor (guitar noise.wav datoteka)

Dinamicka obrada audio signala 36

Page 45: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

Slika 4.2: Dinamicka obrada signala - limiter (guitar noise.wav datoteka)

Kao sto je prikazano na Slikama 4.1 i 4.2, za kompresor i limiter radi se detekcija efek-

tivne vrijednosti signala (parametar Detection Type) uz digitalnu vremensku konstantu

(parametar Time constant) cija je formula dana u poglavlju 2.3.1. Vremena reakcije i

otpustanja postavljenja su na inicijalne vrijednosti (parametri Attack Time i Release

Time), dok je omjer kompresije (parametar Ratio) postavljen na 10. Prag detekcije

(parametar Threshold) je -40dB. S obzirom na to da je sirina koljena (parametar Knee

Width) postavljena na nula, radi se o strmom prijelazu (hard knee) i ne primjenjuje se

Langranzova interpolacija za izracun pojacanja. Izlazno pojacanje (parametar Output

Gain) primjenjuje se kako bi se povecala razina signala nakon dinamicke obrade.

Dinamicka obrada audio signala 37

Page 46: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

Slicno kao za kompresor i limiter, za silazni ekspander i noise gate uredaj za detek-

ciju anvelope koristi se efektivna vrijednost signala. Parametri ulaznog i izlaznog

pojacanja, praga, vremena reakcije i otpustanja te sirina koljena postavljene su na nji-

hove inicijalne vrijednosti uz omjer ekspanzije jednog reda velicine. Slika 4.3 prikazuje

valni oblik signala audio datoteke nakon dinamicke ekspanzije razine.

Slika 4.3: Dinamicka obrada signala - silazni ekspander (guitar noise.wav datoteka)

Slika 4.4 prikazuje rad noise gate uredaja. Kao sto je opisano u prethodnim poglav-

ljima, noise gate uredaj ogranicava razinu suma, odnosno ako razina signala padne

ispod predefiniranog praga, pojacanje tog signala padne na nula. Parametri noise gate

uredaja odgovaraju onima postavljenim kod silaznog ekspandera.

Dinamicka obrada audio signala 38

Page 47: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

Slika 4.4: Dinamicka obrada signala - noise gate (guitar noise.wav datoteka)

Slike 4.5 - 4.8 prikazuju rad razlicitih dinamickih procesora nad audio datotekom

koja opisuje zvuk gitare bez ukljucenog efekta distorzije. Slike 4.5 i 4.6 prikazuju rad

dinamickog kompresora/limitera razine uz dinamicko mijenjanje parametara kom-

presije. U pocetku izvodenja programa, parametri dinamicke kompresije postavljeni

su na inicijalne vrijednosti. U ovom slucaju, radi se detekcija vrsne vrijednosti signala

uz analognu vremensku konstantu. Omjer kompresije je postavljen na 10 uz sirinu

koljena 20dB (soft knee kompresija).

Dinamicka obrada audio signala 39

Page 48: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

Slika 4.5: Dinamicka obrada signala - kompresor (guitar clean.wav datoteka)

S obzirom na to da su parametri kompresije u pocetku izvodenja programa postavljeni

na svoje inicijalne vrijednosti, ne dolazi do aktivacije kompresora i izlazni signal prati

ulazni signal kako je prikazano Slikom 4.5. Zatim se spusti razina praga cime se

aktivira rad kompresora i na izlazu se dobiva komprimiran signal (uzorak 0.8 ∗ 106).

Stupanj kojom ce se smanjiti razina signala opisan je u poglavlju 3.3.3. Naposljetku,

poveca se ulazno pojacanje cime se pospjesuje detekcija razine signala sto rezultira

daljnjim smanjenjem izlaznog signala.

Dinamicka obrada audio signala 40

Page 49: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

Rad limitera razine prikazan je Slikom 4.6. Parametri za detekciju anvelope signala

identicni su onima koristenima pri radu kompresora. U pocetku izvodenja programa

parametri dinamicke obrade signala su postavljeni na inicijalne vrijednosti, cime ne

dolazi do aktiviranja rada limitera i izlazni signal prati ulazni signal kao sto je pri-

kazano Slikom 4.6. Zatim se spusti razina praga, aktivira se rad limitera i na izlazu

se dobiva komprimiran signal (uzorak 0.3 ∗ 106). Potom se na izlazni signal primjeni

izlazno pojacanje (uzorak 0.7 ∗ 106) cime se poveca razina izlaznog signala nakon di-

gitalne obrade.

Slika 4.6: Dinamicka obrada signala - limiter (guitar clean.wav datoteka)

Dinamicka obrada audio signala 41

Page 50: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

Rad silaznog ekspandera prikazan je na Slici 4.7. U pocetku izvodenja programa para-

metri dinamicke ekspanzije postavljeni su na inicijalne vrijednosti izuzev parametra

praga cija je vrijednosti postavljena na -60dB. Za detekciju razine koristi se srednja

kvadratna vrijednost signala uz digitalnu vremensku konstantu. U pocetku izvodenja

programa, izlazni signal prati ulazni signal s obzirom na to da je razina praga takva

da ne dolazi do aktivacije ekspandera. Potom se promjeni razina praga u 0dB te se

omjer ekspanzije postavi na najvecu mogucu vrijednost cime se aktivira rad silaznog

ekspandera, sto rezultira smanjenjem razine svih uzoraka signala cija je vrijednost

manja od vrijednosti praga (uzorak 0.6 ∗ 106).

Slika 4.7: Dinamicka obrada signala - silazni ekspander (guitar clean.wav datoteka)

Dinamicka obrada audio signala 42

Page 51: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 4. Rezultati

Rad noise gate uredaja prikazan je Slikom 4.8. Parametri koji utjecu na detekciju anve-

lope identicni su onima koristenim pri radu silaznog ekspandera. Pri pokretanju

programa, razina praga postavljena je na -60dB cime ne dolazi do aktiviranja rada no-

ise gate uredaja. Zatim se razina praga postavi na 0dB sto rezultira smanjenjem razine

signala (uzorak 0.3 ∗ 106) cija je vrijednost uzoraka signala manja od predefinirane

razine praga.

Slika 4.8: Dinamicka obrada signala - noise gate (guitar clean.wav datoteka)

Dinamicka obrada audio signala 43

Page 52: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Poglavlje 5. Zakljucak

POGLAVLJE 5

Zakljucak

Fokus ovog rada bila je dinamicka obrada signala u stvarnom vremenu. Preciznije,

teoretski su obradeni principi dinamicke obrade signala koji se baziraju na radu

razlicitih uredaja za dinamicku regulaciju razine i to: kompresor, limiter, ekspan-

der i noise gate. U prakticnom dijelu diplomskog zadatka izvedeno je programsko

rjesenje za dinamicku regulaciju razine audio signala u stvarnom vremenu. Program-

sko rjesenje izvedeno je u Python i C++ programskim jezicima. Nadalje, korisniku

je omoguceno, preko grafickog korisnickog sucelja, podesavanje svih parametara di-

namicke obrade audio signala, te spremanje rezultata obrade.

Poboljsanja implementiranog sustava vidljiva su u obliku ”pametnog” dinamickog

procesora, gdje se ulazni signal analizira kako bi se parametri kompresije/ekspanzije

bolje prilagodili sadrzaju audio datoteka.

Dinamicka obrada audio signala 44

Page 53: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Literatura Literatura

Literatura

[1] Ryan J. Cassidy. ”Dynamic range compression of audio signals consistent with

recent time-varying loudness models”. 2004 IEEE International Conference on Aco-

ustics, Speech, and Signal Processing 4 (2004), str. iv–iv.

[2] William C. Pirkle. Designing Audio Effect Plug-Ins in C++: With Digital Audio Sig-

nal Processing Theory. 1. izdanje. Taylor i Francis, 2012.

[3] Python Software Foundation. Python. 2001-2019 (pristupljeno 14. Sijecnja, 2019).

url: https://www.python.org/.

[4] ISO. ISO/IEC 14882:2017 Information technology — Programming languages — C++.

5. izdanje. Zeneva, Svicarska: International Organization for Standardization,

prosinac 2017, str. 1605. url: https://www.iso.org/standard/68564.html.

[5] Robert Bradshaw i dr. Stefan Behnel. Cython - C Extensions for Python. 2018 (pris-

tupljeno 14. Sijecnja, 2019). url: https://cython.org/.

[6] Martin H. Weik. Nyquist theorem. Boston, MA: Springer US, 2001, str. 1127–1127.

isbn: 978-1-4020-0613-5. doi: 10.1007/1- 4020- 0613- 6_12654. url: https:

//doi.org/10.1007/1-4020-0613-6_12654.

[7] S. Hamid Nawab Alan V. Oppenheim Alan S. Willsky. Signals and Systems. 2. iz-

danje. Prentice Hall, 1997.

[8] Jesper Nilsson i Thorbjørn Bonvik. ”Dynamic Range Sound Compressor Unit”.

Zavrsni rad. Gothenburg, Svedska: CHALMERS UNIVERSITY OF TECHNO-

LOGY/ UNIVERSITY OF GOTHENBURG, 2017.

[9] Gary Davis i Ralph Jones. The Sound Reinforcement Handbook. 2. izdanje. Milwa-

ukee, WI : Hal Leonard Publishing, 1989, str. 436. isbn: 9780881889000.

Dinamicka obrada audio signala 45

Page 54: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Literatura Literatura

[10] Ivan Durek i Hrvoje Domitrovic. Materijali za predavanja iz predmeta AUDIOTEH-

NIKA za studente preddiplomskog studija Fakulteta elektrotehnike i racunarstva u Za-

grebu Sveucilista u Zagrebu. inacica 2.01. Fakultet elektrotehnike i racunarstva

u Zagrebu. 2018 (pristupljeno 15. Sijecnja, 2019). url: https://bib.irb.hr/

datoteka/966354.Audiotehnika_-_Materijali_za_predavanja_2_01.pdf.

[11] Rustin W.Allred. ”Digital Audio Dynamic Range Compressor and Method”.

Pat. US Patent 6 757 396. 2004. url: https://patents.google.com/patent/

US6757396.

[12] Jon C. Schmidt. ”Apparatus for Dynamic Range Compression of an Audio Sig-

nal”. Pat. US Patent 5 832 444. 1998. url: https : / / patents . google . com /

patent/US5832444.

[13] Joshua D. Reiss Dimitrios Giannoulis Michael Massberg. ”Digital Dynamic Range

Comporessor Design - A Tutorial and Analysis”. Journal of the Audio Engineering

Society 60.6 (Srpanj 2012), str. 399–408.

[14] Guy W. McNally. ”Dynamic Range Control of Digital Audio Signals”. Journal

of the Audio Engineering Society 32 (svibanj 1984), str. 316–327. url: https://

www.researchgate.net/publication/243463167_Dynamic_Range_Control_of_

Digital_Audio_Signals.

[15] A. Baric Z. Butkovic J. Divkovic-Puksec. Elektronika 1. inacica 1.0. Fakultet elek-

trotehnike i racunarstva u Zagrebu. 2006.

[16] Sophocles J. Orfanidis. Introduction to Signal Processing. Upper Saddle River, NJ,

USA: Prentice-Hall, Inc., 1995. isbn: 0-13-209172-0.

[17] Goran Muic i Mladen Jurak. Predavanje i vjezbe iz racunarskog praktikuma. 2006/2007

(pristupljeno 5. Sijecnja, 2019). url: https://web.math.pmf.unizg.hr/nastava/

rp2/nastava.html.

[18] Riverbank Computing Limited. PyQt5 Reference Guide. 2018 (pristupljeno 5. Sijecnja,

2019). url: http://pyqt.sourceforge.net/Docs/PyQt5/.

[19] University of North Carolina at Chapel Hill Luke Campagnola. PyQtGraph -

Scientific Graphics and GUI Library for Python. 2017 (pristupljeno 5. Sijecnja, 2019).

url: http://www.pyqtgraph.org/.

Dinamicka obrada audio signala 46

Page 55: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Literatura Literatura

[20] Python Software Foundation. wave - Read and write WAV files. (pristupljeno 5.

Sijecnja, 2019). url: https://docs.python.org/2/library/wave.html.

[21] Travis Oliphant. NumPy: A guide to NumPy. USA: Trelgol Publishing. [Online;

pristupljeno 18. Sijecnja, 2019]. 2006–. url: http://www.numpy.org/.

[22] Hubert Pham. PyAudio. 2006 (pristupljeno 5. Sijecnja, 2019). url: https : / /

people.csail.mit.edu/hubert/pyaudio/.

Dinamicka obrada audio signala 47

Page 56: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

Sazetak

Dinamicka obrada audio signala

Sazetak

Dinamicka regulacija razine cesto je koristen i praktican alat za upravljanje dinamickim

rasponom audio signala. Dinamicki procesori imaju dugu povijest koristenja u elek-

troakusticnom lancu i mogu se implementirati u analognoj i digitalnoj domeni. U

ovom radu, teorijski su obradeni principi dinamicke obrade audio signala. Nada-

lje, koristenjem Python i C++ programskih jezika povezanih preko Cython sucelja,

programski je izvedena feedforward topologija dinamickog procesora s grafickim ko-

risnickim suceljem koji omogucuje namjestanje prijenosne karakteristike i osnovnih

parametara dinamicke kompresije/ekspanzije razine audio signala.

Kljucne rijeci: dinamicka regulacija razine; dinamicki procesori; kompresor; ekspan-

der; limiter; noise gate; Python; Cython; C++

Dynamic Audio Signal Processing

Abstract

Dynamic range control is a common and practical tool used to control the dynamic

range of an audio signal. Dynamic processors have a long history of use in the elec-

troacoustic chain and they can be implemented both in analog and digital domain. In

this paper, basics principles of dynamic audio signal processing are discussed. Furt-

hermore, feedforward dynamic processor with a graphical user interface is developed

in Python and C++ programming languages where Cython is used as an interface

between the two. Software implementation allows for the transfer function parame-

ters tuning.

Keywords: dynamic range control; dynamic processor; compressor; limiter; expan-

der; noise gate; Python; Cython; C++

Dinamicka obrada audio signala 48

Page 57: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

PRILOG A

Programski kod grafickog korisnickog

sucelja - Python

1 # -*- coding: utf-8 -*-

2

3 # Form implementation generated from reading ui file ’UserInterface.ui’

4 #

5 # Created by: PyQt5 UI code generator 5.11.3

6 #

7 # WARNING! All changes made in this file will be lost!

8

9 from PyQt5 import QtCore, QtGui, QtWidgets

10 from PyQt5.QtWidgets import qApp

11

12 from enum import Enum

13 import pyqtgraph as pg

14 import numpy as np

15 import threading

16 import pyaudio

17 import wave

18

19 import dynamicProcessor_wrapper

20

21 class TimeConstant(Enum):

22 Digital = 0

23 Analog = 1

24

25 class ProcessorType(Enum):

26 COMPRESSOR = 0

Dinamicka obrada audio signala 49

Page 58: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

27 LIMITER = 1

28 EXPANDER = 2

29 NOISE_GATE = 3

30

31 class DetectionType(Enum):

32 DETECT_PEAK_VALUE = 0

33 DETECT_MEAN_SQUARE = 1

34 DETECT_RMS = 2

35

36 class PlotWidget(pg.GraphicsWindow):

37 pg.setConfigOptions(antialias=True)

38 def __init__(self, parent=None, **kargs):

39 pg.GraphicsWindow.__init__(self, **kargs)

40 self.setParent(parent)

41 self.setWindowTitle(’Time and frequency signal representation’)

42 self.signalWAVEFORM = self.addPlot(title=’Audio Waveform - Before Dynamic

↪→ Signal Processing’, row=1, col=1)

43 self.DSPwaveform = self.addPlot(title=’Audio Waveform - After Dynamic

↪→ Signal Processing’, row=2, col=1)

44

45 self.signalData = []

46 self.DSPsignalData = []

47

48 self.captureSampleCountSignal = 0

49 self.captureSampleCountDSP = 0

50

51 self.dataCaptureSignal = list()

52 self.dataCaptureDSP = list()

53

54 self.savedSignalData = list()

55 self.savedDSPdata = list()

56

57 self.curvesignal = self.signalWAVEFORM.plot(self.dataCaptureSignal, pen=’c’)

58 self.curveDSPsignal = self.DSPwaveform.plot(self.dataCaptureDSP, pen=’m’)

59

60 self.timer = pg.QtCore.QTimer(self)

61 self.timer.timeout.connect(self.update)

62 self.timer.start(60)

63 def normalizeInputData(self, inData):

Dinamicka obrada audio signala 50

Page 59: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

64 inData = inData.astype(np.float32)

65 inData /= 32768.0

66 return inData

67

68 def clearPlotData(self):

69 if self.timer.isActive() == True:

70 self.timer.stop()

71

72 self.captureSampleCountSignal = 0

73 self.captureSampleCountDSP = 0

74

75 self.dataCaptureSignal = list()

76 self.dataCaptureSignal = list()

77

78 self.savedSignalData = list()

79 self.savedDSPdata = list()

80

81 if self.timer.isActive() == False:

82 self.timer.start(60)

83

84 def plotWAVfile(self, inputData):

85 self.signalData = self.normalizeInputData(inputData)

86 self.curveWaveform = self.signalWAVEFORM.plot(self.signalData, pen=’c’)

87 def update(self):

88 self.curveWaveform = self.signalWAVEFORM.clear()

89 self.curveWaveform = self.signalWAVEFORM.plot(self.dataCaptureSignal,

↪→ pen=’c’)

90 self.curveDSPsignal = self.DSPwaveform.clear()

91 self.curveDSPsignal = self.DSPwaveform.plot(self.dataCaptureDSP, pen=’m’)

92 def captureAddData(self, newData, label):

93 if label == ’Signal’:

94 self.captureSampleCountSignal += len(newData)

95 self.savedSignalData = np.hstack((self.savedSignalData, newData))

96 self.dataCaptureSignal = np.hstack((self.dataCaptureSignal, newData))

97 self.dataCaptureSignal = self.dataCaptureSignal[-len(newData):]

98 elif label == ’DSP’:

99 newData = newData.astype(np.int16)

100 newData = self.normalizeInputData(newData)

101 self.captureSampleCountDSP += len(newData)

Dinamicka obrada audio signala 51

Page 60: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

102 self.savedDSPdata = np.hstack((self.savedDSPdata, newData))

103 self.dataCaptureDSP = np.hstack((self.dataCaptureDSP, newData))

104 self.dataCaptureDSP = self.dataCaptureDSP[-len(newData):]

105

106 def savePlotsToFile(self, inputGain, streamComplete):

107 if streamComplete == True:

108 self.timer.stop()

109 # Figure definition

110 self.curveWaveform = self.signalWAVEFORM.clear()

111 self.curveWaveform = self.signalWAVEFORM.setLabel(axis=’bottom’,

↪→ text=’Number of samples’)

112 self.curveWaveform = self.signalWAVEFORM.setLabel(axis=’left’,

↪→ text=’Amplitude’)

113 self.curveWaveform = self.signalWAVEFORM.plot(self.savedSignalData,

↪→ pen=’c’)

114

115 self.curveDSPsignal = self.DSPwaveform.clear()

116 self.curveDSPsignal = self.DSPwaveform.setLabel(axis=’bottom’,

↪→ text=’Number of samples’)

117 self.curveDSPsignal = self.DSPwaveform.setLabel(axis=’left’,

↪→ text=’Amplitude’)

118 self.curveDSPsignal = self.DSPwaveform.plot(self.savedDSPdata, pen=’m’)

119 else:

120 pass

121

122 class Ui_MainWindow(QtGui.QWidget):

123 def __init__(self):

124 super(Ui_MainWindow, self).__init__()

125 self.streamCompleted = False

126 self.fileLoaded = False

127 self.playInLoop = False

128 self.callPlayCalled = False

129 self.dynamicProcessor = dynamicProcessor_wrapper.PyDynamicProcessor()

130 def setupUi(self, MainWindow):

131 MainWindow.setObjectName("MainWindow")

132 MainWindow.resize(1191, 826)

133 self.centralwidget = QtWidgets.QWidget(MainWindow)

134 self.centralwidget.setObjectName("centralwidget")

135 self.widget = PlotWidget(self.centralwidget)

Dinamicka obrada audio signala 52

Page 61: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

136 self.widget.setGeometry(QtCore.QRect(10, 150, 1161, 611))

137 self.widget.setObjectName("widget")

138 self.layoutWidget = QtWidgets.QWidget(self.centralwidget)

139 self.layoutWidget.setGeometry(QtCore.QRect(10, 10, 81, 121))

140 self.layoutWidget.setObjectName("layoutWidget")

141 self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget)

142 self.gridLayout.setContentsMargins(0, 0, 0, 0)

143 self.gridLayout.setObjectName("gridLayout")

144 self.detGainDial = QtWidgets.QDial(self.layoutWidget)

145 self.detGainDial.setMinimum(-12)

146 self.detGainDial.setMaximum(20)

147 self.detGainDial.setSingleStep(1)

148 self.detGainDial.setProperty("value", 0)

149 self.detGainDial.setNotchesVisible(True)

150 self.detGainDial.setObjectName("detGainDial")

151 self.gridLayout.addWidget(self.detGainDial, 1, 0, 1, 1)

152 self.label = QtWidgets.QLabel(self.layoutWidget)

153 self.label.setObjectName("label")

154 self.gridLayout.addWidget(self.label, 0, 0, 1, 1)

155 self.detGainspinBox = QtWidgets.QSpinBox(self.layoutWidget)

156 self.detGainspinBox.setMinimum(-12)

157 self.detGainspinBox.setMaximum(20)

158 self.detGainspinBox.setObjectName("detGainspinBox")

159 self.gridLayout.addWidget(self.detGainspinBox, 2, 0, 1, 1)

160 self.layoutWidget1 = QtWidgets.QWidget(self.centralwidget)

161 self.layoutWidget1.setGeometry(QtCore.QRect(240, 10, 81, 125))

162 self.layoutWidget1.setObjectName("layoutWidget1")

163 self.gridLayout_2 = QtWidgets.QGridLayout(self.layoutWidget1)

164 self.gridLayout_2.setContentsMargins(0, 0, 0, 0)

165 self.gridLayout_2.setObjectName("gridLayout_2")

166 self.thresholdSlider = QtWidgets.QSlider(self.layoutWidget1)

167 self.thresholdSlider.setMinimum(-60)

168 self.thresholdSlider.setMaximum(0)

169 self.thresholdSlider.setSingleStep(1)

170 self.thresholdSlider.setOrientation(QtCore.Qt.Vertical)

171 self.thresholdSlider.setObjectName("thresholdSlider")

172 self.gridLayout_2.addWidget(self.thresholdSlider, 1, 0, 1, 1)

173 self.label_2 = QtWidgets.QLabel(self.layoutWidget1)

174 self.label_2.setObjectName("label_2")

Dinamicka obrada audio signala 53

Page 62: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

175 self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1)

176 self.thresholdSpinBox = QtWidgets.QSpinBox(self.layoutWidget1)

177 self.thresholdSpinBox.setMinimum(-60)

178 self.thresholdSpinBox.setMaximum(0)

179 self.thresholdSpinBox.setObjectName("thresholdSpinBox")

180 self.gridLayout_2.addWidget(self.thresholdSpinBox, 2, 0, 1, 1)

181 self.layoutWidget2 = QtWidgets.QWidget(self.centralwidget)

182 self.layoutWidget2.setGeometry(QtCore.QRect(350, 10, 81, 125))

183 self.layoutWidget2.setObjectName("layoutWidget2")

184 self.gridLayout_3 = QtWidgets.QGridLayout(self.layoutWidget2)

185 self.gridLayout_3.setContentsMargins(0, 0, 0, 0)

186 self.gridLayout_3.setObjectName("gridLayout_3")

187 self.attackSlider = QtWidgets.QSlider(self.layoutWidget2)

188 self.attackSlider.setMinimum(1)

189 self.attackSlider.setMaximum(300)

190 self.attackSlider.setSingleStep(1)

191 self.attackSlider.setProperty("value", 20)

192 self.attackSlider.setOrientation(QtCore.Qt.Vertical)

193 self.attackSlider.setObjectName("attackSlider")

194 self.gridLayout_3.addWidget(self.attackSlider, 1, 0, 1, 1)

195 self.label_3 = QtWidgets.QLabel(self.layoutWidget2)

196 self.label_3.setObjectName("label_3")

197 self.gridLayout_3.addWidget(self.label_3, 0, 0, 1, 1)

198 self.attackSpinBox = QtWidgets.QSpinBox(self.layoutWidget2)

199 self.attackSpinBox.setMinimum(1)

200 self.attackSpinBox.setMaximum(300)

201 self.attackSpinBox.setProperty("value", 20)

202 self.attackSpinBox.setObjectName("attackSpinBox")

203 self.gridLayout_3.addWidget(self.attackSpinBox, 2, 0, 1, 1)

204 self.layoutWidget3 = QtWidgets.QWidget(self.centralwidget)

205 self.layoutWidget3.setGeometry(QtCore.QRect(570, 10, 81, 125))

206 self.layoutWidget3.setObjectName("layoutWidget3")

207 self.gridLayout_4 = QtWidgets.QGridLayout(self.layoutWidget3)

208 self.gridLayout_4.setContentsMargins(0, 0, 0, 0)

209 self.gridLayout_4.setObjectName("gridLayout_4")

210 self.label_4 = QtWidgets.QLabel(self.layoutWidget3)

211 self.label_4.setObjectName("label_4")

212 self.gridLayout_4.addWidget(self.label_4, 0, 0, 1, 1)

213 self.releaseSlider = QtWidgets.QSlider(self.layoutWidget3)

Dinamicka obrada audio signala 54

Page 63: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

214 self.releaseSlider.setMinimum(20)

215 self.releaseSlider.setMaximum(5000)

216 self.releaseSlider.setSingleStep(1)

217 self.releaseSlider.setProperty("value", 1000)

218 self.releaseSlider.setOrientation(QtCore.Qt.Vertical)

219 self.releaseSlider.setObjectName("releaseSlider")

220 self.gridLayout_4.addWidget(self.releaseSlider, 1, 0, 1, 1)

221 self.releaseSpinBox = QtWidgets.QSpinBox(self.layoutWidget3)

222 self.releaseSpinBox.setMinimum(20)

223 self.releaseSpinBox.setMaximum(5000)

224 self.releaseSpinBox.setProperty("value", 1000)

225 self.releaseSpinBox.setObjectName("releaseSpinBox")

226 self.gridLayout_4.addWidget(self.releaseSpinBox, 2, 0, 1, 1)

227 self.layoutWidget4 = QtWidgets.QWidget(self.centralwidget)

228 self.layoutWidget4.setGeometry(QtCore.QRect(680, 10, 81, 125))

229 self.layoutWidget4.setObjectName("layoutWidget4")

230 self.gridLayout_5 = QtWidgets.QGridLayout(self.layoutWidget4)

231 self.gridLayout_5.setContentsMargins(0, 0, 0, 0)

232 self.gridLayout_5.setObjectName("gridLayout_5")

233 self.label_5 = QtWidgets.QLabel(self.layoutWidget4)

234 self.label_5.setObjectName("label_5")

235 self.gridLayout_5.addWidget(self.label_5, 0, 0, 1, 1)

236 self.ratioSpinBox = QtWidgets.QSpinBox(self.layoutWidget4)

237 self.ratioSpinBox.setMinimum(1)

238 self.ratioSpinBox.setMaximum(20)

239 self.ratioSpinBox.setObjectName("ratioSpinBox")

240 self.gridLayout_5.addWidget(self.ratioSpinBox, 2, 0, 1, 1)

241 self.ratioSlider = QtWidgets.QSlider(self.layoutWidget4)

242 self.ratioSlider.setMinimum(1)

243 self.ratioSlider.setMaximum(20)

244 self.ratioSlider.setSingleStep(2)

245 self.ratioSlider.setProperty("value", 1)

246 self.ratioSlider.setOrientation(QtCore.Qt.Vertical)

247 self.ratioSlider.setObjectName("ratioSlider")

248 self.gridLayout_5.addWidget(self.ratioSlider, 1, 0, 1, 1)

249 self.layoutWidget5 = QtWidgets.QWidget(self.centralwidget)

250 self.layoutWidget5.setGeometry(QtCore.QRect(120, 10, 91, 121))

251 self.layoutWidget5.setObjectName("layoutWidget5")

252 self.gridLayout_6 = QtWidgets.QGridLayout(self.layoutWidget5)

Dinamicka obrada audio signala 55

Page 64: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

253 self.gridLayout_6.setContentsMargins(0, 0, 0, 0)

254 self.gridLayout_6.setObjectName("gridLayout_6")

255 self.outputGainDial = QtWidgets.QDial(self.layoutWidget5)

256 self.outputGainDial.setMinimum(0)

257 self.outputGainDial.setMaximum(20)

258 self.outputGainDial.setSingleStep(1)

259 self.outputGainDial.setProperty("value", 0)

260 self.outputGainDial.setNotchesVisible(True)

261 self.outputGainDial.setObjectName("outputGainDial")

262 self.gridLayout_6.addWidget(self.outputGainDial, 1, 0, 1, 1)

263 self.label_6 = QtWidgets.QLabel(self.layoutWidget5)

264 self.label_6.setObjectName("label_6")

265 self.gridLayout_6.addWidget(self.label_6, 0, 0, 1, 1)

266 self.outGainspinBox = QtWidgets.QSpinBox(self.layoutWidget5)

267 self.outGainspinBox.setMaximum(20)

268 self.outGainspinBox.setObjectName("outGainspinBox")

269 self.gridLayout_6.addWidget(self.outGainspinBox, 2, 0, 1, 1)

270 self.layoutWidget6 = QtWidgets.QWidget(self.centralwidget)

271 self.layoutWidget6.setGeometry(QtCore.QRect(790, 10, 81, 125))

272 self.layoutWidget6.setObjectName("layoutWidget6")

273 self.gridLayout_7 = QtWidgets.QGridLayout(self.layoutWidget6)

274 self.gridLayout_7.setContentsMargins(0, 0, 0, 0)

275 self.gridLayout_7.setObjectName("gridLayout_7")

276 self.kneeSlider = QtWidgets.QSlider(self.layoutWidget6)

277 self.kneeSlider.setMinimum(0)

278 self.kneeSlider.setMaximum(20)

279 self.kneeSlider.setSingleStep(1)

280 self.kneeSlider.setOrientation(QtCore.Qt.Vertical)

281 self.kneeSlider.setObjectName("kneeSlider")

282 self.gridLayout_7.addWidget(self.kneeSlider, 1, 0, 1, 1)

283 self.label_7 = QtWidgets.QLabel(self.layoutWidget6)

284 self.label_7.setObjectName("label_7")

285 self.gridLayout_7.addWidget(self.label_7, 0, 0, 1, 1)

286 self.kneeWidthSpinBox = QtWidgets.QSpinBox(self.layoutWidget6)

287 self.kneeWidthSpinBox.setMaximum(20)

288 self.kneeWidthSpinBox.setObjectName("kneeWidthSpinBox")

289 self.gridLayout_7.addWidget(self.kneeWidthSpinBox, 2, 0, 1, 1)

290 self.layoutWidget7 = QtWidgets.QWidget(self.centralwidget)

291 self.layoutWidget7.setGeometry(QtCore.QRect(900, 10, 101, 51))

Dinamicka obrada audio signala 56

Page 65: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

292 self.layoutWidget7.setObjectName("layoutWidget7")

293 self.gridLayout_8 = QtWidgets.QGridLayout(self.layoutWidget7)

294 self.gridLayout_8.setContentsMargins(0, 0, 0, 0)

295 self.gridLayout_8.setObjectName("gridLayout_8")

296 self.timeConstComboBox = QtWidgets.QComboBox(self.layoutWidget7)

297 self.timeConstComboBox.setObjectName("timeConstComboBox")

298 self.timeConstComboBox.addItem("")

299 self.timeConstComboBox.addItem("")

300 self.gridLayout_8.addWidget(self.timeConstComboBox, 1, 0, 1, 1)

301 self.label_9 = QtWidgets.QLabel(self.layoutWidget7)

302 self.label_9.setObjectName("label_9")

303 self.gridLayout_8.addWidget(self.label_9, 0, 0, 1, 1)

304 self.layoutWidget8 = QtWidgets.QWidget(self.centralwidget)

305 self.layoutWidget8.setGeometry(QtCore.QRect(900, 80, 101, 51))

306 self.layoutWidget8.setObjectName("layoutWidget8")

307 self.gridLayout_9 = QtWidgets.QGridLayout(self.layoutWidget8)

308 self.gridLayout_9.setContentsMargins(0, 0, 0, 0)

309 self.gridLayout_9.setObjectName("gridLayout_9")

310 self.label_8 = QtWidgets.QLabel(self.layoutWidget8)

311 self.label_8.setObjectName("label_8")

312 self.gridLayout_9.addWidget(self.label_8, 0, 0, 1, 1)

313 self.processorComboBox = QtWidgets.QComboBox(self.layoutWidget8)

314 self.processorComboBox.setObjectName("processorComboBox")

315 self.processorComboBox.addItem("")

316 self.processorComboBox.addItem("")

317 self.processorComboBox.addItem("")

318 self.processorComboBox.addItem("")

319 self.gridLayout_9.addWidget(self.processorComboBox, 1, 0, 1, 1)

320 self.layoutWidget_2 = QtWidgets.QWidget(self.centralwidget)

321 self.layoutWidget_2.setGeometry(QtCore.QRect(1030, 10, 141, 51))

322 self.layoutWidget_2.setObjectName("layoutWidget_2")

323 self.gridLayout_10 = QtWidgets.QGridLayout(self.layoutWidget_2)

324 self.gridLayout_10.setContentsMargins(0, 0, 0, 0)

325 self.gridLayout_10.setObjectName("gridLayout_10")

326 self.detectionTypeComboBox = QtWidgets.QComboBox(self.layoutWidget_2)

327 self.detectionTypeComboBox.setObjectName("detectionTypeComboBox")

328 self.detectionTypeComboBox.addItem("")

329 self.detectionTypeComboBox.addItem("")

330 self.detectionTypeComboBox.addItem("")

Dinamicka obrada audio signala 57

Page 66: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

331 self.gridLayout_10.addWidget(self.detectionTypeComboBox, 1, 0, 1, 1)

332 self.label_10 = QtWidgets.QLabel(self.layoutWidget_2)

333 self.label_10.setObjectName("label_10")

334 self.gridLayout_10.addWidget(self.label_10, 0, 0, 1, 1)

335 self.widget1 = QtWidgets.QWidget(self.centralwidget)

336 self.widget1.setGeometry(QtCore.QRect(460, 10, 81, 125))

337 self.widget1.setObjectName("widget1")

338 self.formLayout = QtWidgets.QFormLayout(self.widget1)

339 self.formLayout.setContentsMargins(0, 0, 0, 0)

340 self.formLayout.setObjectName("formLayout")

341 self.label_12 = QtWidgets.QLabel(self.widget1)

342 self.label_12.setObjectName("label_12")

343 self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_12)

344 self.delayLineSlider = QtWidgets.QSlider(self.widget1)

345 self.delayLineSlider.setMaximum(300)

346 self.delayLineSlider.setSliderPosition(1)

347 self.delayLineSlider.setOrientation(QtCore.Qt.Vertical)

348 self.delayLineSlider.setObjectName("delayLineSlider")

349 self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole,

↪→ self.delayLineSlider)

350 self.delayLinespinBox = QtWidgets.QSpinBox(self.widget1)

351 self.delayLinespinBox.setMaximum(300)

352 self.delayLinespinBox.setObjectName("delayLinespinBox")

353 self.formLayout.setWidget(2, QtWidgets.QFormLayout.SpanningRole,

↪→ self.delayLinespinBox)

354 self.widget2 = QtWidgets.QWidget(self.centralwidget)

355 self.widget2.setGeometry(QtCore.QRect(1030, 80, 141, 51))

356 self.widget2.setObjectName("widget2")

357 self.formLayout_2 = QtWidgets.QFormLayout(self.widget2)

358 self.formLayout_2.setContentsMargins(0, 0, 0, 0)

359 self.formLayout_2.setObjectName("formLayout_2")

360 self.label_13 = QtWidgets.QLabel(self.widget2)

361 self.label_13.setObjectName("label_13")

362 self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole,

↪→ self.label_13)

363 self.lineEdit = QtWidgets.QLineEdit(self.widget2)

364 self.lineEdit.setObjectName("lineEdit")

365 self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.SpanningRole,

↪→ self.lineEdit)

Dinamicka obrada audio signala 58

Page 67: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

366 MainWindow.setCentralWidget(self.centralwidget)

367 self.menubar = QtWidgets.QMenuBar(MainWindow)

368 self.menubar.setGeometry(QtCore.QRect(0, 0, 1191, 17))

369 self.menubar.setObjectName("menubar")

370 self.menu_File = QtWidgets.QMenu(self.menubar)

371 self.menu_File.setObjectName("menu_File")

372 self.menu_Run = QtWidgets.QMenu(self.menubar)

373 self.menu_Run.setObjectName("menu_Run")

374 MainWindow.setMenuBar(self.menubar)

375 self.statusbar = QtWidgets.QStatusBar(MainWindow)

376 self.statusbar.setObjectName("statusbar")

377 MainWindow.setStatusBar(self.statusbar)

378 self.toolBar = QtWidgets.QToolBar(MainWindow)

379 self.toolBar.setObjectName("toolBar")

380 MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)

381 self.action_Open = QtWidgets.QAction(MainWindow)

382 self.action_Open.setObjectName("action_Open")

383 self.action_Exit = QtWidgets.QAction(MainWindow)

384 self.action_Exit.setObjectName("action_Exit")

385 self.action_Play = QtWidgets.QAction(MainWindow)

386 self.action_Play.setObjectName("action_Play")

387 self.action_Stop = QtWidgets.QAction(MainWindow)

388 self.action_Stop.setObjectName("action_Stop")

389 self.actionSave_Plot_Data = QtWidgets.QAction(MainWindow)

390 self.actionSave_Plot_Data.setObjectName("actionSave_Plot_Data")

391 #self.actionPlay_in_Loop = QtWidgets.QAction(MainWindow)

392 #self.actionPlay_in_Loop.setObjectName("actionPlay_in_Loop")

393 self.action_Save_Plot_Data = QtWidgets.QAction(MainWindow)

394 self.action_Save_Plot_Data.setObjectName("action_Save_Plot_Data")

395 self.actionExit = QtWidgets.QAction(MainWindow)

396 self.actionExit.setObjectName("actionExit")

397 self.menu_File.addAction(self.action_Open)

398 self.menu_File.addSeparator()

399 self.menu_File.addAction(self.actionSave_Plot_Data)

400 self.menu_File.addSeparator()

401 self.menu_File.addAction(self.action_Save_Plot_Data)

402 self.menu_File.addSeparator()

403 self.menu_File.addAction(self.actionExit)

404 self.menu_File.addSeparator()

Dinamicka obrada audio signala 59

Page 68: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

405 self.menu_Run.addAction(self.action_Play)

406 self.menu_Run.addSeparator()

407 #self.menu_Run.addAction(self.actionPlay_in_Loop)

408 #self.menu_Run.addSeparator()

409 self.menu_Run.addAction(self.action_Stop)

410 self.menu_Run.addSeparator()

411 self.menu_Run.addSeparator()

412 self.menubar.addAction(self.menu_File.menuAction())

413 self.menubar.addAction(self.menu_Run.menuAction())

414

415 self.retranslateUi(MainWindow)

416

417 self.detGainDial.valueChanged[’int’].connect(self.detGainspinBox.setValue)

418 self.detGainspinBox.valueChanged[’int’].connect(self.detGainDial.setValue)

419 self.detGainDial.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedInputGain(self.detGainDial.value()))

420

421 self.outputGainDial.valueChanged[’int’].connect(self.outGainspinBox.setValue)

422 self.outGainspinBox.valueChanged[’int’].connect(self.outputGainDial.setValue)

423 self.outputGainDial.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedOutputGain(self.outputGainDial.value()))

424

425 self.thresholdSlider.valueChanged[’int’].connect(self.thresholdSpinBox.setValue)

426 self.thresholdSpinBox.valueChanged[’int’].connect(self.thresholdSlider.setValue)

427 self.thresholdSlider.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedThreshold(self.thresholdSlider.value()))

428

429 self.attackSlider.valueChanged[’int’].connect(self.attackSpinBox.setValue)

430 self.attackSpinBox.valueChanged[’int’].connect(self.attackSlider.setValue)

431 self.attackSlider.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedAttackTimeMs(self.attackSlider.value()))

432

433 self.releaseSlider.valueChanged[’int’].connect(self.releaseSpinBox.setValue)

434 self.releaseSpinBox.valueChanged[’int’].connect(self.releaseSlider.setValue)

435 self.releaseSlider.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedReleaseTimeMs(self.releaseSlider.value()))

436

437 self.ratioSlider.valueChanged[’int’].connect(self.ratioSpinBox.setValue)

438 self.ratioSpinBox.valueChanged[’int’].connect(self.ratioSlider.setValue)

Dinamicka obrada audio signala 60

Page 69: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

439 self.ratioSlider.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedRatio(self.ratioSlider.value()))

440

441 self.kneeSlider.valueChanged[’int’].connect(self.kneeWidthSpinBox.setValue)

442 self.kneeWidthSpinBox.valueChanged[’int’].connect(self.kneeSlider.setValue)

443 self.kneeSlider.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedKneeWidth(self.kneeSlider.value()))

444

445 self.delayLineSlider.valueChanged[’int’].connect(self.delayLinespinBox.setValue)

446 self.delayLinespinBox.valueChanged[’int’].connect(self.delayLineSlider.setValue)

447 self.delayLineSlider.valueChanged[’int’].connect(lambda:

↪→ self.dynamicProcessor.userChangedDelayLine(self.delayLineSlider.value()))

448

449 self.timeConstComboBox.activated.connect(self.connectTimeConstant)

450 self.processorComboBox.activated.connect(self.connectProcessorType)

451 self.detectionTypeComboBox.activated.connect(self.connectDetectionType)

452

453 self.action_Open.triggered.connect(self.actionOpenFile)

454 self.actionSave_Plot_Data.triggered.connect(self.closeFile)

455 self.action_Save_Plot_Data.triggered.connect(lambda:

↪→ self.widget.savePlotsToFile(self.detGainDial.value(),

↪→ self.streamCompleted))

456 self.actionExit.triggered.connect(self.exitApp)

457 self.action_Play.triggered.connect(self.actionPlay)

458 #self.actionPlay_in_Loop.triggered.connect(self.playLoop)

459 self.action_Stop.triggered.connect(self.closeStream)

460

461 QtCore.QMetaObject.connectSlotsByName(MainWindow)

462

463 def connectTimeConstant(self):

464 if self.timeConstComboBox.currentText() == ’Digital’:

465 self.dynamicProcessor.userChangedTimeConstant(TimeConstant.Digital.value)

466 elif self.timeConstComboBox.currentText() == ’Analog’:

467 self.dynamicProcessor.userChangedTimeConstant(TimeConstant.Analog.value)

468 print(self.dynamicProcessor.getTimeConstant())

469

470 def connectProcessorType(self):

471 if self.processorComboBox.currentText() == ’COMPRESSOR’:

472 self.dynamicProcessor.userChangedProcessorType(ProcessorType.COMPRESSOR.value)

Dinamicka obrada audio signala 61

Page 70: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

473 elif self.processorComboBox.currentText() == ’LIMITER’:

474 self.dynamicProcessor.userChangedProcessorType(ProcessorType.LIMITER.value)

475 elif self.processorComboBox.currentText() == ’EXPANDER’:

476 self.dynamicProcessor.userChangedProcessorType(ProcessorType.EXPANDER.value)

477 elif self.processorComboBox.currentText() == ’GATE’:

478 self.dynamicProcessor.userChangedProcessorType(ProcessorType.NOISE_GATE.value)

479 print(self.dynamicProcessor.getProcessorType())

480

481 def connectDetectionType(self):

482 if self.detectionTypeComboBox.currentText() == ’DETECT_PEAK_VALUE’:

483 self.dynamicProcessor.userChangedDetectionType(DetectionType.DETECT_PEAK_VALUE.value)

484 elif self.detectionTypeComboBox.currentText() == ’DETECT_MEAN_SQUARE’:

485 self.dynamicProcessor.userChangedDetectionType(DetectionType.DETECT_MEAN_SQUARE.value)

486 elif self.detectionTypeComboBox.currentText() == ’DETECT_RMS’:

487 self.dynamicProcessor.userChangedDetectionType(DetectionType.DETECT_RMS.value)

488 print(self.dynamicProcessor.getDetectionType())

489

490

491 def actionOpenFile(self):

492 self.errorMsg = QtWidgets.QErrorMessage()

493 name = QtGui.QFileDialog.getOpenFileName(self, ’Load a WAV file’,

↪→ "*.wav")[0]

494 if name:

495 self.waveFile = wave.open(name, ’rb’)

496 if self.waveFile.getsampwidth() != 2 or self.waveFile.getcomptype() !=

↪→ ’NONE’:

497 self.errorMsg.showMessage(’Application does not support this format

↪→ or compression type’)

498 self.waveFile.close()

499 else:

500 self.numChannels, self.sampleWidth, self.frameRate, self.numFrames,

↪→ self.compType, self.compName = \

501 self.waveFile.getparams()

502 self.fileLoaded = True

503 self.lineEdit.setText(name)

504 self.clearPlotData()

505 else:

506 self.doNothing()

507

Dinamicka obrada audio signala 62

Page 71: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

508 def doNothing(self):

509 pass

510

511 def closeFile(self):

512 if self.fileLoaded == True:

513 self.waveFile.close()

514 self.lineEdit.setText("")

515 else:

516 self.doNothing()

517

518 def exitApp(self):

519 qApp.exit()

520

521 def retranslateUi(self, MainWindow):

522 _translate = QtCore.QCoreApplication.translate

523 MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

524 self.label.setText(_translate("MainWindow", "Input Gain / dB"))

525 self.label_2.setText(_translate("MainWindow", "Threshold / dB"))

526 self.label_3.setText(_translate("MainWindow", "Attack Time / ms"))

527 self.label_4.setText(_translate("MainWindow", "Release Time / ms"))

528 self.label_5.setText(_translate("MainWindow", "Ratio"))

529 self.label_6.setText(_translate("MainWindow", "Output Gain / dB"))

530 self.label_7.setText(_translate("MainWindow", "Knee Width / dB"))

531 self.timeConstComboBox.setItemText(0, _translate("MainWindow", "Digital"))

532 self.timeConstComboBox.setItemText(1, _translate("MainWindow", "Analog"))

533 self.label_9.setText(_translate("MainWindow", "Time constant"))

534 self.label_8.setText(_translate("MainWindow", "Processor"))

535 self.processorComboBox.setItemText(0, _translate("MainWindow",

↪→ "COMPRESSOR"))

536 self.processorComboBox.setItemText(1, _translate("MainWindow", "LIMITER"))

537 self.processorComboBox.setItemText(2, _translate("MainWindow", "EXPANDER"))

538 self.processorComboBox.setItemText(3, _translate("MainWindow", "GATE"))

539 self.detectionTypeComboBox.setItemText(0, _translate("MainWindow",

↪→ "DETECT_PEAK_VALUE"))

540 self.detectionTypeComboBox.setItemText(1, _translate("MainWindow",

↪→ "DETECT_MEAN_SQUARE"))

541 self.detectionTypeComboBox.setItemText(2, _translate("MainWindow",

↪→ "DETECT_RMS"))

542 self.label_10.setText(_translate("MainWindow", "Detection Type"))

Dinamicka obrada audio signala 63

Page 72: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

543 self.label_12.setText(_translate("MainWindow", "Delay Line / ms"))

544 self.label_13.setText(_translate("MainWindow", "Loaded File:"))

545 self.menu_File.setTitle(_translate("MainWindow", "&File"))

546 self.menu_Run.setTitle(_translate("MainWindow", "&Run"))

547 self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))

548 self.action_Open.setText(_translate("MainWindow", "&Import WAV File"))

549 self.action_Exit.setText(_translate("MainWindow", "&Exit"))

550 self.action_Play.setText(_translate("MainWindow", "&Play"))

551 self.action_Stop.setText(_translate("MainWindow", "&Stop"))

552 self.actionSave_Plot_Data.setText(_translate("MainWindow", "&Close WAV

↪→ File"))

553 #self.actionPlay_in_Loop.setText(_translate("MainWindow", "Play in Loop"))

554 self.action_Save_Plot_Data.setText(_translate("MainWindow", "&Plot Data"))

555 self.actionExit.setText(_translate("MainWindow", "&Exit"))

556

557 def actionPlay(self):

558 if self.fileLoaded == False:

559 self.actionOpenFile()

560 else:

561 self.waveFile.rewind()

562

563 if self.fileLoaded == False:

564 pass

565 else:

566 self.callPlay()

567

568 def closeStream(self):

569 if self.callPlayCalled == True:

570 self.stream.stop_stream()

571 self.stream.close()

572 self.p.terminate()

573 self.playInLoop = False

574 self.callPlayCalled = False

575 self.streamCompleted = True

576 else:

577 pass

578

579 def timeConstEnumToInt(self):

580 if self.timeConstComboBox.currentText() == ’Digital’:

Dinamicka obrada audio signala 64

Page 73: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

581 return TimeConstant.Digital.value

582 else:

583 return TimeConstant.Analog.value

584

585 def processorTypeEnumtoInt(self):

586 if self.processorComboBox.currentText() == ’COMPRESSOR’:

587 return ProcessorType.COMPRESSOR.value

588 elif self.processorComboBox.currentText() == ’LIMITER’:

589 return ProcessorType.LIMITER.value

590 elif self.processorComboBox.currentText() == ’EXPANDER’:

591 return ProcessorType.EXPANDER.value

592 elif self.processorComboBox.currentText() == ’GATE’:

593 return ProcessorType.NOISE_GATE.value

594

595 def detectionTypeToInt(self):

596 if self.detectionTypeComboBox.currentText() == ’DETECT_PEAK_VALUE’:

597 return DetectionType.DETECT_PEAK_VALUE.value

598 elif self.detectionTypeComboBox.currentText() == ’DETECT_MEAN_SQUARE’:

599 return DetectionType.DETECT_MEAN_SQUARE.value

600 elif self.detectionTypeComboBox.currentText() == ’DETECT_RMS’:

601 return DetectionType.DETECT_RMS.value

602

603 def clearPlotData(self):

604 self.widget.clearPlotData()

605

606 def callPlay(self):

607 self.waveFile.rewind()

608 self.clearPlotData()

609 self.streamCompleted = False

610 self.callPlayCalled = True

611 self.dynamicProcessor.initialize(self.detGainDial.value(),

612 self.outputGainDial.value(),

613 self.thresholdSlider.value(),

614 self.attackSlider.value(),

615 self.releaseSlider.value(),

616 self.ratioSlider.value(),

617 self.kneeSlider.value(),

618 self.frameRate,

619 self.delayLineSlider.value(),

Dinamicka obrada audio signala 65

Page 74: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

620 self.timeConstEnumToInt(),

621 self.processorTypeEnumtoInt(),

622 self.detectionTypeToInt())

623

624 self.dynamicProcessor.prepareForPlay()

625

626 self.p = pyaudio.PyAudio()

627 self.stream =

↪→ self.p.open(format=self.p.get_format_from_width(self.waveFile.getsampwidth()),

628 channels=self.numChannels,

629 rate=self.frameRate,

630 output=True,

631 frames_per_buffer=1024,

632 stream_callback=self.audioCallback)

633 self.streamStart = True

634 self.stream.start_stream()

635

636 def loopPlay(self):

637 while isPlaying:

638 self.callPlay()

639

640 def playLoop(self):

641 global isPlaying

642 global loopThread

643

644 if not isPlaying:

645 isPlaying = True

646 loopThread = threading.Thread(target=self.loopPlay())

647 loopThread.start()

648

649 def audioCallback(self, in_data, frame_count, time_info, flag):

650 data = self.waveFile.readframes(frame_count)

651 data = np.frombuffer(data, dtype=np.int16)

652 self.widget.captureAddData(data / 32768.0, ’Signal’)

653

654 outData = np.zeros(data.size, dtype=np.float32)

655 if self.dynamicProcessor.processAudioFrame(data.astype(np.float32),

↪→ outData) == False:

656 outData = data

Dinamicka obrada audio signala 66

Page 75: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG A. Programski kod grafickog korisnickog sucelja - Python

657

658 dataPlot = outData

659 self.widget.captureAddData(dataPlot, ’DSP’)

660

661 if self.waveFile.getnframes() == self.waveFile.tell():

662 self.streamCompleted = True

663 outData = outData.astype(np.int16)

664

665 return (outData.tobytes(), pyaudio.paContinue)

666

667 if __name__ == "__main__":

668 import sys

669 app = QtWidgets.QApplication(sys.argv)

670 MainWindow = QtWidgets.QMainWindow()

671 ui = Ui_MainWindow()

672 ui.setupUi(MainWindow)

673 MainWindow.setWindowTitle("Dynamic Signal Processor")

674 MainWindow.show()

675 sys.exit(app.exec_())

Dinamicka obrada audio signala 67

Page 76: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG B. Programski kod detektora razine signala - C++

PRILOG B

Programski kod detektora razine

signala - C++

U nastavku se nalazi definicija klase EnvelopeFollower.

1 #ifndef ENVELOPEFOLLOWER_H

2 #define ENVELOPEFOLLOWER_H

3

4 #define FLT_MIN_POS 1.175494351e-38

5 #define FLT_MIN_NEG -1.175494351e-38

6

7 const float TC_ANALOG = -1.00239343;

8 const float TC_DIGITAL = -4.60517018;

9

10 class EnvelopeFollower

11 {

12 public:

13 EnvelopeFollower();

14 ~EnvelopeFollower();

15 public:

16 void init(float sample_rate, float attack_time, float release_time,

17 int detection_type, bool analog_time_const, bool log_detector);

18 void setSampleRate(float sample_rate);

19 void setAttackTime(float attack_time);

20 void setReleaseTime(float release_time);

21 void setDetectionType(int detection_type);

22 void setTimeConstant(bool analog_time_const);

23 void setLogDetector(bool log_detector);

24 float detectEnvelope(float sample);

Dinamicka obrada audio signala 68

Page 77: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG B. Programski kod detektora razine signala - C++

25

26 float getSampleRate(void);

27 float getAttackTimeMs(void);

28 float getAttackTime(void);

29 float getReleaseTimeMs(void);

30 float getReleaseTime(void);

31 float getEnvelopeValue(void);

32 int getDetectionType(void);

33 bool getAnalogTimeConstant(void);

34 bool getLogDetector(void);

35 private:

36 float sampleRate;

37 float attackTimeMs;

38 float attackTime;

39 float releaseTimeMs;

40 float releaseTime;

41 float envelopeValue;

42

43 int detectionType;

44 int nSample;

45

46 bool analogTimeConst;

47 bool logDetector;

48 };

49

50 #endif // ENVELOPEFOLLOWER_H

U nastavku se nalazi implementacija klase EnvelopeFollower.

1 #include "envelopefollower.h"

2

3 #include <cmath>

4

5 EnvelopeFollower::EnvelopeFollower()

6 {

7 sampleRate = 44100.0;

8 attackTimeMs = 0.0;

9 attackTime = 0.0;

10 releaseTimeMs = 0.0;

Dinamicka obrada audio signala 69

Page 78: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG B. Programski kod detektora razine signala - C++

11 releaseTime = 0.0;

12 envelopeValue = 0.0;

13

14 detectionType = 0;

15 nSample = 0;

16

17 analogTimeConst = false;

18 logDetector = false;

19 }

20

21 EnvelopeFollower::~EnvelopeFollower()

22 {

23 }

24

25 void EnvelopeFollower::init(float sample_rate, float attack_time, float

↪→ release_time,

26 int detection_type, bool analog_time_const, bool log_detector)

27 {

28 sampleRate = sample_rate;

29 attackTimeMs = attack_time;

30 releaseTimeMs = release_time;

31 envelopeValue = 0.0;

32

33 detectionType = detection_type;

34

35 analogTimeConst = analog_time_const;

36 logDetector = log_detector;

37

38 setAttackTime(attackTimeMs);

39 setReleaseTime(releaseTimeMs);

40 }

41

42 void EnvelopeFollower::setSampleRate(float sample_rate)

43 {

44 sampleRate = sample_rate;

45 }

46

47 void EnvelopeFollower::setAttackTime(float attack_time)

48 {

Dinamicka obrada audio signala 70

Page 79: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG B. Programski kod detektora razine signala - C++

49 attackTimeMs = attack_time;

50

51 if (analogTimeConst)

52 attackTime = exp(TC_ANALOG/(attackTimeMs * sampleRate * 0.001));

53 else

54 attackTime = exp(TC_DIGITAL/(attackTimeMs * sampleRate * 0.001));

55 }

56

57 void EnvelopeFollower::setReleaseTime(float release_time)

58 {

59 releaseTimeMs = release_time;

60

61 if (analogTimeConst)

62 releaseTime = exp(TC_ANALOG/(releaseTimeMs * sampleRate * 0.001));

63 else

64 releaseTime = exp(TC_DIGITAL/(releaseTimeMs * sampleRate * 0.001));

65 }

66

67 void EnvelopeFollower::setDetectionType(int detection_type)

68 {

69 detectionType = detection_type;

70 }

71

72 void EnvelopeFollower::setTimeConstant(bool analog_time_const)

73 {

74 analogTimeConst = analog_time_const;

75

76 setAttackTime(attackTimeMs);

77 setReleaseTime(releaseTimeMs);

78 }

79

80 void EnvelopeFollower::setLogDetector(bool log_detector)

81 {

82 logDetector = log_detector;

83 }

84

85 float EnvelopeFollower::detectEnvelope(float sample)

86 {

87 switch(detectionType)

Dinamicka obrada audio signala 71

Page 80: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG B. Programski kod detektora razine signala - C++

88 {

89 case 0:

90 sample = fabs(sample);

91 break;

92 case 1:

93 case 2:

94 sample = fabs(sample) * fabs(sample);

95 break;

96 default:

97 break;

98 }

99

100 float currentEnvelope = 0.0;

101 if (sample > envelopeValue)

102 currentEnvelope = (envelopeValue - sample) * attackTime + sample;

103 else

104 currentEnvelope = (envelopeValue - sample) * releaseTime + sample;

105

106 if (currentEnvelope > 0.0 && currentEnvelope < FLT_MIN_POS)

107 currentEnvelope = 0.0;

108 if (currentEnvelope < 0.0 && currentEnvelope > FLT_MIN_NEG)

109 currentEnvelope = 0.0;

110

111 currentEnvelope = fmin(currentEnvelope, (float)1.0);

112 currentEnvelope = fmax(currentEnvelope, (float)0.0);

113

114 envelopeValue = currentEnvelope;

115

116 if (detectionType == 2)

117 currentEnvelope = pow(currentEnvelope, (float)0.5);

118

119 if (logDetector)

120 {

121 if (currentEnvelope <= 0)

122 return -96.0;

123

124 return 20*log10(currentEnvelope);

125 }

126

Dinamicka obrada audio signala 72

Page 81: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG B. Programski kod detektora razine signala - C++

127 return currentEnvelope;

128 }

129

130 float EnvelopeFollower::getSampleRate()

131 {

132 return sampleRate;

133 }

134

135 float EnvelopeFollower::getAttackTimeMs()

136 {

137 return attackTimeMs;

138 }

139

140 float EnvelopeFollower::getAttackTime()

141 {

142 return attackTime;

143 }

144

145 float EnvelopeFollower::getReleaseTimeMs()

146 {

147 return releaseTimeMs;

148 }

149

150 float EnvelopeFollower::getReleaseTime()

151 {

152 return releaseTime;

153 }

154

155 float EnvelopeFollower::getEnvelopeValue()

156 {

157 return envelopeValue;

158 }

159

160 int EnvelopeFollower::getDetectionType()

161 {

162 return detectionType;

163 }

164

165 bool EnvelopeFollower::getAnalogTimeConstant()

Dinamicka obrada audio signala 73

Page 82: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG B. Programski kod detektora razine signala - C++

166 {

167 return analogTimeConst;

168 }

169

170 bool EnvelopeFollower::getLogDetector()

171 {

172 return logDetector;

173 }

Dinamicka obrada audio signala 74

Page 83: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

PRILOG C

Programski kod dinamickog procesora

- C++

U nastavku se nalazi definicija klase DynamicProcessor.

1 #ifndef DYNAMICPROCESSOR_H

2 #define DYNAMICPROCESSOR_H

3

4 #include "envelopefollower.h"

5

6 #include <stdlib.h>

7

8 #define INT_MAX_VALUE 32768

9

10 enum TimeConstant

11 {

12 Digital = 0,

13 Analog

14 };

15

16 enum ProcessorType

17 {

18 COMPRESSOR = 0,

19 LIMITER,

20 EXPANDER,

21 NOISE_GATE

22 };

23

24 enum DetectionType

Dinamicka obrada audio signala 75

Page 84: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

25 {

26 DETECT_PEAK_VALUE = 0,

27 DETECT_MEAN_SQUARE,

28 DETECT_RMS

29 };

30

31 class DynamicProcessor

32 {

33 public:

34 DynamicProcessor();

35 ~DynamicProcessor();

36 public:

37 bool prepareForPlay(void);

38 bool processAudioFrame(float *inData, int size, float *outData);

39 bool normalizeInputData(float *inData, int size);

40 bool denormalizeOutputData(float *outputData, int size);

41 float calculateCompressorGain(float envelopeValue, float threshold_level, float

↪→ ratio_level, float knee_width, bool limiter);

42 float calculateExpanderGain(float envelopeValue, float threshold_level, float

↪→ ratio_level, float knee_width, bool noise_gate);

43 double lagrangeInterpolate(double *x, double *y, int n, double xbar);

44 void initialize(float input_gain, float output_gain, float threshold_level,

↪→ float attack_time_ms,

45 float release_time_ms, float ratio_level, float knee_width, float

↪→ sample_rate, float delay_line,

46 TimeConstant time_constant, ProcessorType processor_type, DetectionType

↪→ detection_type);

47

48 void userChangedInputGain(float input_gain);

49 void userChangedOutputGain(float output_gain);

50 void userChangedThreshold(float threshold_level);

51 void userChangedAttackTimeMs(float attack_time_ms);

52 void userChangedReleaseTimeMs(float release_time_ms);

53 void userChangedRatio(float ratio_level);

54 void userChangedKneeWidth(float knee_width);

55 void userChangedDelayLine(float delay_line);

56 void userChangedTimeConstant(TimeConstant time_const);

57 void userChangedProcessorType(ProcessorType processor_type);

58 void userChangedDetectionType(DetectionType detection_type);

Dinamicka obrada audio signala 76

Page 85: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

59

60 float getInputGain(void);

61 float getOutputGain(void);

62 float getThreshold(void);

63 float getAttackTimeMs(void);

64 float getReleaseTimeMs(void);

65 float getRatio(void);

66 float getKneeWidth(void);

67 float getDelayLine(void);

68 float getSampleRate(void);

69 int getTimeConstant(void);

70 int getProcessorType(void);

71 int getDetectionType(void);

72

73 bool cmpChannelSettings(void);

74 float getEnvelopeValueLeftChannel(void);

75 float getEnvelopeValueRightChannel(void);

76

77 EnvelopeFollower leftEnvelopeFollower;

78 EnvelopeFollower rightEnvelopeFollower;

79 public:

80 float sampleRate;

81 float inputGain;

82 float outputGain;

83 float threshold;

84 float releaseTimeMs;

85 float attackTimeMs;

86 float ratio;

87 float kneeWidth;

88 float delayLine;

89

90 ProcessorType processorType;

91 TimeConstant timeConst;

92

93 DetectionType detectionType;

94 };

95

96 #endif // DYNAMICPROCESSOR_H

Dinamicka obrada audio signala 77

Page 86: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

U nastavku se nalazi implementacija klase DynamicProcessor.

1 #include "dynamicprocessor.h"

2

3 #include <cmath>

4 #include <algorithm>

5

6 #ifndef min

7 #define min(a,b) (((a) < (b)) ? (a) : (b))

8 #endif

9

10 DynamicProcessor::DynamicProcessor()

11 {

12 sampleRate = 0.0;

13 inputGain = 0.0;

14 outputGain = 0.0;

15 threshold = 0.0;

16 attackTimeMs = 0.0;

17 releaseTimeMs = 0.0;

18 ratio = 0.0;

19 kneeWidth = 0.0;

20 delayLine = 0.0;

21

22 timeConst = Digital;

23 processorType = COMPRESSOR;

24 detectionType = DETECT_PEAK_VALUE;

25 }

26

27 DynamicProcessor::~DynamicProcessor()

28 {

29 }

30

31 void DynamicProcessor::initialize(float input_gain, float output_gain, float

↪→ threshold_level, float attack_time_ms, float release_time_ms, float

↪→ ratio_level, float knee_width, float sample_rate, float delay_line,

↪→ TimeConstant time_constant, ProcessorType processor_type, DetectionType

↪→ detection_type)

32 {

Dinamicka obrada audio signala 78

Page 87: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

33 inputGain = input_gain;

34 outputGain = output_gain;

35 threshold = threshold_level;

36 attackTimeMs = attack_time_ms;

37 releaseTimeMs = release_time_ms;

38 ratio = ratio_level;

39 kneeWidth = knee_width;

40 sampleRate = sample_rate;

41 delayLine = delay_line;

42

43 timeConst = time_constant;

44 processorType = processor_type;

45 detectionType = detection_type;

46 }

47

48 bool DynamicProcessor::prepareForPlay(void)

49 {

50 if (timeConst == Analog)

51 {

52 leftEnvelopeFollower.init(sampleRate, attackTimeMs, releaseTimeMs,

↪→ detectionType, true, true);

53 rightEnvelopeFollower.init(sampleRate, attackTimeMs, releaseTimeMs,

↪→ detectionType, true, true);

54 }

55 else

56 {

57 leftEnvelopeFollower.init(sampleRate, attackTimeMs, releaseTimeMs,

↪→ detectionType, false, true);

58 rightEnvelopeFollower.init(sampleRate, attackTimeMs, releaseTimeMs,

↪→ detectionType, false, true);

59 }

60

61 return true;

62 }

63

64 bool DynamicProcessor::normalizeInputData(float *inData, int size)

65 {

66 for (int i = 0; i < size; i++)

67 inData[i] /= INT_MAX_VALUE;

Dinamicka obrada audio signala 79

Page 88: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

68

69 return true;

70 }

71

72 bool DynamicProcessor::denormalizeOutputData(float *outputData, int size)

73 {

74 for (int i = 0;i < size; i++)

75 outputData[i] *= INT_MAX_VALUE;

76

77 return true;

78 }

79

80 double DynamicProcessor::lagrangeInterpolate(double *x, double *y, int n, double

↪→ xbar)

81 {

82 double fx = 0.0;

83 double l = 1.0;

84

85 for (int i = 0; i < n; i++)

86 {

87 l = 1.0;

88 for (int j = 0; j < n; j++)

89 {

90 if (i != j)

91 l = (xbar-x[j])/(x[i]-x[j]);

92 }

93 fx += l*y[i];

94 }

95 return fx;

96 }

97

98 float DynamicProcessor::calculateCompressorGain(float envelopeValue, float

↪→ threshold_level, float ratio_level, float knee_width, bool limiter)

99 {

100 float compressorSlope = 1.0 - (1.0 / ratio);

101

102 if (limiter)

103 compressorSlope = 1.0;

104

Dinamicka obrada audio signala 80

Page 89: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

105 if (knee_width > 0 && envelopeValue > (threshold_level - knee_width / 2.0) &&

↪→ envelopeValue < (threshold_level + knee_width / 2.0))

106 {

107 double x[2];

108 double y[2];

109 x[0] = threshold_level - (knee_width / 2.0);

110 x[1] = threshold_level + (knee_width / 2.0);

111 y[0] = min(0, x[1]);

112 y[1] = compressorSlope;

113

114 compressorSlope = lagrangeInterpolate(&x[0], &x[1], 2, envelopeValue);

115 }

116 float gain = compressorSlope * (threshold_level - envelopeValue);

117

118 gain = min(0, gain);

119

120 return pow(10.0, gain / 20.0);

121 }

122

123 float DynamicProcessor::calculateExpanderGain(float envelopeValue, float

↪→ threshold_level, float ratio_level, float knee_width, bool noise_gate)

124 {

125 float expanderSlope = (1.0 / ratio_level) - 1.0;

126

127 if (noise_gate)

128 expanderSlope = -1.0;

129

130 if (knee_width > 0 && envelopeValue > (threshold_level - knee_width / 2.0) &&

↪→ envelopeValue < (threshold_level + knee_width / 2.0))

131 {

132 double x[2];

133 double y[2];

134 x[0] = threshold_level - (knee_width / 2.0);

135 x[1] = threshold_level + (knee_width / 2.0);

136 x[1] = min(0, x[1]);

137 y[0] = expanderSlope;

138 y[1] = 0;

139

140 expanderSlope = lagrangeInterpolate(&x[0], &x[1], 2, envelopeValue);

Dinamicka obrada audio signala 81

Page 90: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

141 }

142

143 float gain = expanderSlope * (threshold_level - envelopeValue);

144

145 gain = min(0, gain);

146

147 return pow(10.0, gain / 20.0);

148 }

149

150 bool DynamicProcessor::processAudioFrame(float *inData, int size, float *outData)

151 {

152 float inputGainLin = pow(10.0, inputGain / 20.0);

153 float outputGainLin = pow(10.0, outputGain / 20.0);

154

155 float envelopeValue;

156

157 float gain = 1.0;

158

159 if (!normalizeInputData(&inData[0], size))

160 return false;

161

162 for (int i = 0; i < size; i++)

163 {

164 gain = 1.0;

165

166 if (i % 2)

167 envelopeValue = rightEnvelopeFollower.detectEnvelope(inData[i] *

↪→ inputGainLin);

168 else

169 envelopeValue = leftEnvelopeFollower.detectEnvelope(inData[i] *

↪→ inputGainLin);

170

171 if (processorType == COMPRESSOR)

172 gain = calculateCompressorGain(envelopeValue, threshold, ratio, kneeWidth,

↪→ false);

173 else if (processorType == LIMITER)

174 gain = calculateCompressorGain(envelopeValue, threshold, ratio, kneeWidth,

↪→ true);

175 else if (processorType == EXPANDER)

Dinamicka obrada audio signala 82

Page 91: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

176 gain = calculateExpanderGain(envelopeValue, threshold, ratio, kneeWidth,

↪→ false);

177 else if (processorType == NOISE_GATE)

178 gain = calculateExpanderGain(envelopeValue, threshold, ratio, kneeWidth,

↪→ true);

179

180 outData[i] = gain * inData[i] * outputGainLin;

181 }

182 if (!denormalizeOutputData(&outData[0], size))

183 return false;

184

185 return true;

186 }

187

188 /*------------------------------------------------------------------------------

189 * Functions to update parameters when user changes control interface

190 * ----------------------------------------------------------------------------*/

191 void DynamicProcessor::userChangedInputGain(float input_gain)

192 {

193 inputGain = input_gain;

194 }

195

196 void DynamicProcessor::userChangedOutputGain(float output_gain)

197 {

198 outputGain = output_gain;

199 }

200

201 void DynamicProcessor::userChangedThreshold(float threshold_level)

202 {

203 threshold = threshold_level;

204 }

205

206 void DynamicProcessor::userChangedAttackTimeMs(float attack_time_ms)

207 {

208 attackTimeMs = attack_time_ms;

209

210 leftEnvelopeFollower.setAttackTime(attackTimeMs);

211 rightEnvelopeFollower.setAttackTime(attackTimeMs);

212 }

Dinamicka obrada audio signala 83

Page 92: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

213

214 void DynamicProcessor::userChangedReleaseTimeMs(float release_time_ms)

215 {

216 releaseTimeMs = release_time_ms;

217

218 leftEnvelopeFollower.setReleaseTime(releaseTimeMs);

219 rightEnvelopeFollower.setReleaseTime(releaseTimeMs);

220 }

221

222 void DynamicProcessor::userChangedRatio(float ratio_level)

223 {

224 ratio = ratio_level;

225 }

226

227 void DynamicProcessor::userChangedKneeWidth(float knee_width)

228 {

229 kneeWidth = knee_width;

230 }

231

232 void DynamicProcessor::userChangedDelayLine(float delay_line)

233 {

234 delayLine = delay_line;

235 }

236

237 void DynamicProcessor::userChangedTimeConstant(TimeConstant time_const)

238 {

239 timeConst = time_const;

240

241 if (timeConst == Digital)

242 {

243 leftEnvelopeFollower.setTimeConstant(false);

244 rightEnvelopeFollower.setTimeConstant(false);

245 }

246 else if (timeConst == Analog)

247 {

248 leftEnvelopeFollower.setTimeConstant(true);

249 rightEnvelopeFollower.setTimeConstant(true);

250 }

251 }

Dinamicka obrada audio signala 84

Page 93: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

252

253 void DynamicProcessor::userChangedProcessorType(ProcessorType processor_type)

254 {

255 processorType = processor_type;

256 }

257

258 void DynamicProcessor::userChangedDetectionType(DetectionType detection_type)

259 {

260 detectionType = detection_type;

261 }

262

263 /*------------------------------------------------------------------------------

264 * Functions for debugging DynamicProcessor class

265 * ----------------------------------------------------------------------------*/

266 float DynamicProcessor::getInputGain()

267 {

268 return inputGain;

269 }

270

271 float DynamicProcessor::getOutputGain()

272 {

273 return outputGain;

274 }

275

276 float DynamicProcessor::getThreshold()

277 {

278 return threshold;

279 }

280

281 float DynamicProcessor::getAttackTimeMs()

282 {

283 return attackTimeMs;

284 }

285

286 float DynamicProcessor::getReleaseTimeMs()

287 {

288 return releaseTimeMs;

289 }

290

Dinamicka obrada audio signala 85

Page 94: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

291 float DynamicProcessor::getRatio()

292 {

293 return ratio;

294 }

295

296 float DynamicProcessor::getKneeWidth()

297 {

298 return kneeWidth;

299 }

300

301 float DynamicProcessor::getDelayLine()

302 {

303 return delayLine;

304 }

305

306 float DynamicProcessor::getSampleRate()

307 {

308 return sampleRate;

309 }

310

311 int DynamicProcessor::getTimeConstant()

312 {

313 return timeConst;

314 }

315

316 int DynamicProcessor::getProcessorType()

317 {

318 return processorType;

319 }

320

321 int DynamicProcessor::getDetectionType()

322 {

323 return detectionType;

324 }

325

326 /*------------------------------------------------------------------------------

327 * Functions to debugg Envelope Follower class

328 *

329 * funtions check if both channels are initialized correctly

Dinamicka obrada audio signala 86

Page 95: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

330 * ----------------------------------------------------------------------------*/

331 bool DynamicProcessor::cmpChannelSettings()

332 {

333 if (leftEnvelopeFollower.getSampleRate() !=

↪→ rightEnvelopeFollower.getSampleRate())

334 return false;

335

336 if (leftEnvelopeFollower.getAttackTime() !=

↪→ rightEnvelopeFollower.getAttackTime())

337 return false;

338

339 if (leftEnvelopeFollower.getAttackTimeMs() !=

↪→ rightEnvelopeFollower.getAttackTimeMs())

340 return false;

341

342 if (leftEnvelopeFollower.getReleaseTimeMs() !=

↪→ rightEnvelopeFollower.getReleaseTimeMs())

343 return false;

344

345 if (leftEnvelopeFollower.getReleaseTime() !=

↪→ rightEnvelopeFollower.getReleaseTime())

346 return false;

347

348 if (leftEnvelopeFollower.getDetectionType() !=

↪→ rightEnvelopeFollower.getDetectionType())

349 return false;

350

351 if (leftEnvelopeFollower.getAnalogTimeConstant() !=

↪→ rightEnvelopeFollower.getAnalogTimeConstant())

352 return false;

353

354 if (leftEnvelopeFollower.getLogDetector() !=

↪→ rightEnvelopeFollower.getLogDetector())

355 return false;

356

357 return true;

358 }

359

360 float DynamicProcessor::getEnvelopeValueLeftChannel()

Dinamicka obrada audio signala 87

Page 96: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG C. Programski kod dinamickog procesora - C++

361 {

362 return leftEnvelopeFollower.getEnvelopeValue();

363 }

364

365 float DynamicProcessor::getEnvelopeValueRightChannel()

366 {

367 return rightEnvelopeFollower.getEnvelopeValue();

368 }

Dinamicka obrada audio signala 88

Page 97: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG D. Cython wrapper funkcije za klasu EnvelopeFollower

PRILOG D

Cython wrapper funkcije za klasu

EnvelopeFollower

U nastavku se nalazi redefinicija klase EnvelopeFollower u Cython sintaksi.

1 #distutils: language = c++

2 #distutils: sources = envelopefollower.cpp

3

4 from libcpp cimport bool

5

6 cdef extern from "envelopefollower.h":

7 cdef cppclass EnvelopeFollower:

8 EnvelopeFollower()

9 void init(float, float, float, int, bool, bool)

10 void setSampleRate(float)

11 void setAttackTime(float)

12 void setReleaseTime(float)

13 void setDetectionType(int)

14 void setTimeConstant(bool)

15 void setLogDetector(bool)

16 float detectEnvelope(float)

17 float getSampleRate()

18 float getAttackTimeMs()

19 float getAttackTime()

20 float getReleaseTimeMs()

21 float getReleaseTime()

22 float getEnvelopeValue()

23 int getDetectionType()

24 bool getAnalogTimeConstant()

Dinamicka obrada audio signala 89

Page 98: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG D. Cython wrapper funkcije za klasu EnvelopeFollower

25 bool getLogDetector()

26

27 cdef class PyEnvelopeFollower:

28 cdef EnvelopeFollower *this_ptr

29 def __cinit__(self):

30 self.this_ptr = new EnvelopeFollower()

31 def __dealloc__(self):

32 del self.this_ptr

33 def init(self, sample_rate, attack_time_ms, release_time_ms, detection_type,

↪→ analog_time_const, log_detector):

34 self.this_ptr.init(sample_rate, attack_time_ms, release_time_ms,

↪→ detection_type, analog_time_const, log_detector)

35 def setSampleRate(self,sample_rate):

36 return self.this_ptr.setSampleRate(sample_rate)

37 def setAttackTime(self, attack_time_ms):

38 return self.this_ptr.setAttackTime(attack_time_ms)

39 def setReleaseTime(self, release_time_ms):

40 return self.this_ptr.setReleaseTime(release_time_ms)

41 def setDetectionType(self, detection_type):

42 return self.this_ptr.setDetectionType(detection_type)

43 def setTimeConstant(self, analog_time_const):

44 return self.this_ptr.setTimeConstant(analog_time_const)

45 def setLogDetector(self, log_detector):

46 return self.this_ptr.setLogDetector(log_detector)

47 def detectEnvelope(self, sample):

48 return self.this_ptr.detectEnvelope(sample)

49 def getSampleRate(self):

50 return self.this_ptr.getSampleRate()

51 def getAttackTimeMs(self):

52 return self.this_ptr.getAttackTimeMs()

53 def getAttackTime(self):

54 return self.this_ptr.getAttackTime()

55 def getReleaseTimeMs(self):

56 return self.this_ptr.getReleaseTimeMs()

57 def getReleaseTime(self):

58 return self.this_ptr.getReleaseTime()

59 def getEnvelopeValue(self):

60 return self.this_ptr.getEnvelopeValue()

61 def getDetectionType(self):

Dinamicka obrada audio signala 90

Page 99: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG D. Cython wrapper funkcije za klasu EnvelopeFollower

62 return self.this_ptr.getDetectionType()

63 def getAnalogTimeConstant(self):

64 return self.this_ptr.getAnalogTimeConstant()

65 def getLogDetector(self):

66 return self.this_ptr.getLogDetector()

Dinamicka obrada audio signala 91

Page 100: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG E. Cython wrapper funkcije za klasu DynamicProcessor

PRILOG E

Cython wrapper funkcije za klasu

DynamicProcessor

U nastavku se nalazi redefinicija klase DynamicProcessor u Cython sintaksi.

1 #distutils: language = c++

2 #distutils: sources = dynamicprocessor.cpp, envelopefollower.cpp

3

4 from libcpp cimport bool

5

6 import numpy as np

7 cimport numpy as np

8

9 cdef extern from "dynamicprocessor.h":

10 ctypedef enum TimeConstant: Digital, Analog

11 ctypedef enum ProcessorType: COMPRESSOR, LIMITER, EXPANDER, NOISE_GATE

12 ctypedef enum DetectionType: DETECT_PEAK_VALUE, DETECT_MEAN_SQUARE

13 cdef cppclass DynamicProcessor:

14 DynamicProcessor()

15 bool prepareForPlay()

16 bool processAudioFrame(float *arr_a, int size, float *arr_b)

17 void initialize(float, float, float, float , float, float, float, float,

↪→ float, TimeConstant, ProcessorType, DetectionType)

18 void userChangedInputGain(float)

19 void userChangedOutputGain(float)

20 void userChangedThreshold(float)

21 void userChangedAttackTimeMs(float)

22 void userChangedReleaseTimeMs(float)

23 void userChangedRatio(float)

Dinamicka obrada audio signala 92

Page 101: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG E. Cython wrapper funkcije za klasu DynamicProcessor

24 void userChangedKneeWidth(float)

25 void userChangedDelayLine(float)

26 void userChangedTimeConstant(TimeConstant)

27 void userChangedProcessorType(ProcessorType)

28 void userChangedDetectionType(DetectionType)

29

30 float getInputGain()

31 float getOutputGain()

32 float getThreshold()

33 float getAttackTimeMs()

34 float getReleaseTimeMs()

35 float getRatio()

36 float getKneeWidth()

37 float getDelayLine()

38 float getSampleRate()

39 int getTimeConstant()

40 int getProcessorType()

41 int getDetectionType()

42

43 bool cmpChannelSettings()

44 float getEnvelopeValueLeftChannel()

45 float getEnvelopeValueRightChannel()

46

47 cdef class PyDynamicProcessor:

48 cdef DynamicProcessor *this_ptr

49 def __cinit__(self):

50 self.this_ptr = new DynamicProcessor()

51 def __dealloc__(self):

52 del self.this_ptr

53 def prepareForPlay(self):

54 return self.this_ptr.prepareForPlay()

55 def userChangedInputGain(self, float inputGain):

56 return self.this_ptr.userChangedInputGain(inputGain)

57 def userChangedOutputGain(self, float output_gain):

58 return self.this_ptr.userChangedOutputGain(output_gain)

59 def userChangedThreshold(self, float threshold):

60 return self.this_ptr.userChangedThreshold(threshold)

61 def userChangedAttackTimeMs(self, float attack_time_ms):

62 return self.this_ptr.userChangedAttackTimeMs(attack_time_ms)

Dinamicka obrada audio signala 93

Page 102: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG E. Cython wrapper funkcije za klasu DynamicProcessor

63 def userChangedReleaseTimeMs(self, float release_time_ms):

64 return self.this_ptr.userChangedReleaseTimeMs(release_time_ms)

65 def userChangedRatio(self, float ratio):

66 return self.this_ptr.userChangedRatio(ratio)

67 def userChangedKneeWidth(self, float knee_width):

68 return self.this_ptr.userChangedKneeWidth(knee_width)

69 def userChangedDelayLine(self, float delay_line):

70 return self.this_ptr.userChangedDelayLine(delay_line)

71 def userChangedTimeConstant(self, TimeConstant time_const):

72 return self.this_ptr.userChangedTimeConstant(time_const)

73 def userChangedProcessorType(self, ProcessorType processor_type):

74 return self.this_ptr.userChangedProcessorType(processor_type)

75 def userChangedDetectionType(self, DetectionType detection_type):

76 return self.this_ptr.userChangedDetectionType(detection_type)

77 def getInputGain(self):

78 return self.this_ptr.getInputGain()

79 def getOutputGain(self):

80 return self.this_ptr.getOutputGain()

81 def getThreshold(self):

82 return self.this_ptr.getThreshold()

83 def getAttackTimeMs(self):

84 return self.this_ptr.getAttackTimeMs()

85 def getReleaseTimeMs(self):

86 return self.this_ptr.getReleaseTimeMs()

87 def getRatio(self):

88 return self.this_ptr.getRatio()

89 def getKneeWidth(self):

90 return self.this_ptr.getKneeWidth()

91 def getDelayLine(self):

92 return self.this_ptr.getDelayLine()

93 def getSampleRate(self):

94 return self.this_ptr.getSampleRate()

95 def getTimeConstant(self):

96 return self.this_ptr.getTimeConstant()

97 def getProcessorType(self):

98 return self.this_ptr.getProcessorType()

99 def getDetectionType(self):

100 return self.this_ptr.getDetectionType()

101 def cmpChannelSettings(self):

Dinamicka obrada audio signala 94

Page 103: bib.irb.hrSadrzajˇ Popis slika v Popis tablica vi Popis kratica vii 1 Uvod 1 2 Osnovni pojmovi u obradi audio signala 3 2.1 Uzorkovanje signala

PRILOG E. Cython wrapper funkcije za klasu DynamicProcessor

102 return self.this_ptr.cmpChannelSettings()

103 def getEnvelopeValueLeftChannel(self):

104 return self.this_ptr.getEnvelopeValueLeftChannel()

105 def getEnvelopeValueRightChannel(self):

106 return self.this_ptr.getEnvelopeValueRightChannel()

107 def processAudioFrame(self, np.ndarray[np.float32_t, ndim=1] inputData,

↪→ np.ndarray[np.float32_t, ndim=1] outputData):

108 return self.this_ptr.processAudioFrame(<float*>np.PyArray_DATA(inputData),

↪→ <int>len(inputData), <float*>np.PyArray_DATA(outputData))

109 def initialize(self, float input_gain, float output_gain, float

↪→ threshold_level, float attack_time_ms, float release_time_ms, float

↪→ ratio_level, float knee_width, float sample_rate, float delay_line,

↪→ TimeConstant time_constant, ProcessorType processor_type, DetectionType

↪→ detection_type):

110 return self.this_ptr.initialize(input_gain, output_gain, threshold_level,

↪→ attack_time_ms, release_time_ms, ratio_level, knee_width,

↪→ sample_rate, delay_line, time_constant, processor_type,

↪→ detection_type)

Dinamicka obrada audio signala 95