409108.Nenad Peanac - Diplomski Rad

79
SVEUČILIŠTE U ZAGREBU FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA DIPLOMSKI RAD br. 1780 Korištenje zvuka u Java aplikacijama Nenad Pećanac

Transcript of 409108.Nenad Peanac - Diplomski Rad

Nenad Peanac - Diplomski rad

SVEUILITE U ZAGREBU

FAKULTET ELEKTROTEHNIKE I RAUNARSTVA

DIPLOMSKI RAD br. 1780Koritenje zvuka u Java aplikacijamaNenad PeanacZagreb, prosinac 2008.Sadraj11.Uvod

32.Opis koritenih tehnologija

32.1.Programski jezik Java

32.1.1.Razvoj jezika i njegova namjena

42.1.2.Java danas

42.1.3.Zvuna podrka

52.2.Java Sound API

52.2.1.Koncept, namjena i performanse

62.2.2.Funkcionalnost

72.2.3.Digitalni zapis zvuka

82.2.4.Format zvunog zapisa

82.2.5.Format zvune datoteke

92.2.6.Zvuna konfiguracija

112.2.7.MIDI protokol

132.2.8.Dizajn i programska struktura MIDI modula

162.2.9.Koritenje MIDI modula

202.3.Swing

202.3.1.Razvoj i namjena

202.3.2.Arhitektura

253.Opis aplikacije

253.1.Koncept, namjena i dizajn

263.2.Glavni modul

263.2.1.Glavni izbornik

303.2.2.Preglednik instrumenata

323.3.Glavni sekvencer

343.4.Sporedni sekvencer

373.5.Kontrolni modul

384.Programska izvedba aplikacije

384.1.Pregled i organizacija koda

384.1.1.Klase grafikog suelja

404.1.2.Zvune klase

404.1.3.Pomone klase

414.2.Implementacija zvunog sustava

414.2.1.Klasa SynthesizerWrapper

434.2.2.Klasa SequencerWrapper

464.3.Implementacija grafikog suelja

474.3.1.Izvedba glavnog modula

504.3.2.Izvedba osnovnog sekvencerskog modula

554.3.3.Izvedba glavnog sekvencerskog modula

604.3.4.Izvedba sporednog sekvencerskog modula

644.3.5.Izvedba kontrolnog modula

665.Literatura

676.Zakljuak

1. UvodDigitalno zapisivanje, reprodukcija i obrada zvuka u dananje vrijeme ine osnovnu studijsku tehnologiju za rukovanje zvunim zapisima. Napretkom raunalne tehnologije, u 90-tim godinama 20. stoljea digitalna obrada zvuka se ubrzano razvila, te preuzela veinski udio u zastupljenosti na svjetskom tritu nad analognim tehnologijama. Prvi praktini ureaj za snimanje i reprodukciju zvunog zapisa izumio i patentirao je Thomas Edison 1878. godine. [1] Bio je to mehaniki ureaj nazvan fonografski cilindar. Radio je na principu igle koja je bila privrena na membranu, ije je vibracije prenosila na votani cilindar. Ureaj je brzo usavren i rasprostranjen irom svijeta. Ovim izumom ovjeku je prvi put dana mogunost da uhvati i spremi zvuk, te ga reproducira po elji. Snimanjem zvuka, distribucijom i prodajom zvunih zapisa zapoeta je nova, brzo rastua grana industrije. Do 1910. godine snimljeno je i rasprodano nekoliko milijuna naslova. Ureaj je uskoro zamijenjen gramofonom, kojeg je izumio Emile Berliner 1887. godine [2], a industrija se nastavila sve bre razvijati. Mehaniki proces snimanja zvuka ubrzo je zamijenjen elektrinim.

Analogno snimanje zvuka zapoeli su 1920-tih godina inenjeri amerike tvrtke Bell Telephone Laboratories usavravanjem ureaja nazvanog mikrofon, kojeg je takoer izumio Emile Berliner 1876. godine. Tvrtka je izum otkupila za potrebe telefonske industrije. Analogni proces snimanja zvuka upotpunjen je izumom magnetofona njemake tvrtke AEG 1935. godine. 1948. godine ameriki izumitelj Les Paul izumio je viekanalni magnetofon [3] koji je postao glavni alat za studijsko snimanje i montau zvuka sve do 90-tih godina 20. stoljea, kada je zamijenjen raunalima. Ovim izumom postalo je mogue napredno manipuliranje slijedom zvunih zapisa, spajanje zvunih dionica i kreiranje zvunih sekvenci. Digitalno zapisivanje zvuka postalo je mogue tek 60-tih godina dvadesetog stoljea. Proces pretvorbe analognog zvunog signala u digitalni oblik pod nazivom PCM (eng. Pulse-Code Modulation) prvi je istraio i patentirao britanski znanstvenik Alec Reeves jo 1937. godine. Nakon objave njegovog rada amerika tvrtka Bell Telephone Laboratories poela je raditi na implementaciji procesa. 1957. godine njihov inenjer Max Mathews razvio je sustav za snimanje zvuka uz pomo raunala. Od 1970. godine na tritu su se pojavili viekanalni digitalni snimai zvuka tvrtki Denon, Mitsubishi i Soundstream koji su koristili PCM tehnologiju zapisivanja. Digitalni zapisi spremali su se i dalje na magnetske trake, a najpoznatiji tip takvog medija bile su DAT (eng. Digital Audio Tape) trake, esto koritene u studijske svrhe. 70-tih godina 20. stoljea na tritu su se takoer poeli pojavljivati elektroniki instrumenti, kao to su sintesajzeri i sekvenceri. 80-tih godina takvi ureaji inili su standardnu opremu glazbenih studija. Uskoro, u zvuna studija su poela ulaziti i raunala, koja su se spajala sa klavijaturama i ostalim elektronikim komponentama koritenjem MIDI tehnologije (eng. Musical Instrument Digital Interface). [4] Ova tehnologija predstavljena je 1983. godine i uvela je u upotrebu industrijski standardiziran protokol za povezivanje, kontrolu i sinkroniziranje elektronikih ureaja koji se odrao do danas. Protokol je definiran na nain da ureaji meu sobom izmjenjuju MIDI poruke, koje sadre instrukcije za izvoenje operacija koje ureaji trebaju obaviti. Poetkom 90-tih godina za zapisivanje zvuka su se poeli koristiti raunalni tvrdi diskovi. Zvuk se u poetku spremao u sirovim AIFF ili WAV formatima, a kasnije su uvedeni komprimirani formati kao to su MP3, WMA i OGG. Nakon to su raunalni tvrdi diskovi dostigli dovoljne veliine, a procesori dovoljne brzine, otvorila se mogunost za efikasno spremanje i rukovanje sa velikim zvunim zapisima. Ubrzo, raunala su postala osnovni alat svakog glazbenog studija. Dananji profesionalni programski alati kao to su Cubase, Protools, Logic, Acid, Nuendo ili Sonar korisniku nude funkcionalnosti cijelog glazbenog studija u jednoj aplikaciji, koja se uz prikladnu zvunu podrku moe koristiti na prosjenom korisnikom osobnom raunalu. Takvi programi rezultat su dugogodinjeg razvoja i napisani su u programskim jezicima C i C++. Od nedavno, napretkom i optimizacijom programskog jezika Java, uz koritenje Java Sound API biblioteke, postalo je mogue razvijati sline prenosive aplikacije prihvatljivih performansi.

2. Opis koritenih tehnologija2.1. Programski jezik Java

2.1.1. Razvoj jezika i njegova namjenaProgramski jezik Java osmiljen je u tvrtci Sun Microsystems poetkom 90-tih godina prolog stoljea. Razvoj jezika poeo je 1990. godine kao Stealth project (eng. nevidljivi, prikriveni projekt), poslije nazvan Green project (eng. zeleni projekt), a vodili su ga Bill Joy, Patrick Naughton, Mike Sheridan i James Gosling. U poetku, Java je bila poznata pod nazivom Oak (eng. hrast) [5], koji joj je dao Gosling prema starom hrastu koji je rastao u dvoritu ispred prozora njegove radne sobe. Od tog naziva kasnije se ipak odustalo zbog problema oko autorskih prava, nakon ega je usvojeno ime Java. Cilj Sun-ovog tajnog projekta bio je predvianje smjera razvoja raunarske znanosti i smiljanje naina kako ga uhvatiti.

Budunost se oekivala u vidu nastavka minijaturizacije raunalnih komponenti i postupnom proirenju raunarske znanosti na podruje ve postojeih elektronikih ureaja, kao to su npr. kuanski aparati. Poetna ideja projekta bila je povezivanje mnotva elektronikih naprava sa jednim centralnim ureajem, nalik daljinskom upravljau, odnosno gledano openito, izgradnja sustava koji e omoguiti mreno povezivanje i meusobnu komunikaciju velikog broja razliitih elektronikih ureaja. Da bi to postalo mogue, trebalo je razviti novi hardver, nai prikladni programski jezik, te dizajnirati i realizirati operacijski sustav sa grafikim sueljem, pristupaan korisniku. Odlueno je da niti jedan programski jezik do tada, pa ni C++ ne zadovoljava potrebne uvjete za razvoj takvog sustava, te se poelo raditi na novom jeziku, Oak-u.

Zahtjevi koje je taj novi jezik trebao ispuniti bili su:

1) jednostavnost (jezik treba biti iroko rasprostranjen, pa zato ne smije biti suvie sloen),2) pouzdanost (blokiranje i ponovno pokretanje elektronikih ureaja su nedopustivi),3) sigurnost (mrena komunikacija mora biti zatiena),4) prenosivost (jezik je potrebno izvoditi na razliitim ureajima, pa mora biti vieplatformski).Tri godine nakon poetka projekta, predstavljen je ureaj *7 koji je bio prethodnik dananjih PDA ureaja. On je unato svom revolucionarnom dizajnu doivio neuspjeh na tritu, jer je bilo prerano za takav tip tehnologije.

Nakon poetnog neuspjeha, Javu se probalo iskoristiti za potrebe kabelske televizije, no tamo je takoer doivjela neuspjeh pred ve postojeim sustavom. Pojavom Interneta, u Sun-u su shvatili da je Java po svojim karakteristikama savren izbor za izradu web aplikacija.

Java je prilagoena novoj primjeni i slubeno izdana 1995. godine. Omoguila je izradu dinamikih web stranica i sloenih web aplikacija, neovisno o platformi na kojoj se izvodi, te je vrlo brzo postala sveprisutna na Internetu. Idui korak bio je ulazak na trite mobilnih telefona to se takoer pokazalo uspjenim. 2.1.2. Java danasStatistike kau [6] da otprilike 4.5 milijuna programera trenutno radi u Javi, da je vrijednost poslova obavljenih upotrebom Java tehnologija oko 100 milijardi dolara godinje, da se trite igara na mobilnim telefonima procjenjuje na oko 3 milijarde dolara, te da 70% planiranih beinih aplikacija koristi Javu.

Budui da je namijenjena svijetu Interneta i multimedijskoj upotrebi, Java od svojih najranijih verzija sadri podrku za zvuk, u obliku biblioteke pod nazivom Java Sound API, uz koju je potom dodana i podrka za video i 3D grafiku.

2.1.3. Zvuna podrka

U verziji Jave 1.02 u jezik je uvedena biblioteka Java Sound API. Koritenjem prvih verzija te biblioteke bilo mogue reproducirati tek jednostavne 8 kHz zvukove zapisane u AU formatu, no situacija se bitno izmijenila u verziji 1.2 kad je u Javinu zvunu podrku uvrten HeadSpace Audio Engine tvrtke Beatnik Corporation. [7] Uz upotrebu istih suelja, programerima je dana mogunost koritenja AU, WAV, AIFF, MIDI, i RMF zvukova. Iako je kvaliteta zvuka poboljana do CD kvalitete, (do frekvencije uzorkovanja od 44 kHz), nije postojao nain programske kontrole kao to je pauziranje i nastavljanje reprodukcije zvuka, prikazivanje trenutnog poloaja ili dobivanje obavijesti da je reprodukcija gotova. Java Sound API pruao je programerima tek osnovnu funkcionalnost.

U verziji Jave 1.3 ti nedostatci su ispravljeni. Do verzije 1.5 uklonjeno je dosta greaka i implementirane su nove, optimizirane osnovne funkcije napisane u C-u. Time je omoguena brza i efikasna podrka za razvoj programa koji zahtijevaju kratak odziv od zvunog sustava i namijenjeni su obavljanju velikog broja sloenih zvunih operacija koje se trebaju izvravati u realnom vremenu.

U trenutnoj verziji Jave 1.6, Java Sound API je stabilna i zaokruena cjelina, namijenjena visokom stupnju kontrole nad zvukom i upotrebi u bilo kakvoj vrsti multimedijskih aplikacija, od jednostavnih korisnikih programa do zahtjevnih profesionalnih sustava.2.2. Java Sound API

2.2.1. Koncept, namjena i performanseJava Sound API je programski okvir niske razine koji prua mogunosti za neposredno kontroliranje i obradu ulaznih i izlaznih zvunih zapisa u audio ili u MIDI formatu. Osim to nudi izravnu kontrolu nad zvukom, Java Sound API je dizajniran sa ciljem pruanja proirivosti i fleksibilnosti.Java Sound API prua najnii mogui nivo kontrole nad zvukom na Java platformi. Dijelovi API-ja su mehanizmi preko kojih je mogue programski pristupiti ili rukovati sistemskim resursima kao to su audio mikseri, MIDI sintesajzeri i ostali MIDI ureaji, itai, snimai, pretvornici zvunih zapisa i slino. Java Sound API ne sadri sofisticirane zvune editore ili grafike alate, ali prua mogunosti na osnovu kojih se takvi programi mogu izgraditi. API naglaava kontrolu zvuka na niskom nivou nad onom koju korisnici tipino oekuju.U Javi takoer postoje API-ji viih razina koji sadre elemente usko vezane uz zvune operacije. Jedan od takvih je JMF (eng. Java Media Framework), dostupan kao standardna ekspanzija Java platforme. JMF predstavlja ujedinjenu arhitekturu, komunikacijski protokol i programsko suelje za snimanje i reprodukciju audio i video zapisa. Na ovaj nain programerima se nudi jednostavna osnova za izgradnju programa za reprodukciju multimedijskih sadraja. S druge strane, ako je potrebno izgraditi sofisticiraniju aplikaciju sa naprednijim opcijama kao to su reprodukcija segmentiranih ili velikih zvunih zapisa, upotreba audio efekata ili manipulacija nad MIDI zapisom, Java Sound API nudi primjereniji pristup zbog veeg nivoa kontrole.

Java Sound API sastavljen je iz skupa brzih, optimiranih osnovnih funkcija napisanih u C/C++ kodu. Takve funkcije piu se u proizvoljnom jeziku i provode se u binarni kod spreman za izvoenje na ciljanoj platformi. Na taj nain se zaobilazi interpretiranje meukoda i eliminira mogue kanjenje unutar JVM-a (eng. Java Virtual Machine), te izravno pristupa resursima sustava na niskoj razini (eng. Low level programing). Tako su na Windowsima osnovne funkcije napisane i prevedene uz pomo Direct Sound-a, a na Linuxu uz pomo ALSA-e. Ovakav pristup upotrijebljen je radi ubrzanja rada Java Sound API-ja, a dobivene performanse su u rangu sa klasinim C/C++ kodom. Vrijeme uitavanja aplikacije takoer je skraeno u odnosu na obian Java kod jer su sve funkcije za upravljanje zvukom unaprijed prevedene, pa se kanjenje uglavnom odnosi na ostale Java klase, kao to su npr. klase grafikog suelja, klase za mrenu komunikaciju i slino [8].Mogunosti i performanse Java Sound API-ja dobro demonstrira mnotvo besplatnih aplikacija dostupnih na Internetu [9].2.2.2. FunkcionalnostJava Sound API sastoji se od dva funkcionalno odvojena modula. Jedan prua audio, a drugi MIDI podrku. Svaki modul podran je unutar svog paketa:

1) javax.sound.sampled - paket specificira suelja za snimanje, mijeanje i reprodukciju snimljenog zvuka,2) javax.sound.midi - paket specificira suelja za MIDI sintezu, rukovanje MIDI sekvencama i upravljanje MIDI dogaajima.

Osim ova dva paketa, Java Sound API jo ine paketi javax.sound.sampled.spi i javax.sound.midi.spi koji sadre servise, tj. apstraktne klase i suelja preko kojih je mogue uvesti dodatne komponente i funkcionalnosti unutar API-ja.2.2.3. Digitalni zapis zvukaPaket javax.sound.sampled prua mogunosti za upravljanje digitalno zapisanim zvukom, koji se unutar Java Sound API-ja naziva uzorkovani zvuk (eng. sampled). Pod tim nazivom se podrazumijeva bilo kakav tip digitalnog zapisanog zvuka. Uzorci zvuka predstavljaju uzastopne slike zvunog signala. Kad se zvuk zapisuje u analognom obliku, koristi se mikrofon, koji zvune valove pretvara u analogne elektrine signale valnog oblika. Kad se zvuk prebacuje iz analognog zapisa u digitalni, koristi se AD (analogno-digitalno) sklopovlje koje elektrine signale pretvara u digitalne informacije postupkom uzorkovanja. Postupak [9] je ilustriran na slijedeoj slici:

Slika 1. Uzorkovanje zvunog signalaZvuni se signal uzorkuje na nain da se u skladu sa odabranom frekvencijom uzorkovanja periodiki zapisuje slika zvunog signala, tj. iznos amplitude elektrinog vala kojim je predstavljen zvuk. Na gornjoj slici, plavim su tokicama oznaene vrijednosti zvunog signala predstavljenog crvenom krivuljom u trenutcima uzorkovanja. to je frekvencija uzorkovanja vea, to e zapis zvuka biti vjerniji. Ako koristimo dananju CD kvalitetu zapisa zvuka, sa frekvencijom od 44 100 Hz, to znai da 44 100 puta u sekundi zapisujemo vrijednost zvunog signala. Osim frekvencije uzorkovanja, za kvalitetu zapisa zvuka je bitna jo i kvantizacija, tj. rezolucija zvunog zapisa koja odreuje broj bitova kojima se zapisuje iznos amplitude zvuka. to je iznos kvantizacije vei, kvaliteta zapisa je bolja. Danas se zvuk veinom zapisuje sa 16, 24 i 32 bita.Java Sound API generalno razlikuje dvije vrste formata zvunih podataka. Prvu vrstu predstavlja format koji se koristi za zvune zapise, a drugu format kojim se zapisuju zvune datoteke.

2.2.4. Format zvunog zapisa

Ovaj format sadri podatke koji predstavljaju atribute promatranog zvunog zapisa. Unutar API-ja predstavlja se objektom tipa AudioFormat koji sadri podatke o:1) tehnici kodiranja (esto PCM),2) broju kanala (1 za mono, 2 za stereo, ili vie za viekanalni zapis kao surround 5.1),3) frekvenciji uzorkovanja (eng. sample rate),4) kvantizaciji,5) frekvenciji prikaza (eng. frame rate),6) veliini prozora, u bajtovima (eng. frame size) ovdje se izraz prozor odnosi na koliinu informacija svih zvunih kanala koji ine promatrani zvuk u danom trenutku, izraen u bajtovima,7) poretku bajtova (big endian / little endian).2.2.5. Format zvune datoteke

Dok prethodni oblik formata direktno opisuje zapis zvuka, ovaj format specificira strukturu datoteke u koju se takvi podaci spremaju. Osim zvunih podataka, u zvunim datotekama se esto nalaze i druge informacije kao npr. podaci o autoru, atributi zapisa, kao to su trajanje, vrsta kodiranja i slino. Takvi dodatni podaci obino se zapisuju u zaglavljima zvunih datoteka.

Java Sound API format zapisa zvune datoteke predstavlja objektom tipa AudioFileFormat koji sadri:

1) tip datoteke (WAVE, AIFF itd.),2) duinu datoteke izraenu u bajtovima,3) duinu datoteke izraenu u prozorima,4) prethodno opisani AudioFormat objekt sa atributima zvuka.2.2.6. Zvuna konfiguracija Da bismo mogli iskoristiti dani zvuni zapis unutar nekog sustava, potreban nam je zvuni ureaj koji moemo upotrijebiti za upravljanje sa zvukom. U Java Sound API-ju svaki zvuni ureaj predstavljen je mikserom. Programski mikser je koncept koji potjee iz koncepta audio miksera.Svrha miksera je upravljanje s jednim ili vie tokova zvunih ulaza, te jednim ili vie tokova zvunih izlaza podataka. Programski mikser esto predstavlja implementaciju suelja ureaja kao to je zvuna kartica. Svaki ulaz i izlaz na zvunoj kartici predstavljeni su ulaznim i izlaznim prikljukom na njenom mikseru. Audio mikser ima kanale ili linije signala, pri emu svaka linija predstavlja tok jednog zvunog signala (obino stereo signal). U svaki kanal dakle ide jedan izvor zvuka, kao to je npr. mikrofon, gitara, bubanj, gramofon itd. Svaki kanal ima potenciometre, rotacijske i klizne, preko kojih je mogue podesiti nivo i filtriranje zvuka, dodati efekte kao to je npr. reverb efekt, koji daje prostornost zvuku.

Svrha audio miksera je spajanje vie ulaznih zvunih signala u jedan ili vie izlaznih, koji se onda preko izlaznih prikljuaka mogu slati u ureaje za snimanje i reprodukciju zvuka. Mikser je dakle sredinja komponenta svake audio konfiguracije. U Java Sound API-ju se, analogno tome, svakom zvunom konfiguracijom upravlja pomou jednog ili vie miksera.Primjer audio miksera prikazan je na slijedeoj slici:

Slika 2. Primjer audio mikseraJava Sound API dizajniran je na nain koji ne pretpostavlja predefiniranu zvunu konfiguraciju i doputa proizvoljan broj razliitih audio komponenti unutar sustava. Podrane su uobiajene operacije za rukovanje sa ulaznim i izlaznim zvunim signalima kao i mijeanje viestrukih tokova zvuka. Primjer jedne tipine zvune konfiguracije prikazan je na slijedeoj slici:

Slika 3. Primjer zvune konfiguracijePrimjer pokazuje sustav sa zvunom karticom koja ima vie ulaza i vie izlaza, dok je mikser izveden softverski. Izvori zvuka su programi, mrea, sintesajzer, datoteke sa zvunim zapisom, mikrofon itd. Sav zvuk iz izvora dolazi do miksera gdje se spaja u jedan tok informacija (eng. stream) koji se preko izlaza moe predati ureajima za reprodukciju.2.2.7. MIDI protokolMIDI standard definira komunikacijski protokol za razne elektronike glazbene ureaje, kao to su elektrine klavijature i osobna raunala. MIDI informacije mogu se prenositi kablovima meu ureajima i spremati u standardne datoteke.

Standard je prvenstveno bio zamiljen za prijenos nota meu sintesajzerima. Pojavom osobnih raunala proiren je u svrhu povezivanja instrumenata sa raunalima. MIDI specifikacija sastoji se od hardverskog i softverskog dijela. Hardverski dio uglavnom opisuje mehanizme i prikljuke za povezivanje ureaja, dok softverski dio ini veinu specifikacije, budui da dananja raunala raspolau i vie nego dovoljnom procesorskom moi za izvedbu softverskih sintesajzera i sekvencera.

Unutar Java Sound API-ja MIDI standard opisan je javax.sound.midi paketom. Ovaj paket omoguava upravljanje MIDI dogaajima i reprodukciju zvuka na temelju tih dogaaja. Dok semplirani zvuk sadri direktan prikaz zvuka, MIDI je format zapisa koji sadri instrukcije prema kojima se neki zvuk moe sintetizirati. Takav format ne opisuje direktno sam zvuk ve dogaaje koji utjeu na proces stvaranja zvuka koji se generira u sintesajzeru. Takvi dogaaji su npr. pritisci tipaka, okretanje potenciometara, pritiskanje gumba i slino.

MIDI dogaaji ne moraju biti izvedeni na vanjskim ureajima, ve mogu biti i softverski generirani te spremljeni u datoteku. Programi koji stvaranju, generiraju i ureuju takve MIDI datoteke zovu se sekvenceri. Sintesajzeri koji iz takvog zapisa generiraju zvuk mogu biti vanjski ureaji, programi ili ipovi na zvunoj kartici. Osim same reprodukcije, sintesajzeri esto imaju podrku za razne efekte. Zvune kartice esto imaju ulazne i izlazne prikljuke preko kojih se mogu povezivati sa vanjskim MIDI ureajima.

Funkcionalnost MIDI zapisa ilustrirana je MIDI konfiguracijom na slijedeoj slici:

Slika 4. Primjer MIDI konfiguracijePrimjer pokazuje aplikaciju koja priprema glazbenu reprodukciju iz MIDI datoteke spremljene na tvrdom disku (na lijevoj strani slike). Standardni MIDI zapis ita se u softverskom sekvenceru, koji alje MIDI poruke vanjskom sintesajzeru koji potom reproducira zvuk, ili programskom sintesajzeru koji koristi bazu datoteka sa instrukcijama za generiranje zvukova poznatih instrumenata.

Kao to se vidi na slici, MIDI poruke unutar sustava imaju vremenske oznake, po kojima ih programski sintesajzer izvodi. One se moraju ukloniti prije slanja vanjskom sintesajzeru, te mu se moraju poslati u oznaenim trenucima. Ova razlika izmeu MIDI poruka unutar raunalnog sustava i vanjskih MIDI komponenti postoji zbog toga to standard u vrijeme svog nastanka (1984-te godine) nije bio razvijen za raunala nego je naknadno prilagoen takvoj upotrebi.

Zbog toga se MIDI specifikacija dijeli na 2 dijela:

1) MIDI 1.0 - protokol za povezivanje MIDI komponenti. Odnosi se na originalni standard, razvijen za komunikaciju meu sintesajzerima.

2) Standardne MIDI datoteke - proirenje standarda, ukljuuje podrku za spremanje MIDI zapisa u datoteke 2.2.7.1. MIDI 1.0

U MIDI specifikaciji 1.0 podaci su predstavljeni MIDI porukama. Vrste poruka meusobno se razlikuju po prvom bajtu poruke. Taj bajt zove se statusni bajt, a oznaen je jedinicom na mjestu najznaajnijeg bita. Nakon njega slijede bajtovi poruke. MIDI poruke se obino koriste kanalno. Svaki kanal se pridjeljuje pojedinom instrumentu tako da se ureaj namjesti da reagira samo na poruke poslane na odreenom kanalu. Za takvu komunikaciju imamo kanalne MIDI poruke, koje imaju statusni bajt takav da se u prva etiri bita nalazi zapis kanala, a u druga etiri bita vrsta poruke. Npr. dvije najee koritene vrste MIDI poruka su Note On i Note Off za sviranje i prestanak sviranja odreene note. Ovakve poruke obino koriste dva podatkovna bajta, jedan koji odreuje visinu note i drugi koji odreuje jainu kojom je nota odsvirana.

Ova osnovna verzija MIDI specifikacije dizajnirana je za prijenos MIDI informacija izmeu komponenti u realnom vremenu. To znai da se MIDI porukama ne pridodaju nikakve vremenske oznake, ve se akcije zapisane u porukama izvode odmah po primitku poruke. 2.2.7.2. Standardne MIDI datoteke

Standardne MIDI datoteke proiruju osnovni MIDI protokol i dodaju mu mogunost pohrane MIDI informacija. Takve datoteke zapravo sadre MIDI dogaaje. MIDI dogaaj je MIDI poruka sa dodanom vremenskom oznakom koja odreuje vrijeme izvoenja te poruke. Niz takvih dogaaja naziva se sekvencom.

Standardna MIDI datoteka organizirana je u trake. Svaka traka sadri slijed nota za odreeni instrument. Moemo rei da MIDI datoteka sadri sekvence MIDI dogaaja za pojedine instrumente.

2.2.8. Dizajn i programska struktura MIDI modula

MIDI modul Java Sound API-ja dizajniran je sa ciljem potpune podrke MIDI standarda, te jednostavnog upravljanja MIDI ureajima. Programska implementacija se stoga svodi na simuliranje standardom specificiranih MIDI komponenti.

2.2.8.1. MIDI poruke

MIDI poruke predstavljene su apstraktnom klasom MidiMessage. Ta klasa predstavlja osnovnu, vremenski neoznaenu MIDI poruku u skladu sa specifikacijom 1.0. Takoer moe sadravati poruku definiranu proirenom MIDI specifikacijom ali bez vremenske oznake.

Klasa MidiMessage ima tri podklase:1) ShortMessages - su najee koritene poruke. Nakon statusnog bajta slijede dva podatkovna.

2) SysexMessages - su posebne poruke vezane uz sustav. Mogu imati puno podatkovnih bajtova i obino ih definira proizvoa sustava.

3) MetaMessages - su vrsta poruka koja se zapisuje u MIDI datoteke. Sadre tekst pjesama, podatke o tempu i slino, koje imaju znaenje za sekvencer ali ne i sintesajzer.2.2.8.2. MIDI dogaaji, sekvence i trake

MIDI dogaaji sadre MIDI poruke i vremenske informacije o njihovom izvoenju, te se zapisuju u MIDI datoteke. Programski gledano, MIDI dogaaj predstavljen je klasom MidiEvent , koja je omota oko klase poruke i njene instance mogue je zapisivati u standardne MIDI datoteke. Metode klase omoguavaju nam itanje i postavljanje vremenskih informacija te dobavljanje osnovne MIDI poruke. Njeno postavljanje mogue je samo za vrijeme konstrukcije dogaaja.

Niz MIDI dogaaja ini traku, koja odgovara zapisu sviranja jednog instrumenta. Niz traka ini sekvencu. Programski, sekvence i trake predstavljene su klasama Track i Sequence. Njihove instance mogue je stvoriti itanjem iz datoteke ili koritenjem konstruktora. Klase MidiEvent, Track i Sequence ine hijerarhiju u smislu vlasnitva, ali ne i nasljeivanja, jer su sve izvedene iz klase java.lang.Object.2.2.8.3. MIDI ureaji

MIDI ureaji unutar Java Sound API-ja predstavljeni su MidiDevice sueljem. Objekti koji implementiraju ovo suelje imaju mogunost komunikacije sa drugim takvim objektima odnosno MIDI ureajima. Takav objekt moe biti implementiran softverski ili kao suelje prema MIDI podrci nekog hardverskog ureaja kao to je zvuna kartica ili eksterni sintesajzer. Suelje prua funkcionalnosti za otvaranje i zatvaranje ureaja, kao i funkcionalnosti tipinih ulaznih i izlaznih MIDI prikljuaka, kao to je slanje i primanje MIDI poruka. Ureaji specijalizirane namjene kao to su sintesajzeri i sekvenceri imaju na raspolaganju njegova podsuelja Sythesizer i Sequencer. Suelje takoer sadri unutarnju klasu MidiDevice.Info u kojoj se nalaze tekstualne informacije o ureaju. 2.2.8.4. Odailjai i primatelji

Ovi objekti slue za odailjanje i primanje MIDI poruka. Odailjai moraju implementirati Transmitter suelje a primatelji Receiver suelje. MIDI ureaj alje ili prima poruke preko jednog ili vie takvih objekata, pri emu se kae da on te objekte posjeduje. Svaki odailja moe biti spojen na jednog primatelja odjednom, i suprotno. Ako elimo da nam ureaj alje poruke prema vie primatelja odjednom, onda mora posjedovati vie odailjaa pri emu je svaki spojen sa svojim primateljem.

2.2.8.5. SekvenceriSekvencer je ureaj za snimanje i reprodukciju sekvenci MIDI dogaaja. Posjeduje odailjae i primatelje, jer mora slati poruke ostalim ureajima kao to su sintesajzeri ili izlazni MIDI prikljuci, te ih primati prilikom zapisivanja u MIDI datoteke. Sekvencer je u API-ju predstavljen objektom koji implementira Sequencer suelje. U odnosu na svoje nadsuelje MidiDevice, ovo suelje definira dodatne metode za osnovne mogunosti sekvenciranja, kao to su uitavanje sekvenci iz MIDI datoteka, postavljanje tempa izvoenja i sinkroniziranje ostalih ureaja. Programi preko suelja takoer mogu registrirati objekte sluae, koji se obavjetavaju o izvravanju odabranih funkcija sekvencera. 2.2.8.6. Sintisajzeri

Sintesajzer je ureaj za generiranje zvuka. To je jedini objekt u MIDI paketu Java Sound API-ja koji generira zvuk. Sintesajzer kontrolira 16 MIDI kanala. Kanali su instance klase koja implementira MidiChannel suelje. Zvuk se moe generirati direktno, koritenjem metoda ovih objekata ili slanjem poruka sintesajzeru, koji onda prema njima generira zvukove. Poruke su ei nain upotrebe. Sintesajzer ih prima od sekvencera ili preko ulaznog porta. Osim informacija iz MIDI poruka, npr. o visini i jaini note, sintesajzer mora znati kako uope generirati traeni zvuk, da bi ga mogao interpretirati na traeni nain. Ova vrsta informacija predstavljena je Instrumentom. Svaki instrument sadri skup instrukcija u prema kojima sintesajzer generira odreeni zvuk. Instrumenti su ugraeni u sintesajzer ili mu se dodaju u obliku kolekcije instrumenata (eng. soundbank).2.2.9. Koritenje MIDI modulaU nastavku je ilustrirano koritenje MIDI modula na primjerima operacija koje se u aplikacijama najee izvode.2.2.9.1. Ispitivanje i zauzimanje dostupnih MIDI ureaja

Pristupanje MIDI ureajima u Java Sound API-ju izvodi se preko klase MidiSystem, koja predstavlja sredinji objekt za upravljanje MIDI sustavom. Klasa sadri statike metode kojima se mogu ispitati i dobaviti raspoloivi MIDI ureaji, sistemske implementacije suelja kao to su Sequencer i Synthesizer, implementacije eksternih suelja primatelja i odailjaa, informacije o podranim MIDI datotekama itd. Dohvat raspoloivih ureaja obavlja se upotrebom metode:

static MidiDevice.Info[] getMidiDeviceInfo()Metoda vraa polje MidiDevice.Info objekata koji sadre informacije o pojedinom MIDI ureaju, kao to su ime klase, mogunosti i tekstualni opis.

Dohvat odabranog ureaja izvodi se metodom:

static MidiDevice getMidiDevice(MidiDevice.Info info)Osim odabira konkretnog ureaja, mogue je koristiti i podrazumijevane (eng. default) MIDI ureaje. U tu svrhu koristimo slijedee metode:

1) static Sequencer getSequencer(),2) static Synthesizer getSynthesizer(),3) static Receiver getReceiver(),4) static Transmitter getTransmitter().Prije koritenja, MIDI ureaje je potrebno rezervirati upotrebom metode open():if (!(device.isOpen())) {

try {

device.open();

} catch (MidiUnavailableException e) {

// obrada iznimke

}

}Nakon to je ureaj rezerviran, potrebno ga je povezati sa drugim ureajima radi ostvarivanja komunikacije. Nakon to su potrebne operacije obavljene, ureaj se zatvara metodom close().2.2.9.2. Odailjanje i primanje MIDI poruka

Povezivanje dva MIDI ureaja izvodi se spajanjem odailjaa jednog ureaja sa primateljem drugog. Povezivanje se uvijek obavlja na strani odailjaa. Odailja sadri metode za ispitivanje i postavljanje primatelja. Kad se primatelj postavi, znai da je izmeu njih uspostavljena MIDI veza. Odailja alje poruke primatelju koristei njegove metode. Preko tih metoda primatelj prima poruke od drugih objekata. Oba objekta sadre metode za zatvaranje veze, nakon ega postaju dostupni za stvaranje veza sa drugim ureajima.U slijedeem primjeru prikazano je povezivanje sekvencera i sintesajzera:// deklariranje referenci

Sequencer seq;

Transmitter seqTrans;

Synthesizer synth;

Receiver synthRcvr;try {

//dohvat pretpostavljenog sekvencera seq = MidiSystem.getSequencer();

seqTrans = seq.getTransmitter(); // dohvat pretpostavljenog sintisajzera

synth = MidiSystem.getSynthesizer();

synthRcvr = synth.getReceiver();

// povezivanje odasiljaa i primatelja

seqTrans.setReceiver(synthRcvr);

} catch (MidiUnavailableException e) {

// obrada iznimke

}Nakon upotrebe, sve primatelje i odailjae potrebno je zatvoriti pozivanjem njihove close() metode. Svaki MIDI ureaj sadri metodu istog potpisa, koja ga zatvara skupa sa njegovim primateljima i odailjaima.

MIDI poruke je mogue slati i programski, bez upotrebe odailjaa. Ovakav je postupak koristan kod programa koji generiraju MIDI poruke npr. iz MIDI tipkovnice sa ekrana i alju ih sintesajzeru koji potom proizvodi zvuk. Potrebno je instancirati praznu poruku iz klase ShortMessage i popuniti je koritenjem metode:

void setMessage(int command, int channel, int data1, int data2)

Nakon toga poruku je potrebno poslati primatelju koristei njegovu metodu:void send(MidiMessage message, long timeStamp)

Argument timeStamp je interna veliina koja se koristi za ispravljanje i sinkronizaciju latencije kod MIDI poruka do koje moe doi zbog npr. kanjenja u operativnom sustavu ili u mrenom prometu. Predstavlja vrijeme u mikrosekundama od otvaranja ureaja koji sadri primatelja kojem pripada koritena metoda send(). Ako se ne koristi, pridruuje joj se vrijednost -1.Ovakvo slanje poruke ilustrira slijedei kod:

// stvaranje prazne poruke

ShortMessage myMsg = new ShortMessage();

// sviranje note C5 (60), umjereno glasno (jaina = 90).

myMsg.setMessage(ShortMessage.NOTE_ON, 0, 60, 90);

// vremenske oznake se ne koriste

long timeStamp = -1;

// dohvat primatelja

Receiver rcvr = MidiSystem.getReceiver();

// slanje poruke

rcvr.send(myMsg, timeStamp);

2.2.9.3. Uitavanje, izvoenje i snimanje MIDI sekvenci

MIDI zapisi pohranjuju se u obliku sekvenci MIDI dogaaja. Za upravljanje MIDI sekvencama koristi se sekvencer. Pomou njega se mogu izvoditi, ureivati i snimati MIDI sekvence. Sekvencer u tu svrhu obino sadri primatelje i odailjae. Primateljima se koristi pri snimanju, a odailjaima pri slanju MIDI zapisa ureajima za izvoenje.

Dohvat i otvaranje sekvencera prikazani su slijedeim programskim odsjekom:

// dohvat podrazumijevanog sekvencera

Sequencer sequencer;

sequencer = MidiSystem.getSequencer();

// provjera

if (sequencer == null) {

// greska, ne postoji sekvencer ...

} else

sequencer.open();

}Sekvencu se moe dobaviti iz MIDI datoteke, mogue ju je stvoriti runo, ili iz dobivenih MIDI poruka. Uitavanje sekvence iz datoteke moe se obaviti na slijedei nain:

try {

// otvaranje datoteke

File myMidiFile = new File("seq1.mid");

// uitavanje MIDI datoteke u sekvencu

Sequence mySeq = MidiSystem.getSequence(myMidiFile);

// postavljanje sekvence

sequencer.setSequence(mySeq);

}

catch (Exception e) {

// obrada iznimke

}

Nakon uitavanja sekvence, upravljanje njezinim izvoenjem obavlja se koritenjem slijedeih metoda:1) void start(),

2) void stop(),3) void getMicrosecondPosition(long microsecond),4) void setMicrosecondPosition(long microsecond),

5) public void getTempoInBPM(float bpm),6) public void setTempoInBPM(float bpm).Izvoenje sekvenci mogue je sinkronizirati sa drugim MIDI ureajima. Na sekvencer je takoer mogue prikljuiti i objekte sluae, koji se obavjetavaju pri izvoenju registriranih dogaaja.

2.3. Swing2.3.1. Razvoj i namjenaSwing je biblioteka za izradu grafikih suelja u sklopu programskog jezika Java. Biblioteka ini dio Sun-ovog paketa grafikih komponenti pod nazivom JFC (eng. Java Foundation Classes) u kojem su jo bibliteke AWT i Java 2D. Swing je prvi razvila tvrtka Netscape Communications Corporation pod nazivom IFC (eng. Internet Foundation Classes) krajem 1996. godine. Godinu dana poslije tvrtka Sun Microsystems odluila je ukljuiti biblioteku IFC kao standardni dio jezika Java.Swing je nasljednik AWT biblioteke, izgraen na njenim komponentama u cilju otklanjanja AWT-ovih nedostataka, koji su uglavnom bili vezani za preveliku ovisnost o grafikim sueljima platforme. Swing-ove komponente se prikazuju preko Java 2D biblioteke, koristei pritom AWT-ove mehanizme komunikacije sa platformom. Na taj nain je postignuta udaljenost od platformskog koda, te mogunost kreiranja sofisticiranijih grafikih komponenti u odnosu na AWT. Swing osim toga prua i mogunost odabira grafikih tema (eng. Look And Feel), koje se mogu jednostavno kreirati i mijenjati. Ovaj mehanizam omoguava Swing-ovim komponentama da emuliraju izgled komponenti platforme na kojoj se izvode, ili da namjerno izgledaju drugaije.2.3.2. Arhitektura

Swing je platformski nezavisan MVC (eng. Model View Controller) okvir za izradu grafikih suelja u programskom jeziku Java. [11] Izveden je kao jednodretveni programski model sa slijedeim karakteristikama:1) Platformska nezavisnost - Swing je platformski nezavisan jer kreira i iscrtava vizualne komponente neovisno o platformskim komponentama, koristei Javinu 2D grafiku biblioteku. AWT je za razliku od Swing-a gradio grafika suelja od ve postojeih sistemskih komponenti, tako to ih je pozivao kroz sistemski API.2) Komponenta orijentacija - Swing je okvir temeljen na komponentama, tj. objektima koji prate dobro poznate/specificirane karakteristine uzorke ponaanja. Te komponente asinkrono generiraju dogaaje, imaju ograniena svojstva i odgovaraju na dobro poznat skup naredbi karakteristian za svaku komponentu. Swing-ove komponente su osim toga i u skladu sa Java Beans konvencijom.3) Prilagodljivost - sve komponente u Swing-u sadravaju vizualne modele, koje je mogue prilagoditi korisnikim potrebama. Vizualni izgled komponenti odreuje se kompozicijom standardnih grafikih elemenata kao to su okviri prozora, klizai, ukrasi itd. Korisnik programski moe zadati grafike elemente, boje, prozirnosti i slino, ovisno o svojstvima pojedine komponente. Komponenta prema korisnikovu odabiru konfigurira prikladne klase za prikazivanje (eng. renderer) takvih komponenti. Takoer je mogue implementirati korisnike klase za prikaz, te na taj nain kreirati jedinstvene grafike komponente. Na slijedeoj slici prikazane su JTable komponente sa razliitim implementacijama prikaza elija:

Slika 5. JTable komponente sa razliitim implementacijama prikaza elija

4) Proirivost - Swing predstavlja programski okvir vrlo razdijeljene arhitekture, koja doputa korisniku implementaciju velikog broja suelja temeljnih komponenti. Korisnici mogu izmijeniti postojee komponente i njihove funkcionalnosti ili ih nadograditi. 5) Okvir lake kategorije (eng. Lightweight) - konfigurabilnost je rezultat izbora da se ne koriste grafiki elementi samog operativnog sustava, ve se prikazivanje komponenti izvodi preko Java 2D biblioteke. Na ovaj nain, okvir ima vie slobode pri prikazivanju svojih komponenti i moe ih prikazivati na bilo koji nain, bez ogranienja koja se mogu nametati zbog odabira platforme. Ipak, jezgra svake komponente je AWT-ov Container. To je osnovna klasa u AWT okviru koju nasljeuju sve Swing-ove klase. Na ovaj nain Swing se prikljuuje na platformske procese, kao to su preslikavanja ekrana, praenje pokreta mia i slino, te preko njih komunicira sa sustavom.

Swing dakle nadograuje semantiku i prikaz platformskih komponenti sa vlastitom semantikom i vizualizacijom. Npr. kad se pozove metoda paint() definirana u svakom AWT-ovom Container-u, a time i u svakoj Swing-ovoj komponenti, ona se potom prikazuje koristei Javine grafike mehanizme, neovisno o platformi. Osim vizualizacije, nadogradnja se odnosi i na mehanizam upravljanja dogaajima koji koriste komponente. Swing koristi sloeniji model upravljanja od AWT-a meu komponentama, koji se tek na kraju povezuje sa sustavom kroz AWT-ov model. 6) Konfigurabilnost - Swing jako ovisi o mehanizmima izvoenja. Ta ovisnost i indirektni uzorci izvoenja omoguavaju mu trenutno reagiranje na promjene u konfiguraciji. Aplikacije napisane u Swing-u tako npr. mogu mijenjati grafike teme za vrijeme izvoenja. Osim toga, mogue je kreirati korisnike teme, koje ne mijenjaju bitno ostatak aplikacijskog koda i lako se dodaju. Primjeri nekoliko komercijalnih grafikih tema prikazani su na slijedeoj slici:

Slika 6. Komercijalne grafike teme za Swing7) Slabo vezan / MVC okvir - Swing je biblioteka koja se velikim dijelom oslanja na MVC arhitekturu. Taj tip arhitekture konceptualno razdvaja podatke predstavljene korisniku od suelja preko kojeg su mu podaci prezentirani. Zbog toga veina komponenti sadri modele specificirane u obliku suelja, pri emu su u svim konkretnim komponentama sadrane njihove podrazumijevane implementacije. Programer moe koristiti podrazumijevane implementacije ili implementirati vlastite. Modeli su odgovorni za pruanje dogaaja i konceptualnih svojstava precizno definiranih sueljem za odreenu komponentu. Osim toga, modeli takoer pruaju i programski nain prikljuivanja sluaa dogaaja na komponentama. Dogaaji koji se pri tom oslukuju su usko vezani uz model i preko njega se interpretiraju odgovarajuoj komponenti.Za prikaz komponenti su odgovorne klase za prikazivanje. Implementiranjem vlastitih klasa za prikaz komponente ili nasljeivanjem postojeih moemo joj izmijeniti izgled i dio funkcionalnosti. Npr. moemo implementirati tablicu tipa JTable koja u svojim elijama sadri slike umjesto teksta.

Funkcionalnost komponenti pruaju editorske klase. Npr. ako nam elije tablice sadre objekte tipa JButton koritenjem editorske klase moemo specificirati ponaanje koje komponenta treba izvoditi prilikom klika na eliju, kao to je prikaz dijaloga ili mijenjanje boje elije ili slino.Na slijedeoj slici prikazana je Sun-ova Swing Demo aplikacija, u kojoj su demonstrirane neke od vizualnih mogunosti Swing-a u kombinaciji sa Java 2D bibliotekom, pod grafikim temama Windows i Motif:

Slika 7. Swing Demo aplikacija3. Opis aplikacije3.1. Koncept, namjena i dizajn

Aplikacija izraena u okviru ovog diplomskog rada predstavlja grafiki MIDI sekvencer, namijenjen izgradnji jednostavnih i sloenih MIDI sekvenci, te spremanju u MIDI datoteke. Grafiko suelje aplikacije prikazano je na slijedeoj slici:

Slika 8. Grafiko suelje aplikacijeAplikacija se sastoji od etiri modula:

1) Glavni modul predstavlja glavni prozor aplikacije i sadri sve ostale module,2) Glavni sekvencer (Sequencer) - slui za izgradnju sloenih sekvenci,3) Sporedni sekvencer (Loop Tool) - slui za izgradnju jednostavnih sekvenci (eng. loop),4) Kontrolni modul (Mixer) - upravlja iznosom glasnoe i reverba svih raspoloivih MIDI kanala.Podjela aplikacije na module odraz je njihove funkcionalnosti i programske implementacije. Glavni i sporedni sekvencer su sline strukture, i ine zasebne cjeline, pa su stoga programski implementirani kao podklase osnovnog sekvencera. Kontrolni modul je po funkcionalnosti takoer zasebna cjelina, pa je ovakva podjela najprimjerenija za preglednu organizaciju programskog koda, te vizualnu preglednost aplikacije.3.2. Glavni modulGlavni modul predstavlja osnovni modul aplikacije u kojem se nalaze glavni prozor i izbornik aplikacije, preglednik instrumenata Explorer i ostali moduli, Sequencer, LoopTool i Mixer. U ovom odjeljku opisani su glavni izbornik i preglednik instrumenata, jer ine neposredni dio glavnog modula, dok su ostali moduli zbog svoje izdvojenosti opisani u zasebnim odjeljcima.3.2.1. Glavni izbornik

Glavni izbornik aplikacije sastoji se od tri podizbornika: File, Midi i Help.

3.2.1.1. Podizbornik FilePodizbornik File nudi osnovne operacije za upravljanje radom tj. projektima:

1) New - operacija postavlja program u poetno stanje.

2) Open - pokree se izbornik za odabir datoteke, prikazan na slijedeoj slici:

Slika 10. Izbornik za otvaranje datoteke

Ukoliko se uita nepodrani oblik datoteke korisnik se obavjetava porukom o pogreci:

Slika 9. Prikaz pogreke pri otvaranju datoteke3) Save - operacija pokree izbornik za spremanje trenutnog projekta u datoteku. Ime i ekstenzija su proizvoljni. Predloena je upotreba jqs ekstenzije. Izbornik za spremanje datoteke prikazan je na slijedeoj slici:

Slika 11. Izbornik za spremanje datoteke

Podaci se spremaju u tekstualnu XML datoteku. Ovaj oblik zapisa se standardno koristi za serijalizaciju Swing objekata od verzije Jave 1.5.

Ukoliko doe do greke prilikom spremanja datoteke, korisniku se prikazuje poruka o pogreci:

Slika 12. Prikaz pogreke pri spremanju datoteke4) Quit - operacija vri zatvaranje aplikacije.

3.2.1.2. Podizbornik MIDI

Podizbornik MIDI nudi dvije operacije 1) Change Soundbank - operacija pokree izbornik za odabir datoteke sa kolekcijom zvukova (eng. Soundbank) za Java sintesajzer, prikazan na slijedeoj slici:

Slika 13. Izbornik za odabir kolekcije zvukova

Kolekcija zvukova za Java sintesajzer obino je spremljena u datoteci sa gm ekstenzijom, u GM (General MIDI) formatu. Uz aplikaciju dolazi Javina podrazumijevana kolekcija zvukova, u najkvalitetnijoj verziji, koja se uitava pri pokretanju programa, neovisno o trenutno instaliranoj podrazumijevanoj kolekciji unutar aktivnog JRE-a (Java Runtime Environment). Korisnike kolekcije zvukova u navedenom formatu mogue je kreirati upotrebom komercijalnog programa Beatnik editor tvrtke Beatnik, koja je dizajnirala Java Sound API. Ukoliko doe do pogreke pri uitavanju kolekcije, korisnik se o tome obavjetava slijedeom porukom:

Slika 14. Prikaz pogreke pri odabiru kolekcije zvukova

Render MIDI File - operacija pokree izbornik za spremanje datoteke sa MIDI zapisom. Datoteke sa MIDI zapisom su u standardnom SMF (eng. Standard Midi File) formatu, koji je propisala udruga MIDI Manufacturers Association [12]. Taj format je prepoznatljiv na svim raunalnim platformama i MIDI sustavima. Podrazumijevana ekstenzija takvih datoteka je MID, ali je mogue koristiti proizvoljnu. Izbornik je prikazan na slijedeoj slici:

Slika 15. Izbornik za spremanje MIDI zapisa

Ako prilikom izvravanja operacije doe do pogreke, korisnik se obavjetava slijedeom porukom:

Slika 16. Prikaz pogreke pri spremanju MIDI zapisa

3.2.1.3. Podizbornik HelpPodizbornik Help nudi operaciju About koja prikazuje dijalog sa informacijama o autoru i aplikaciji:

Slika 17.Prikaz informacija o autoru i aplikaciji3.2.2. Preglednik instrumenataPreglednik instrumenata slui za odabir raspoloivih instrumenata iz uitane kolekcije. Svaki od instrumenata mogue je presluati koritenjem kontrola za pregled na dnu preglednika, te odabrati za koritenje u sekvencerima.Preglednik je prikazan na slijedeoj slici:

Slika 18. Preglednik instrumenata

Za presluavanje eljenog instrumenta potrebno je odabrati jedan od 16 moguih MIDI kanala sintesajzera na kojem e se taj instrument odsvirati. Kanal 00 je podrazumijevani kanal za pregled instrumenata, dok je kanal 09 potrebno odabrati ukoliko elimo presluavati perkusije. U MIDI standardu taj kanal se naziva perkusijski kanal. Kod svih ostalih MIDI kanala se nakon odabira instrumenta na njemu sviraju razliite note odabranog instrumenta. Posebnost perkusijskog kanala je u tome to se na njemu svaka nota odsvira kao razliiti perkusijski instrument. Instrumenti perkusijskog kanala odreeni su MIDI standardom udruge MIDI Manufacters Association. Instrumenti su organizirani u skupine pod nazivom bank. Svaka skupina sadri po 128 instrumenata. Kod podrazumijevane kolekcije zvukova, u skupini Bank 0 nalaze se osnovni instrumenti, dok je skupina Bank 1 namijenjena za presluavanje perkusija. Ona zapravo sadri popis perkusija na razliitim notama tog kanala. Nakon uitavanja u sevencere, perkusijskim instrumentima treba dodijeliti perkusijski kanal. Ova operacija ne izvrava se automatski, jer korisnike kolekcije zvukova ne moraju biti organizirane na ovaj nain.Aplikacija je napisana na nain da radi sa podrazumijevanim softverskim sintesajzerom, koji koristi resurse zvune kartice sustava. Implementacija je takva, jer veina osobnih raunala ima jednu zvunu karticu, dakle jedan raspoloivi sintesajzer. Preglednik koristi posebnu instancu sekvencera i mogue ga je koristiti u isto vrijeme sa glavnim i sporednim sekvencerom, ali pri tome je potrebno uzeti u obzir da se MIDI poruke koje dolaze sa sva tri sekvencera izvode na jednom sintesajzeru. Budui da sintesajzer nakon primitka poruke za promjenu instrumenta na kanalu sve daljnje note na tom kanalu svira sa odabranim instrumentom, svaki razliiti instrument koji nije perkusija treba imati svoj posebni kanal. Isto tako, kanal za presluavanje instrumenta bi trebalo koristiti samo za tu svrhu.Za odabir eljenog instrumenta mogue se koristiti strelicama za navigaciju, a za presluavanje je mogue koristiti tipke na tastaturi:

1) Enter odabir instrumenta i uitavanje u sekvencere (dvostruki klik miem obavlja istu operaciju),1) Space presluavanje instrumenta,2) Backspace zaustavljanje presluavanja.3.3. Glavni sekvencer

Glavni sekvencer koristi se za izgradnju sloenih sekvenci. Sloena sekvenca predstavlja sekvencu jednostavnih sekvenci. Jednostavne sekvence se grade u sporednom sekvenceru. Svaki instrument koji se uita iz preglednika u glavni sekvencer, automatski se odabire u sporednom sekvenceru, dok mu se u glavnom dodjeljuje traka unutar glavne sekvence. U njemu se gradi jednostavna sekvenca, koja se koristi kao osnovni element sloene sekvence. Svaka traka slui za pohranu niza jednostavnih sekvenci, koje se sviraju na odabranom instrumentu, u odabrano vrijeme, sa odreenim brojem ponavljanja.Glavni sekvencer prikazan je na slijedeoj slici:

Slika 19. Glavni sekvencer

Osnovni dijelovi glavnog sekvencera su alatne trake i tablice, predoene na prethodnoj slici:

1) Kontrole za sviranje - obavljaju operacije sviranja i zaustavljanja sekvence, te sviranja sa ponavljanjem. Sviranje se pokree uz automatsku izgradnju sekvence. Ukoliko je sviranje u tijeku gumb za sviranje slui kao pauza, dok gumb za zaustavljanje uvijek vraa sekvencer na poetak sekvence.2) Spremanje sekvence - izvodi se na nain da se sve popunjene elije iz desne tablice zapisuju kao jednostavne sekvence u glavnu sekvencu. Prilikom editiranja tablice, potrebno je spremiti sekvencu da bi promjene mogle nastupiti.3) Tempo - se zadaje brojem otkucaja u minuti. Pri tome otkucaj oznaava etvrtinsku notu. Tempo se nakon odabira automatski postavlja u oba sekvencera.

4) Broj ponavljanja - ukupno trajanje glavne sekvence odreeno je brojem ponavljanja jednostavnih sekvenci, tj. brojem stupaca desne tablice. Ukoliko se odabere manji broj stupaca od trenutnog, podaci u stupcima koji se uklanjaju se odbacuju. U suprotnome se dodaju prazni stupci.5) Kontrola glasnoe - upravlja glasnoom cijele aplikacije. Raspon glasnoe svih kanala sintesajzera se odreuje prema rasponu ove kontrole.6) Trake / Instrumenti - lijeva tablica sekvencera sadri imena pojedinih traka sekvence. Odabirom elije u sporedni sekvencer se uitavaju spremljeni podaci za pripadnu traku, kao to su ime, instrument, kanal i note koje ine njenu jednostavnu sekvencu. Poetna imena traka se odreuju prema instrumentima koji su dodijeljeni pojedinim trakama pri uitavanju iz preglednika. Dvostrukim klikom na eliju tablice ta imena se mogu mijenjati prema elji. Pritiskom tipke Delete traka se uklanja iz tablice.7) Oznake jednostavnih sekvenci - prema njima se grade trake za pojedine instrumente na prethodno opisan nain.3.4. Sporedni sekvencer

Sporedni sekvencer slui za izgradnju jednostavnih sekvenci. Jednostavna sekvenca gradi se koritenjem dugih i kratkih nota. Kratke note predstavljaju etvrtinke i oznaavaju se jednom svijetlo plavom elijom, dok se duge note mogu protezati kroz proizvoljan broj elija i oznaene su tamno plavom bojom. Duge note obino se koriste za instrumente, a kratke za perkusije.Jednostavne sekvence slue za izgradnju traka u glavnom sekvenceru. Kao to su note graevni elementi jednostavnih sekvenci, tako su jednostavne sekvence graevni elementi sloenih sekvenci. Jednostavne sekvence imaju proizvoljnu duljinu od n*16 stupaca, jer je sekvencer namijenjen izradi najee koritenih sekvenci zapisanih u 4/4 taktu. Sve jednostavne sekvence su jednake duljine, to znai da se mijenjanjem duine jednostavne sekvence mijenjaju sve jednostavne sekvence u projektu. Duina sekvence obino se odreuje na poetku pisanja sekvence i iznosi 16, 32, 64 ili 128 stupaca. Ukoliko se ne eli koristiti ponavljanje sekvenci moe se jednostavno odabrati vea duina za jednostavnu sekvencu, koja onda preuzima ulogu sloene i ispunjava se notama.Sporedni sekvencer prikazan je na slijedeoj slici:

Slika 20. Sporedni sekvencer

Osnovni elementi sporednog sekvencera su alatne trake i tablice prikazane na prethodnoj slici:

1) Kontrole za sviranje - obavljaju operacije sviranja i zaustavljanja sekvence, te sviranja sa ponavljanjem. Sviranje se pokree uz automatsku izgradnju sekvence. Ukoliko je sviranje u tijeku gumb za sviranje slui kao pauza, dok gumb za zaustavljanje uvijek vraa sekvencer na poetak sekvence.

2) Spremanje sekvence - izvodi se na nain da se sve popunjene elije iz desne tablice zapisuju u jednostavnu sekvencu. Prilikom editiranja tablice, potrebno je spremiti sekvencu da bi promjene mogle nastupiti.

3) Odabir trake - svaka jednostavna sekvenca gradi jednu traku sloene sekvence, na nain da se svira na odabranim mjestima, odabrani broj puta. Nakon odabira trake, u sporedni sekvencer se uitavaju njene postavke kao to su instrument, MIDI kanal na kojem se instrument svira i glasnoa trake.4) MIDI kanal - odreuje na kojem e se kanalu sintesajzera svirati odabrana traka, tj. instrument koji joj je pridruen. Kanal automatski ostaje sauvan nakon promijene.5) Duljina sekvence - sve jednostavne sekvence imaju istu duljinu odreene ovim parametrom. Ako se duljina sekvence povea, tablica se ispunjava praznim elijama. U suprotnom, sve note iza granice duljine nove sekvence se odbacuju. 6) Kontrola glasnoe slui odreivanju iznosa glasnoe sekvenc. Vrijednost se sprema odmah nakon promijene.7) Visine nota - pokazuju mogue visine nota s kojima se gradi jednostavna sekvenca. Raspon raspoloivih nota se prostire na 10 oktava. Srednja nota u tom rasponu je C5.8) Duga nota - oznaka za instrumente koji proizvode tonove proizvoljnog trajanja. Poetak note odreuje se prvom, a kraj zadnjom tamno plavom elijom na istoj visini.

9) Kratka nota - obino se koristi za perkusije ili kratke tonove.3.5. Kontrolni modul

Kontrolni modul prikazan je na slijedeoj slici:

Slika 21. Kontrolni modul

Kontrolni modul se koristi za podeavanje iznosa glasnoe i reverba svih raspoloivih MIDI kanala. Reverb je zvuna pojava koja se dogaa pri generiranju zvuka u prostoru. Nakon to se prestane proizvoditi zvuk, ovisno o prostoru u kojem se zvuk rasprostire, dolazi do stvaranja raznih odjeka, zbog kojih se zvuk uje jo neko vrijeme, ali mu intenzitet brzo opada. Efekt reverba se moe jasno primijetiti kad se zvuk proizvodi npr. u tunelu, katedralama, peinama i slino. Razlikuje se od obine jeke po tome to se sastoji od mnotva manjih i brzih odjeka, koji se ne mogu jasno razaznati. Efekt pridonosi prostornosti zvuka. Odsvirane note se ne odsijecaju naglo pri prestanku trajanja, ako se pri tom koristi reverb.4. Programska izvedba aplikacije4.1. Pregled i organizacija kodaKod aplikacije raspodijeljen je u tri osnovna paketa:1) hr.fer.npecanac.diplomski.gui - paket sadri klase koje grade grafiko suelje aplikacije,2) hr.fer.npecanac.diplomski.sound - paket sadri klase koje ine zvune komponente aplikacije,3) hr.fer.npecanac.diplomski.utility - paket sadri pomone klase.4.1.1. Klase grafikog sueljaKlasni dijagram paketa sa klasama za izradu grafikog suelja prikazan je na iduoj slici:

Slika 22. Klase grafikog suelja

Znaenje isprekidanih linija na slici je slijedee:

1) Crvene linije oznaavaju nasljeivanje i pokazuju u smjeru nadklase,

2) Smee linije oznaavaju instanciranje klase i pokazuju u smjeru klase koja se instancira,3) Zelene linije oznaavaju referenciranje meu klasama.Grafiko suelje sastoji se od etiri osnovne klase, koje predstavljaju etiri prethodno opisana modula:1) MainGUI - glavna i najvea klasa, predstavlja glavni modul iz kojeg se pokree aplikacija,2) SequencerGUI - glavni sekvencer,3) LoopToolGUI - sporedni sekvencer,4) MixerGUI - kontrolni modul.Ostale klase prikazane na dijagramu pruaju funkcionalnosti koje se koriste u osnovnim klasama:1) BasicSequencerGUI - klasa predstavlja sekvencersku nadklasu iz koje se izvode klase glavnog i sporednog sekvencera. Sadri sve zajednike funkcionalnosti oba sekvencera.2) TrackProperties - klasa se koristi kao uzorak za spremanje podataka o svojstvima traka iz glavnog sekvencera. Predstavlja sloeni tip podatka koji sadri ime trake, oznaku instrumenta koji se svira na toj traci, MIDI kanal, glasnou trake i jednostavnu sekvencu koja se na toj traci izvodi.3) TableCellColorEditorSequencer - klasa predstavlja prilagoeni editor elija za glavni sekvencer. U njoj se definira ponaanje tablice u sluaju odabira elije, tj. nain bojanja.4) TableCellColorEditorLoopTool - klasa predstavlja prilagoeni editor elija za sporedni sekvencer.5) TableCellColorRenderer - klasa odreuje prilagoeni nain prikaza elija tablice. Preko nje se definira prikaz boja u elijama, oznaavanje svakog etvrtog stupca, oznaavanje trenutno aktivnog stupca, prikazivanje editiranih elija i slino.6) TableModelSequencer - klasa definira prilagoeni tablini model za desnu tablicu sekvencera. Preko modela se rukuje sa zaglavljem tablice, odreuju joj se dimenzije, koriteni oblici selektiranja i slino.4.1.2. Zvune klase

Aplikacija koristi dvije zvune klase koje se koriste kao omotai oko klasa sekvencera i sintesajzera Java Sound API-ja:

1) SequencerWrapper - klasa se koristi kao omota oko implementacije sekvencera Java Sound API-ja. Omoguava direktno sviranje jedne note danog instrumenta bez potrebe za izgradnjom sekvence (koristi se u pregledniku instrumenata), definira metodu za izgradnju MIDI dogaaja i njihov zapis u trake, te se brine o popunjavanju sekvence meta-porukama koje generiraju meta-dogaaje, preko kojih se u grafikom suelju prati i oznaava trenutna pozicija u sekvenci.2) SynthesizerWrapper - klasa se koristi kao omota oko implementacije sintisajzera Java Sound API-ja. Implemetira metode za uitavanje kolekcija instrumenata iz datoteke, za pristup raspoloivim instrumentima te za postavljanje i itanje iznosa reverba i glasnoe MIDI kanala.4.1.3. Pomone klase

U paketu sa pomonim klasama nalazi se klasa LocalDir koja slui za dohvat reference i imena direktorija u kojem je aplikacija pokrenuta. 4.2. Implementacija zvunog sustavaZvuni sustav implementiran je kroz prethodno opisane klase omotae oko sekvencera i sintesajzera Java Sound API-ja. Omotai se koriste u svrhu proirivanja funkcionalnosti dostupnih zvunih klasa. Koritenje nasljeivanja u ovu svrhu bi bio loginiji pristup, meutim to nije mogue, jer su Sequencer i Synthesizer suelja definirana u okviru API-ja, dok su objekti koji ih implementiraju izvedeni u platformskom kodu i ne moe ih se direktno nasljeivati. Nasljeivanje je mogue jedino u sluaju vlastite implementacije tih suelja.4.2.1. Klasa SynthesizerWrapperKlasa predstavlja omota oko implemetacije suelja Synthesizer u Java Sound API-ju. Sadri slijedee lanske varijable:1) Synthesizer m_Synthesizer - implementacija suelja Synthesizer,2) Instrument[] m_Instruments - polje raspoloivih instrumenata,3) MidiChannel[] m_Channels - polje raspoloivih MIDI kanala,4) SoundBank m_SoundBank - referenca na kolekciju instrumenata.U konstruktoru klase obavlja se dohvat sistemske implementacije suelja Synthesizer i uitavanje kolekcije instrumenata iz datoteke priloene uz aplikaciju. Ukoliko datoteka ne postoji, pokuava se uitati podrazumijevana kolekcija iz JRE-a, ako postoji. U sluaju neuspjeha neke od operacija dolazi do iznimke.

Kod konstruktora prikazan je u slijedeem ispisu:

public SynthesizerWrapper (File p_SoundBankFile) {

// instanciranje sintisajzera

try {

m_Synthesizer = MidiSystem.getSynthesizer();

}

catch (Exception ex) {

throw new RuntimeException( "Unable to instantiate a Synthesizer!");

}

// otvaranje sintisajzera

try {

m_Synthesizer.open();

}

catch (Exception ex) {

throw new RuntimeException( "Unable to open the a Synthesizer!");

}

// dohvat MIDI kanala

m_Channels = m_Synthesizer.getChannels();

// uitavanje kolekcije zvukova iz datoteke

if (p_SoundBankFile != null) {

try {

loadSoundbankFromFile(p_SoundBankFile);

}

catch (Exception e) {

// ako dode do iznimke, // pokusava se uitati sistemska kolekcija (jre)

m_Soundbank = m_Synthesizer.getDefaultSoundbank();

e.printStackTrace();

}

}

// konstruktoru nije predana datoteka sa kolekcijom

// slijedi uitavanje sistemske kolekcije zvukova (jre)

else {

m_Soundbank = m_Synthesizer.getDefaultSoundbank();

// provjera

if (m_Soundbank != null)

{

// dohvat liste raspoloivih instrumenata

m_Instruments =

m_Synthesizer.getAvailableInstruments();

// provjera

if (m_Instruments == null){

throw new RuntimeException(

"No instruments available!");

}

// uitavanje instrumenata

m_Synthesizer.loadAllInstruments(m_Soundbank);

}

else {

throw new RuntimeException(

"Unable to get a default soundbank!");

}

}

}Klasa sadri slijedee javne metode:1) boolean isOpen() - metoda vraa status sintesajzera,2) Patch getPatch(int p_InstIndex) - metoda vraa Patch objekt za predani indeks instrumenta,3) Instrument getInstrument(int p_InstIndex) - metoda za predani indeks vraa odgovarajuci Instrument,4) MidiChannel getChannel(int channel) - metoda za dohvat pojedinog kanala sintesajzera,5) close() - metoda zatvara sintesajzer i otpusta sistemske resurse, 6) Int getInstrumentsCount() - metoda vraa broj raspoloivih instrumenata,7) void loadSoundbankFromFile(File p_SoundbankFile) - metoda uitava kolekciju zvukova iz datoteke,8) void setChannelVolume(int p_Channel, int p_Volume) - metoda postavlja iznos glasnoe pojedinog MIDI kanala,9) void setChannelReverb(int p_Channel, int p_Reverb) - metoda postavlja iznos reverba pojedinog MIDI kanala.4.2.2. Klasa SequencerWrapperKlasa predstavlja omota oko implemetacije suelja Sequencer u Java Sound API-ju. Sadri slijedee lanske varijable:

1) SynthesizerWrapper m_SynthesizerWrapper - referenca na omota sintesajzera,2) Sequencer m_Sequencer - implementacija suelja Sequencer,3) Sequence m_Sequence - zvuna sekvenca,4) Track m_MetaTrack - traka sa meta-podacima za oznaavanje pozicije u sekvenci,5) int m_SequencePPQ - trajanje etvrtinke,6) boolean m_Looping - oznaka ponavljanja sekvence.U konstruktoru klase se obavlja dohvat sistemske implementacije suelja Sequencer, postavljanje osnovnih parametara sekvencera te spajanje sa omotaem sintesajzera. U sluaju neuspjeha neke od operacija dolazi do iznimke.Kod konstruktora prikazan je u slijedeem ispisu:public SequencerWrapper(SynthesizerWrapper p_SynthesizerWrapper, int p_SequencePPQ) {

// provjera parametara

if (p_SequencePPQ < 1 || p_SequencePPQ > 1000)

throw new RuntimeException(

"Unable to instantiate SequencerWrapper! Wrong PPQ!);

// provjera dostupnosti sintisajzera

if (p_SynthesizerWrapper == null || !p_SynthesizerWrapper.isOpen())

throw new RuntimeException(

"Unable to instantiate SequencerWrapper!

Synthesizer is not available!");

// instanciranje sekvencera

try {

m_Sequencer = MidiSystem.getSequencer(false);

}

catch (Exception ex) {

throw new RuntimeException(

"Unable to instantiate Sequencer!");

}

// postavljanje reference na sintisajzer

m_SynthesizerWrapper = p_SynthesizerWrapper;

// otvaranje sekvencera

try {

m_Sequencer.open();

// povezivanje sa sintisajzerom

m_Sequencer.getTransmitter().setReceiver(

m_SynthesizerWrapper.getSynthesizer().getReceiver());

}

catch (Exception ex) {

throw new RuntimeException(

"Unable to open Sequencer!");

}

// postavljanje trajanja cetrvrtinke

setSequencePPQ(m_SequencePPQ);

try {

m_Sequence = new Sequence(Sequence.PPQ, m_SequencePPQ);

}

catch (Exception e) {

e.printStackTrace();

}

}Klasa sadri slijedee javne metode:

1) void PlayMidiInstrumentPreview (int p_InstIndex, int p_Channel, int p_Note, int p_Velocity ) - metoda svira notu C5 odabranog instrumenta, na odabranom kanalu, uz zadanu jainu,2) void PlayMidiNoteOnChanell (int p_InstIndex, int p_Channel, int p_Note, int p_Velocity) - metoda svira notu C5 odabranog instrumenta, na odabranom kanalu, uz zadanu jainu, direktno preko sintesajzera, tj. bez koritenja sekvencera, 3) void createMidiEvent (int p_MidiCommand, int p_Channel, int p_Note, long p_Tick, int p_Velocity) - metoda kreira MIDI poruku klase ShortMessage i zamata je u MidiEvent,4) void createAndWriteMidiEvent (int p_MidiCommand, int p_Channel, int p_Note, long p_Tick, int p_Velocity, Track p_Track) - metoda kreira MIDI poruku klase ShortMessage, zamata je u MidiEvent i upisuje u danu traku,5) void stop () - metoda zaustavlja sviranje (bez vraanja na poetak sekvence), 6) void start (long p_TickPosition) - metoda postavlja sekvencu i kree od zadane pozicije,7) void resume() - metoda nastavlja sviranje u trenutnoj sekvenci od trenutne pozicije (ako je to mogue),8) void addMetaEventListener(MetaEventListener p_Listener) - metoda sekvenceru dodaje slusa meta-dogaaja,9) void createMetaTrack() - metoda sekvenci dodaje traku sa dogaajima na svakom tiku, 10) Byte[] convertInt2Bytes(int p_IntValue) - metoda pretvara tip int u niz bajtova,11) int convertBytes2Int(byte [] p_ByteArray) - metoda niz bajtova pretvara u tip int,12) boolean isRunning() - metoda vraa status sekvencera,13) void clearSequence() - metoda brie sekvencu.4.3. Implementacija grafikog sueljaGrafiko suelje aplikacije sastavljeno je iz etiri osnovna grafika modula. Svaki modul predstavljen je svojom vizualnom klasom, dizajniranom koritenjem dodatka Visual Editor u sklopu programske okoline Eclipse [14] . Struktura koda vizualnih klasa prikazana je slijedeim uzorkom:// trenutni paket

// uvoz koritenih klasa

public class ImeKlase {

// konstante

// lanske varijable

// vizualne komponente

// konstruktor

// glavna inicijalizacijska metoda

// inicijalizacijske metode vizualnih komponenti

// get / set metode// javne metode

// privatne metode

// pomone klase

}Sve klase napisane su u skladu sa JavaBeans konvencijom. [15] U odnosu na standardne Java klase, jedina bitna razlika u strukturi koda vizualnih klasa je glavna inicijalizacijska metoda, koja se pokree iz konstruktora. Ta metoda inicijalizira modul i pokree inicijalizacijske metode svih njegovih vizualnih komponenti.4.3.1. Izvedba glavnog modula

Glavni modul predstavljen je klasom MainGUI. Ova klasa predstavlja glavnu i najveu klasu aplikacije, te definira njezinu osnovnu grafiku strukturu, na koju se nadovezuju ostali moduli. Pri pokretanju aplikacije obavlja inicijalizaciju i povezivanje ostalih grafikih modula i zvunog sustava.

Klasa sadri slijedee lanske varijable:

1) SequencerWrapper m_Sequencer,2) SequencerWrapper m_LoopTool,3) SequencerWrapper m_PreviewPlayer,4) SynthesizerWrapper m_Synthesizer.Prve tri varijable su reference na omotae oko sekvencera za preglednik instrumenata, te glavni i sporedni sekvencerski modul. Sekvenceri se instanciraju u glavnom modulu pri inicijalizaciji zvunog sustava, a potom se dodijeljuju odgovarajuim modulima i meusobno povezuju. etvrta varijabla je referenca na omota oko sintesajzera, koja se instancira i povezuje u istoj metodi. Ostale lanske varijable ine vizualne komponente, meu kojima su i klase ostala 3 modula. Klase modula se u glavnom modulu nazivaju jPanelSequencer, jPanelLoopTool i jPanelMixer, jer se sve izvode iz JPanel klase i ine dio hijerarhije vizualnih JavaBean klasa glavnog modula.

Pokretanje aplikacije izvodi se iz statike metode main() glavnog modula. Metoda je prikazana na slijedeem ispisu:public static void main(String[] args) {

// metoda za pokretanje Swing aplikacije

SwingUtilities.invokeLater(new Runnable() {

public void run() {

// instanciranje glavnog modula

MainGUI application = new MainGUI();

// prikaz glavnog prozora

application.getJFrame().setVisible(true);

try {

// inicijalizacija zvunog sustava

application.initializeSoundSystem();

// inicijalizacija grafikog suelja

Application.connectGUIModules();

}

catch(Exception ex){

// hvatanje i prikazivanje iznimke

JOptionPane.showMessageDialog(

null, ex.getMessage(),"Exception info:", JOptionPane.ERROR_MESSAGE);

ex.printStackTrace();

}

}

}Za pokretanje Swing aplikacija unutar glavne metode koristi se metoda: void static SwingUtilities.invokeLater (Runnable mainClass).Ova metoda slui za pokretanje klase nakon zavretka obavljanja svih dogaaja u grafikom suelju. Na taj nain se aplikacija pokree tek nakon to su sve komponente obavile inicijalizaciju i spremne su za prikazivanje.Glavna inicijalizacijska metoda klase je metoda: JFrame getJFrame()U ovoj metodi obavlja se konfiguriranje glavnog prozora aplikacije, te njegovih komponenti. Nakon prikaza glavnog prozora prvo se inicijalizira zvuni sustav, a potom se grafiki moduli povezuju sa zvunim komponentama i meusobno.Inicijalizacija zvunog sustava obavlja se metodom:

private void initializeSoundSystem().Kod metode prikazan je u slijedeem ispisu:private void initializeSoundSystem() {

// dohvat lokalnog direktorija

LocalDir localDir = new LocalDir();

m_LocalDir = localDir.getLocalDirRef();

// instanciranje sintisajzera sa kolekcijom zvukova iz datoteke

String fileName = localDir.getLocalDirName();

fileName = fileName + "/" + "soundbanks" +

"/" + "soundbank-deluxe.gm";

File soundBankfile = new File(fileName);

m_Synthesizer = new SynthesizerWrapper(soundBankfile);

// instanciranje sekvencera i povezivanje sa sintisajzerom

m_Sequencer = new SequencerWrapper(m_Synthesizer, 4);

m_LoopTool = new SequencerWrapper(m_Synthesizer, 4);

m_PreviewPlayer = new SequencerWrapper(m_Synthesizer, 4);

}Metoda instancira sintesajzer sa podrazumijevanom kolekcijom instrumenata, a potom instancira sekvencere, predajui im sintesajzer kao argument. Povezivanje se obavlja u konstruktorima sekvencera.

Meusobno povezivanje grafikih modula i spajanje sa zvunim modulima obavlja metoda:

void connectGUIModules ().Ova metoda predstavlja sredinju toku aplikacije u kojoj se obavljaju spajanja svih klasa. Spajanje se izvodi postavljanjem referenci u klasama, analogno studijskom spajanju hardverskih komponenti. Osim spajanja klasa, na poetku funkcije se obavlja i uitavanje dostupnih instrumenata u preglednik. Kod metode prikazan je u slijedeem ispisu:

private void connectGUIModules () {

/* Explorer */

loadInstrumentsToExplorer();

/* Sequencer */

// povezivanje SequencerGUI - SequencerWrapper

jPanelSequencer.setSequencer(m_Sequencer);

// povezivanje Sequencer GUI - MixerGUI

jPanelSequencer.setMixerGUI(jPanelMixer);

/* LoopTool */

// povezivanje LoopToolGUI - SequencerWrapper

jPanelLoopTool.setSequencer(m_LoopTool);

// povezivanje LoopToolGUI - MixerGUI

jPanelLoopTool.setMixerGUI(jPanelMixer);

/* LoopTool - Sequencer */

// povezivanje SequencerGUI - LoopToolGUI

jPanelSequencer.setLoopToolGUI(jPanelLoopTool);

// povezivanje LoopToolGUI SequencerGUI

jPanelLoopTool.setSequencerGUI(jPanelSequencer);

/* Mixer */

// povezivanje MixerGUI - SynthesizerWrapper

jPanelMixer.setSynthesizer(m_Synthesizer);

// povezivanje Mixer - LoopToolGUI

jPanelMixer.setLoopToolGUI(jPanelLoopTool);

}4.3.2. Izvedba osnovnog sekvencerskog modulaOsnovni sekvencerski modul ini klasa BasicSequencerGUI. Ova klasa predstavlja osnovnu vizualnu klasu iz koje se izvode glavni i sporedni sekvencer. Klasa proiruje osnovnu kontejnersku klasu JPanel funkcionalnostima zajednikim za oba sekvencera, kao to su sluai na kontrolama za sviranje, metode za upravljanje dimenzijama desne tablice, klase za bojanje elija, metoda za upravljanje oznakom trenutne pozicije u sekvenci i slino. Na taj nain, sve modifikacije zajednikih funkcionalnosti izvode se na jednom mjestu. Klasa sadri slijedee lanske varijable:1) int m_TableRightColumnCount,2) int m_TablesRowCount,3) int m_TableRowHeight,4) int m_TableLeftColumnWidth,5) int m_TableRightColumnWidth,6) int m_ActiveColumn,7) Vector m_trackProperties,8) SequencerWrapper m_Sequencer,9) MainGUI m_MainGUI.Prvih pet varijabli definiraju svojstva tablica sekvencera kao to su broj stupaca i redaka tablica, te visina i irina elija. Varijabla m_ActiveColumn oznaava osvijetljeni stupac, tj. trenutnu poziciju u sekvenci. Kolekcija m_trackProperties koristi se za spremanje svojstava pojedinih traka iz glavne sekvence. Sastoji se od niza TrackProperties objekata. Zadnje dvije varijable su reference na sekvencer i glavni modul aplikacije. Ostale lanske varijable ine vizualne komponente podijeljene na skupinu privatnih i skupinu zatienih komponenti. Prva skupina se koristi samo u okviru ove klase, dok se druga skupina koristi izravno u izvedenim klasama.

Klasa sadri etiri konstruktora:

1) BasicSequencerGUI (),2) BasicSequencerGUI (int p_RowCount, int p_ColumnCount),3) BasicSequencerGUI (int p_RowCount, int p_ColumnCount, MainGUI p_MainGUI, SequencerWrapper p_SequencerGUI),4) BasicSequencerGUI (int p_RowCount, int p_ColumnCount, MainGUI p_MainGUI, SequencerWrapper p_SequencerGUI, String p_TableLeftTitle).Osnovni konstruktor koristi konstruktor nadklase JPanel, te nakon njega pokree inicijalizacijsku metodu initialize(). Ostali konstruktori sadre opcionalne parametre, koji se takoer mogu postaviti koritenjem javnih metoda za postavljanje lanskih variabli (eng. geter). Inicijalizacijska metoda prikazana je u slijedeem ispisu:private void initialize() {

// postavljanje vizualnih parametara klase

this.setSize(800, 200);

this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

this.setPreferredSize(new Dimension(300, 30));

this.add(getJPanelTop());

this.add(Box.createRigidArea(new Dimension(0,1)));

this.add(getJScrollPane());

// Slusai

// slusa promjena na kontrolama za sviranje - play / pause

jButtonPlayPause.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e) {

if (getSequencer().isRunning()) {

// pauza (stop() izvodi samo zaustavljanje,

// bez vraanja na poetak)

getSequencer().stop();

}

else {

// metoda za nadogradnju

listenerPlay(false, true, getActiveColumn());

}

}

});

// slusa promjena na kontrolama za sviranje - play looped // pause

jButtonPlayPauseLooped.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e) {

if (getSequencer().isRunning()) {

getSequencer().stop();

}

else {

// metoda za nadogradnju

listenerPlay(true, true, getActiveColumn());

}

}

});

// slusa na playback kontrolama - stop

jButtonStop.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e) {

// javna metoda

stopPlayBack();

}

});

// osvjetljavanje prve kolone

setPlayingColumn(0);

}Metoda prvo postavlja vizualne parametre klase, potom registrira sluae i na kraju osvjetljava prvi stupac desne tablice.

Sluai su izvedeni kao anonimne unutarnje klase koje pokreu javne metode klase ili metode oznaene kao metode za nadogradnju. Te metode implementirane su u klasi praznim tijelima, jer su namijene implementaciji u nadklasama. Potpis tih metoda zapoinje sufiksom listener (eng. slua). Sluai na kontrolama za sviranje i sviranje s ponavljanjem izvedeni su takvim metodama jer se proces izgradnje sekvenci prije sviranja razlikuje u glavnom i sporednom sekvenceru. Zaustavljanje je jednako, pa je taj slua izveden javnom metodom, zajednikom za oba sekvencera.Klasa sadri slijedee javne metode:

1) void stopPlayBack() - metoda zaustavlja sviranje sekvence i postavlja poetnu poziciju,2) void clearSequence() - metoda isti sekvencu tj. brie sve zvune zapise,3) int getBarCount() - metoda vraa broj stupaca desne tablice,4) void setHeaderTableRight() - metoda postavljanja zaglavlja desne tablice (ispisuje vremensku liniju),5) void setHeaderTableLeft(String p_HeaderLeftTable) - metoda postavlja zaglavlje lijeve tablice (komponente),6) void repaintTables(boolean p_RepaintLeft, boolean, p_RepaintRight) metoda osvjeava tablice,7) Vector getTableRightColumnIdentifiers() - metoda postavlja zaglavlja stupaca desne tablice,8) void setVisibleToolbars(boolean p_Playback, boolean p_Track, boolean p_Channel, boolean p_BPM, boolean p_Bars, boolean p_Volume) - metoda odreduje vidljive alatne trake,9) void setBPM (Double p_bpm) - metoda postavlja tempo u BPM-ima (eng. Beats per minute),10) Double getBPM() - metoda dohvaa tempo u BPM-ima,11) void setBarCounterOptions(int p_Value, int p_Min, int p_Max, int p_Step) - metoda namjeta opcije na brojau stupaca,12) void setChannelList(String[] p_Channels) - metoda postavlja popis kanala u izbornik za odabir kanala,13) void setRenderer(TableCellEditor p_TEditor) - metoda postavlja podrazumijevanu klasu za prikaz elija,14) void setPlayingColumn(int p_Column) - metoda oznaava zadani stupac u tablici,15) void highlightColumn(int p_Column, boolean p_HLightOn) - metoda oznaava ili ponitava oznaavanje odabranog stupca.Izvedene klase nadograuju slijedee zatiene metode, koje se pozivaju iz sluakih anonimnih klasa vizualnih komponenti, implementiranih na nain prikazan u inicijalizacijskoj metodi klase:1) void listenerMetaEventFired(MetaMessage event) - metoda koja se pokree pri generiranju meta dogaaja na sekvenceru,2) void listenerSetBarCount(int p_BarCount) - metoda se pokree kod promijene veliine sekvence,3) void listenerVolumeStateChanged() - metoda koja se pokree pri promijeni vrijednosti glasnoe,4) void listenerTableSelectedCellChanged(Jtable m_table, int p_SelRow, int p_SelColumn) - metoda koja se pokree pri promjeni selekcije u tablici,5) void listenerPlay(boolean p_Loop, boolean store, long p_TickPosition) - metoda koja pokree sviranje sekvence,6) void listenerStoreTrack() - metoda koja pohranjuje podatke iz tablice i gradi zvunu sekvencu.

Klasa osnovnog sekvencerskog modula sadri dvije pomone klase:

1) SelectionListener - klasa se koristi za upravljanje selekcijom nad tablicom. Predstavlja sluaku klasu koja se registrira nad tablicom, dohvaa poziciju selektirane elije tablice, te pokree vanjsku metodu za nadogradnju koja izvodi potrebne operacije nad elijom, ovisno o potrebama sekvencera.2) TColors - klasa sadri konstante koje predstavljaju boje desne tablice u RGB zapisu (Red Green Blue). Na ovaj nain, nijanse bojanja se mogu izmijeniti jednostavnim mijenjanjem vrijednosti zadanih konstanti.4.3.3. Izvedba glavnog sekvencerskog modula

Klasa glavnog sekvencerskog modula izvedena je iz prethodno opisane klase osnovnog sekvencerskog modula. Ova klasa upravlja izgradnjom i sviranjem glavne sekvence.Klasa sadri slijedee lanske varijable:

1) boolean m_Loading - zastavica koja oznaava uitavanje podataka i onemoguava sluake klase,2) LoopToolGUI m_LoopToolGUI - referenca na sporedni sekvencerski modul,3) MixerGUI m_MixerGUI - referenca na kontrolni modul,4) int m_LoopToolBarCount - duina sekvence sporednog sekvencerskog modula.

Konstruktori su izvedeni kao kod osnovnog modula, pa imamo jedan osnovni i tri opcionalna konstruktora sa dodatnim parametrima:

1) SequencerGUI(),2) SequencerGUI(int p_RowCount, int p_ColumnCount),3) SequencerGUI(int p_RowCount, int p_ColumnCount, MainGUI p_MainGUI, SequencerWrapper p_SequencerGUI),4) SequencerGUI(int p_RowCount, int p_ColumnCount, MainGUI p_MainGUI, SequencerWrapper p_SequencerGUI, String p_TableLTitle).Inicijalizacijska metoda klase prikazana je slijedeim ispisom:private void initialize(){

// postavljanje prikazivaa elija za desnu tablicu

setRenderer(new TableCellColorEditorSequencer());

// postavljanje vidljivih alatnih traka

setVisibleToolbars(true, false, false, true, true, true);

// namjetanje brojaa stupaca

setBarCounterOptions(16, 16, 999, 1);

// inicijalizacija popisa traka

setTrackProperties(new Vector());

// sprijeavanje podrazumijevane akcije pritiskom na "delete"

turnOffDefaultAction(jTableLeft, "DELETE");

// postavljanje glavne aplikacijske kontrole glasnoe

setMasterVolume(127);

// dodavanje slusaa promjena na kontrolu glasnoe

jSliderVolume.addChangeListener(new ChangeListener() {

public void stateChanged(ChangeEvent e) {

if (m_MixerGUI != null) {

m_MixerGUI.setGain(jSliderVolume.getValue());

}

}

});

// dodavanje sluaa za uklanjanje traka na lijevu tablicu

jTableLeft.addKeyListener(new KeyListener(){

public void keyPressed(KeyEvent e) {

}

public void keyReleased(KeyEvent e) {

if(e.getKeyChar() == KeyEvent.VK_DELETE)

{

int index = jTableLeft.getSelectedRow();

if(index != -1) removeTrackFromTable(index);

}

}

public void keyTyped(KeyEvent e) {

}

});

// dodavanje sluaca promjena na lijevu tablicu

// slusac vrsi sinhronizaciju kolekcija popisa traka // izmedu sekvencera i looptoola

jDefaultTableModelLeft.addTableModelListener( new TableModelListener(){

public void tableChanged(TableModelEvent e) {

if (!isLoading()) {

int index = e.getLastRow();

switch(e.getType()){

case TableModelEvent.INSERT:

break;

case TableModelEvent.DELETE:

if(index != 0)

index--;

break;

case TableModelEvent.UPDATE:

String tName = (String)jDefaultTableModelLeft.getValueAt(index, 0);

try {

// provjera da li traka postoji

if ( index