Incremental Leadsheet Editor -...

84
Departement Industri¨ ele Wetenschappen Vakgroep Informatica Academiejaar 2010–2011 Incremental Leadsheet Editor Rik Bauwens Externe Promotor: Dr. W. Schepens Interne Promotor: Dhr. G. Hurtado Mart´ ın Scriptie voorgedragen tot het behalen van de graad van Master in de Industri¨ ele Wetenschappen

Transcript of Incremental Leadsheet Editor -...

Page 1: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Departement Industriele WetenschappenVakgroep Informatica

Academiejaar 2010–2011

Incremental Leadsheet Editor

Rik Bauwens

Externe Promotor: Dr. W. Schepens

Interne Promotor: Dhr. G. Hurtado Martın

Scriptie voorgedragen tot het behalen van de graad van

Master in de Industriele Wetenschappen

Page 2: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Copyright 2010, 2011 Rik Bauwens. Alle rechten voorbehouden. Dit werk mag worden verveelvoudigd en/of

openbaar gemaakt door middel van druk, fotokopie, microfilm, geluidsband, kleitabletten, elektronische of

welke andere wijze ook, onder de volgende voorwaarden:

� Vermelding van de auteur.

� Als je dit werk wijzigt en/of verdeelt, moet dit gebeuren onder dezelfde voorwaarden.

De auteur is niet aansprakelijk voor eventuele fouten en onvolledigheden in dit werk.

Versie 0.6.0

Gecompileerd op: 16 juni 2011

Page 3: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Woord vooraf

Vooreerst wil ik mijn interne promotor, dr. Wijnand Schepens, bedanken voor de creatieve ideeen,

hulp bij het ontwikkeling van het graafsysteem en bijsturing waar dat nodig was. Ook Jannes Plyson,

medestudent aan Hogeschool Gent, zou ik graag willen bedanken voor de goede samenwerking aan dit

overkoepelend project. Vervolgens wil ik mr. Hurtado bedanken voor de begeleiding bij mijn eindwerk.

Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier bij de verwezelijking van dit

eindwerk betrokken was voor hun steun, hulp en geduld.

Rik Bauwens

Gent, Juni 2011

iii

Page 4: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

iv

Page 5: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Samenvatting

In deze scriptie wordt het achterliggende idee van de Incremental Leadsheet Editor toegelicht, alsook de

implementatie en deployment ervan. Dit project is ontwikkeld als laatstejaarsproject voor de opleiding

industriele wetenschappen, afstuddeerrichting informatica. Deze applicatie tracht de cliches waarin

een klassiek, notationeel muziekprogramma dikwijls vervalt, te doorbreken. Hiermee wordt bedoeld

dat de gebruiker in dergelijk programma vaak begrensd wordt in zijn muzikale vrijheid doordat het

programma zelf een resem aan regels oplegt aan de partituur. In wezen is hier niets mee en zorgt

het ervoor dat de partituur altijd volledig muzikaal correct is, maar voor beginnende muzikanten of

muzikanten met een beperkte theoretische achtergrond vormt dit vaak een struikelbrok. Daardoor

wordt meestal niet de moeite genomen om de muziek op een degelijke manier neer te schrijven. In

deze editor wordt de gebruiker zo vrij mogelijk gelaten, zodat hij zelfs dingen kan ingeven die muzikaal

niet volledig correct zijn. Ook enkel ritme, tekst of akkoorden ingeven behoort tot de mogelijkheden.

Ritme kan getikt worden op het toetsenbord en op de leadsheets kunnen zelfs notities geplakt worden

om de samenwerking met andere mensen eenvoudiger te maken, door bijvoorbeeld tips over hoe iets

gespeeld moet worden, aan te geven. De gehele editor is gebouwd op een graafsysteem, dat uitvoerig

behandeld wordt in hoofdstuk 3. In zekere zin maakt dit de applicatie uniek omdat niet het klassieke

pad van programmeren gevolgd werd. Er is geen duidelijke opsplitsing in model-view-controller, wat

bij een GUI applicatie anders wel gebruikelijk is.

v

Page 6: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

vi

Page 7: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Summary

In this thesis, the underlying idea for the Incremental Leadsheet Editor is explained, as well as its

implementation and deployment. This application was developed in order to achieve the degree of

Master in Applied Engineering (specialization Computer Science). This project tries to breach the

stereotypes which accompany most of musical editors. These editors tend to restrict users in achieving

their goal of writing down their music, due to the use of norms and rules. Essentially, this is a good

thing as it ensures that the leadsheet is universal and thus can be read by anyone who has the right

musical background and knowledge. In some cases, however, it is desirable that a group of musicians

can just write their music down in a way they prefer and understand. There are some great musicians

out there who do not have the theoretical background for writing down their music and therefore are

not able to do so. In this editor, the user is liberated from the rules and given the freedom of adding

almost anything he wants to the leadsheet, in any order. It’s also possible to enter only rhythm,

chords or lyrics. Rhythm can even be tapped on the keyboard, the editor does the work and creates a

leadsheet for the tapping pattern. Moreover, scribbles can be added to encourage cooperation between

musicians, for example by giving directions on certain parts of the leadsheet. Eventually, the editor

is built on a connected graph, extensively discussed in chapter 3. In a certain way, this makes this

application unique because of the fact that the usual programming style is more or less abandoned. A

clear distinction between model, view and controller is avoided, despite the fact that this is a common

use for GUI applications.

vii

Page 8: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

viii

Page 9: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Inhoudsopgave

1 Inleiding 1

1.1 Verduidelijking van de titel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.1 Incremental . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.2 Leadsheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.1.3 Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.2 Waarom? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Onderzoek 5

2.1 Notes bij Finale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.2 Notes bij Noteflight . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.3 De analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3 Het graafsysteem 9

3.1 De knopen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.2 De voorwaarden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3.3 De relaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3.3.1 De basisrelaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.3.2 Afgeleide (numerieke) relaties . . . . . . . . . . . . . . . . . . . . . . . 14

3.3.3 Intervallen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3.4 De observable graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

4 Het model 21

4.1 Het idee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

4.2 Het model zonder relaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

4.2.1 Tijdstempels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4.2.2 Tijdlijn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

4.3 Het model met relaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

4.3.1 Deel van een groter geheel . . . . . . . . . . . . . . . . . . . . . . . . . 26

4.3.2 Splitsing van de tijdlijnen . . . . . . . . . . . . . . . . . . . . . . . . . 27

4.3.3 Gebruik van muzikale tijd . . . . . . . . . . . . . . . . . . . . . . . . . 30

4.3.4 Het opslaan van redundante gegevens . . . . . . . . . . . . . . . . . . 31

ix

Page 10: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Inhoudsopgave x

5 De tussenliggende relaties 33

5.1 De merge operatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

5.2 De split operatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

5.3 Mappen van muzikale tijden op x posities . . . . . . . . . . . . . . . . . . . . 37

5.3.1 De TicksToXMapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

5.3.2 De RelationBuilder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

6 De view 41

6.1 Het Coordinatensysteem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

6.1.1 Eerste aanpak: het Graphics object . . . . . . . . . . . . . . . . . . . 41

6.1.2 Tweede aanpak: een apart coordinatensysteem . . . . . . . . . . . . . 42

6.2 Het graafsysteem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

6.2.1 Toegepast op Java Swing componenten . . . . . . . . . . . . . . . . . 43

6.2.2 Toegepast op het tekenen . . . . . . . . . . . . . . . . . . . . . . . . . 46

6.3 Het tekenen van de symbolen . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

6.3.1 De StaffSymbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

6.3.2 De GroupSymbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

6.4 Een extraatje: Scribbles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

7 Deployment 59

8 Conclusies en perspectieven 63

8.1 Een stukje van de taart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

8.2 Uitbreidmogelijkheden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

8.3 Het betaprogramma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

A Muzikale termen 67

B Muzikale symbolen 69

C Kwintencirkel 71

D Beknopte handleiding 73

Page 11: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 1

Inleiding

1.1 Verduidelijking van de titel

In wat volgt zal kort toegelicht worden wat juist bedoeld wordt met de titel, aangezien die

misschien niet zo voor de hand liggend is.

1.1.1 Incremental

Met incrementeel wordt bedoeld dat de partituur, die ingegeven wordt door de gebruiker,

gaandeweg kan aangepast en veranderd worden, ongeacht de volgorde. Het is deze mogelijk-

heid die deze editor onderscheidt van de reeds honderden andere editors. Een reguliere editor

(bijvoorbeeld Finale, Sibelius, Noteflight, Rhythmbox) is vooral partituurgericht. Hiermee

wordt bedoeld dat de aandacht vooral gevestigd wordt op de partituur zelf, en niet op de

muzikaliteit zelf van een stuk. Er wordt altijd vertrokken van een notenbalk, met een be-

paalde voorteking en maatcijfer. Deze zijn de hoofdelementen en zijn onontbeerlijk voor een

partituur, meer zelfs, het is niet mogelijk een partituur in te geven zonder een notenbalk met

een voorteking en maatcijfer te definieren. Daardoor wordt een groot deel van potentiele

gebruikers overgeslagen. Er zijn immers veel muzikanten, die enkel geınteresseerd zijn in een

bepaald aspect van een partituur. Bij een drummer is dit bijvoorbeeld ritme, maar voor een

zanger kan dit enkel melodie of tekst zijn, of een combinatie van beide. Deze editor zal zich

dus vooral richten op deze doelgroep, en de mogelijkheid bieden om enkel ritme, melodie,

tekst of akkoorden in te geven. Het feit dat deze editor een webapplicatie is, schept talloze

mogelijkheiden, waarvan volgend scenario slechts een van de vele mogelijkheden is.

� Een drummer, ergens in de wereld, heeft een bepaald ritme gevonden, maar heeft niet

de kennis om hierbij een tekst of melodie te verzinnen. Hij voert dit ritme met behulp

van kruisjes in op de online partituur. Hierbij wordt enkel ritme aangegeven, en wordt

dus geen toonhoogte ingegeven.

� Een gitarist, die ook kennis heeft van deze editor, is goed in melodieen schrijven, maar

1

Page 12: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 1. Inleiding 2

heeft geen muziektheoretische achtergrond. Hij speelt enkel op gehoor en weet niet hoe

een bepaalde noot klinkt. Hij kan deze melodie wel invoeren, omdat bij het invoegen

van een noot, deze afgespeeld wordt. Hij voert bijgevolg deze melodie in en koppelt ze

aan het ritme, ingevoerd door de drummer.

� Tenslotte is er een dichter, die graag een van zijn teksten op muziek zou willen zetten.

Hij is echter niet zo goed in het vinden van melodieen of het uitzoeken van ritmes.

Zodoende gaat hij op de website die partituren voor deze editor verzamelt, op zoek

naar partituren die wel een ritme en melodie, maar geen tekst bevatten. Hij koppelt de

lettergrepen van zijn tekst aan tonen van de partituur (over welke noot het gaat maakt

opnieuw niet uit).

De nadruk van deze editor ligt dus vooral op flexibiliteit en vrijheid, in tegenstelling tot de

meeste andere partituureditors, die vooral gericht zijn op de partituur zelf, en de muzikale

correctheid ervan.

1.1.2 Leadsheet

Een leadsheet is een document dat bestaat uit meer dan een notenbalk met noten alleen.

Er kunnen ook onder andere lyrics en akkoorden toegevoegd worden. Maar ook een tijd-

lijn, waarbij tijdsaanduidingen kunnen versleept worden, behoort tot de mogelijkheden. Een

leadsheet hoeft dus geen zuivere muziekpartituur te zijn.

1.1.3 Editor

Naast het weergeven van de leadsheet is het ook nodig dat alle elementen ervan kunnen ver-

plaatst, toegevoegd en gewist worden, en dit op een intuıtieve manier. De editeeracties vormen

de hulpmiddelen om een overzichtelijke leadsheet op te bouwen, en zijn hierbij onontbeerlijk.

1.2 Waarom?

Nu blijft de vraag, waarom een editor maken, als er al zo veel verschillende alternatieven

bestaan? De drijfveer voor het bouwen van een editor is meervoudig.

� Eerst en vooral is het incrementele aspect een van de sleutelfuncties van deze editor.

Bijna alle reeds bestaande editors zijn vooral gericht op geschoolde muzikanten, die hun

muziek willen vastleggen onder de vorm van een muziekpartituur, net zoals een auteur

een boek zou schrijven om een concrete afdruk van zijn verhaal te krijgen. Het probleem

dat reeds aangekaart werd in subparagraaf (1.1.1), is dat een amateurmuzikant niet

altijd de volledige theoretische onderbouw heeft omtrent muziekpartituren, waardoor

het moeilijk wordt om een partituur met een van deze programma’s op te bouwen. Ook

Page 13: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 1. Inleiding 3

niet iedereen is geınteresseerd in alle delen van een partituur, en wil bijvoorbeeld enkel

lyrics schrijven.

� Een tweede pijler is dat deze editor een online applicatie is. Ze kan dus door iedereen

over de gehele wereld gebruikt worden, zonder dat het nodig is om extra programma’s

te installeren. Ook wanneer er een nieuwe versie van het programma beschikbaar is,

wordt deze automatisch door iedere gebruiker gebruikt, omdat er maar een versie van

het programma in omloop is (deze die als online applicatie aangeboden wordt).

� Tenslotte is het, dankzij het achterliggende model, eenvoudig om te zoeken in een par-

tituur. Dit biedt enkele interessante toekomstperspectieven: op de website waar de

applicatie gedistribueerd wordt, kan bijvoorbeeld een zoekfunctie aangeboden worden,

waarin een gebruiker de mogelijkheid gegeven wordt te zoeken op alle leadsheets met

een bepaalde melodie of ritme. Of alle leadsheets die enkel melodie in ritme bevatten, en

waarvoor een gebruiker dan lyrics kan schrijven. Dit eindwerk zal zich dus vooral rich-

ten op bovenstaande uitgangspunten, en niet op de traditionele editeracties, die reeds

in elke partituureditor te vinden zijn. Een schematische voorstelling is weergegeven in

figuur 1.1.

Figuur 1.1: Het doel van deze applicatie

Page 14: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 1. Inleiding 4

Page 15: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 2

Onderzoek

Tijdens de eertse fase van mijn masterproef werden er andere partituureditors onder de loep

genomen om na te gaan hoe bepaalde acties geımplementeerd worden en hoe bepaalde pro-

blemen opgevangen worden. Bovendien schepte het een idee over hoe een editor er hoort uit

te zien. Deze analyse werd uitgevoerd voor het softwarepakket Finale1, en de online parti-

tuureditor Noteflight.2 (figuur 2.1). De volgende twee paragrafen beslaan een korte neerslag

van die analyse.

2.1 Notes bij Finale

Bij het starten van het programma en aanmaken van een nieuw document wordt automatisch

een volledig blad opgevuld met notenbalken in solsleutel, waarvan alle maten opgevuld zijn

met hele rusten (er wordt automatisch een maatcijfer 4 4 toegekend). De vragen die we ons

hierbij kunnen stellen is waarom de sleutel reeds ingevuld wordt en waarom het maatcijfer 4 4

gekozen wordt. Het feit dat net die sleutel en dat maatcijfer gekozen wordt ligt voor de hand,

1Finale is een softwarepakket dat op dit de facto standaard is voor muzieknotatiesoftware. Het programma

wordt ontwikkeld door MakeMusic2http://www.noteflight.com

Figuur 2.1: Schermafbeelding van achtereenvolgens MakeMusic Finale en Noteflight

5

Page 16: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 2. Onderzoek 6

want het zijn ook de meest gebruikte. Maar waarom wordt de pagina ineens opgevuld met

notenbalken die gevuld zijn met rusten, ervan uitgaande dat het zo zal zijn dat de partituur

er zal uitzien. Het blijkt niet direct mogelijk te zijn om een lege partituur aan te maken.

Blijkbaar is het ook niet direct (intuıtief) mogelijk om een maat zelf te verwijderen: bij het

selecteren van een maat en het drukken op de delete toets wordt enkel de inhoud van de

maat vervangen door rusten (in dit geval een hele rust). Ongetwijfeld zal dit wel ergens

mogelijk zijn, maar misschien zou het duidelijker moeten zijn hoe dit bereikt wordt. Titel

en uitvoerder worden standaard ingevuld met titel respectievelijk uitvoerder tussen vierkante

haken. Het is wel mogelijk deze weg te laten door de inhoud van het tekstveld te wissen.

Voor het invoeren en bewerken van de partituur wordt gebruik gemaakt van verschillende

editeermodussen. Bovenaan, onder de menubalk is een toolbox weergegeven waar keuze is

tussen onder andere noten, rusten, wijzigingstekens, sleutels, en selecteermodus. Om een

noot toe te voegen stelt men de juiste modus in. Er verschijnt dan een caret3 binnen de

huidige positie van de partituur. Er wordt ineens een (anders gekleurde) noot weergegeven,

die zou ingevoegd worden bij het toevoegen. Het is mogelijk zijn toonhoogte te wijzigen

door de pijltjes omhoog en omlaag te gebruiken. Tegelijkertijd is het ook mogelijk om met

behulp van de muis een noot in te voegen waar de muiscursor op dat moment staat. Er is

ook een duidelijk onderscheid tussen de huidige positie (roze noot), en de in te voegen noot

(grijs). Wat wel mogelijk is, is het invoeren van noten gebruikmakend van het toetsenbord

(A, B, C, ...)4, hetgeen snel overtypen van partituren gemakkelijker maakt. Toevoegen van

akkoorden boven de notenbalk behoort ook tot te mogelijkheden. Er wordt effectief nagegaan

of een akkoord voorkomt in een opgeslagen bibliotheek, en indien dit het geval is, wordt het

akkoord dan ook gepast weergegeven. Voorts kan een onbekend akkoord toegevoegd worden

aan de bibliotheek. Dit is een groot voordeel aangezien er voor een en hetzelfde akkoord soms

tientallen schrijfwijzen bestaan. Op die manier kan iedereen zijn eigen schrijfwijze gebruiken.

Onderaan het programma is een balk voorzien die tips en een korte uitleg geeft bij de huidige

actie (bijvoorbeeld Use the menu to create and edit lyrics and position them on the score).

Links is er nog een toolbox voorzien met verschillende ritmes, voorgesteld als noten (hele

noot, halve noot, triool, ...). Het is mogelijk bij het afspelen te kiezen hoe lang een kwartnoot

duurt door de BPM5 in te stellen(standaard is dit 120), en zo de snelheid van het stuk te

bepalen. Bij het effectief afspelen van de partituur wordt een glijdende caret getoond, die

de positie van het afspelen binnen de partituur aanduidt. Noten, rusten of maten blijven

ongewijzigd (de noot zelf wordt niet gemarkeerd bij het afspelen).

3Verticale lijn die een positie aanduidt waar kan ingevoegd worden (cfr. caret in Microsoft Word) In dit

geval is dit een positie binnen de partituur.4Appendix A5Beats per minute.

Page 17: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 2. Onderzoek 7

2.2 Notes bij Noteflight

Ook hier wordt gebruikgemaakt van een caret bij het intypen van de partituur. Bij het

invoeren wordt de maat geselecteerd waar ingevoegd wordt. Met behulp van de muis kan

dan een positie van de noot (toonhoogte) gekozen worden. Bij het gebruik van pijltjestoetsen

wordt alles wat geselecteerd is een toon naar boven of naar onder verschoven. Ook hier wordt

automatisch een maatcijfer 4 4 gegenereerd. Bij het selecteren van meerdere noten en het

verschuiven worden alle noten uit de selectie mee verschoven. Telkens een noot ingevoegd

wordt, wordt afgespeeld wat precies tussengevoegd wordt (dit is storend bij het overtypen

van een partituur, maar wel handig omdat men het meestal direct hoort wanneer er een foute

noot ingevoegd werd). Omdat het in Flash applicaties niet mogelijk is gebruik te maken van

rechtsklikken, wordt een toolbox voorzien, die verplaatst kan worden binnen het document.

Er is een mogelijkheid tot het kiezen tussen een Page en Strip layout. Dit is bevorderend

voor de flexibiliteit van het programma, omdat zo iedereen de editor naar eigen smaak kan

inrichten. Een Strip Layout zou bijvoorbeeld bruikbaar zijn bij het afspelen van een partituur,

omdat dan niet telkens van lijn moet veranderd worden (dit bemoeilijkt het meevolgen van de

partituur). Ook hier wordt een standaard titel en uitvoerder voorzien. Boven de maten wordt

per maat een balkje voorzien (dat enkel zichtbaar wordt wanneer er met de muis over bewogen

wordt) dat bij aanklikken de volledige maat selecteert. Ook twee icoontjes, een voor en een

achter elke maat, worden automatisch weergegeven bij de maat die gehighlighted wordt. Deze

kunnen gebruikt worden om een maat voor respectievelijk achter de aangeduidde maat in te

voegen.

2.3 De analyse

Uit de analyse van de voorvernoemde programma’s kan een en ander onthouden worden over

hoe een editor er zou moeten uitzien. Ook kan onthouden worden wat er goed en wat er minder

goed uitgewerkt was, en hoe de verschillende acties geımplementeerd werden. Concreet kan

volgende wishlist opgesteld worden.

� Het gebruik van een caret bleek van pas te komen, omdat het altijd duidelijk aangeeft

waar in een partituur men zich bevindt, en waar men precies invoegt of verwijdert. Het

voelt ook intuıtief aan omdat men deze werkwijze reeds gewoon is van de tekstverwerker.

� Wat wel opvalt, is dat elk programma gebruik maakt van een soort toolbox, waar

men symbolen kan uitslepen en plakken op een partituur. De vraag is vooral of dit veel

gebruikt wordt, aangezien het invoegen met behulp van het toetsenbord veel sneller gaat.

Een volledige partituur samenstellen door slepen lijkt ons een onhandig systeem, dus

zal de focus liggen bij het invoegen van symbolen, gebruikmakend van het toetsenbord.

� In beide geteste programma’s wordt vertrokken van een soort dummy partituur. Dit

Page 18: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 2. Onderzoek 8

wil zeggen dat er bij het aanmaken van een nieuw document reeds een aantal maten

getekend worden, voorzien van een sleutel en een maatcijfer. Dit kan uiteraard later

nog aangepast worden, maar maakt het moeilijker om enkel lyrics of akkoorden in te

voeren. Het zal er bij deze editor dus vooral op aankomen om deze mogelijkheid wel te

voorzien, aangezien de nadruk op het incrementeel opbouwen ligt.

� Tenslotte is er in geen enkel programma een mogelijkheid te vinden om eenvoudig com-

mentaar bij een partituur te schrijven (die niet op een of andere manier vasthangt aan

een partituur). Het zou handig zijn om de mogelijkheid te kunnen bieden dat een ge-

bruiker persoonlijke notities kan maken bij delen van zijn partituur, die bijvoorbeeld

enkel zichtbaar zijn op het scherm en niet bij het afdrukken. Dit kan vooral van pas

komen als leidraad voor een andere gebruiker wanneer die iets wil toevoegen aan de

partituur.

Tijdens de ontwikkeling van de editor zullen deze bedenkingen in het achterhoofd gehouden

worden om een algemeen beeld te vormen over hoe bepaalde dingen er moeten uitzien en hoe

acties het best geımplementeerd worden.

Page 19: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3

Het graafsysteem

In dit hoofdstuk zal het achterliggende idee van de editor toegelicht worden. In wezen is

het gehele systeem gebaseerd op een graafsysteem. Dit is eigenlijk een alternatieve opvatting

van het observer pattern1, wat wel meer gebruik wordt in een GUI applicatie. Een GUI

applicatie bestaat doorgaans uit een model, dat de gegevens ordent, bijhoudt en toegankelijk

maakt, en uit een view, die de gegevens toont en gebruikersmanipulatie toelaat. Dit impliceert

dat deze twee altijd met elkaar gesynchroniseerd moeten worden, en dus in principe elkaar

altijd exact moeten weerspiegelen. Dit is het uitgangspunt van het graafsysteem, die deze

synchronisatie en gelijkheid garandeert en verzorgt. Een voorbeeld van een eenvoudige graaf

is weergegeven in figuur 3.1. In de volgende paragrafen zullen de verschillende elementen van

de graaf toegelicht worden.

3.1 De knopen

Een eerste basiselement van de graaf zijn knopen. In het graafsysteem zijn dit eigenlijk niets

meer dan objecten met een waarde van een bepaald type (de staat). Verder zijn deze knopen

ook observable, waardoor andere objecten er kunnen naar luisteren. Er zijn twee soorten

knopen: knopen die kunnen veranderen van waarde (variable of mutable), en deze die bij

initialisatie een bepaalde waarde krijgen en vanaf dan constant zijn. Het type van de waarde

van de knoop wordt meegegeven bij constructie aan de hand van een template parameter. Het

klassenschema wordt gegeven in figuur 3.2. De meest typische implementatie van een knoop

is een BasicValueNode. Deze heeft een attribuut en is observable, zoals hierboven beschreven.

De implementatie is triviaal (codevoorbeeld 3.1).

1Het observer pattern definieert een een-op-veel relatie tussen objecten, zodanig dat wanneer de toestand

van een object verandert, alle afhankelijke objecten worden bericht en automatisch worden geupdatet. Java

ondersteunt dit pattern via meerdere API’s, met name de Observer interface en de Observable klasse. (Head-

first design patterns, O’Reilly)

9

Page 20: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 10

Figuur 3.1: Voorbeeld van het graafsysteem

Codevoorbeeld 3.1: Implementatie van BasicValueNode

public class BasicValueNode<T> extends BasicNode implements MutableValueNode<T>

{private T value ;

public T getValue ( )

{return value ;

}

public void setValue (T value )

{this . va lue = value ;

// a l l e o b s e r v e r s op de hoogte brengen , u i t g e zonderd z i c h z e l f

not i f yObse rve r s ( this ) ;

}}

Deze implementatie van een knoop brengt zijn observers op de hoogte van zodra zijn waarde

gewijzigd werd. Het dient opgemerkt te worden dat een knoop bij het oproepen van de notify

() functie de functie onNotify(Object source) van zijn observers aanroept, en dus op geen

enkele manier zijn staat meedeelt. Een observer moet de staat van de knoop zelf opvragen

door de getValue() methode op te roepen.

Page 21: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 11

Figuur 3.2: Klassenschema van de knoop

Page 22: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 12

3.2 De voorwaarden

Wat we met deze knopen trachten te bereiken is het automatisch voldoen aan opgelegde

voorwaarden voor bepaalde variabelen gebruikt in het programma. Als eerste voorbeeld werd

er reeds aangehaald dat de view van een programma altijd moet weerspiegelen wat er zich in

de gegevenslaag bevindt. Als we in de gegevenslaag een knoop voorzien die de daadwerkelijke

waarde bijhoudt, moeten we in staat zijn deze op een of andere manier te koppelen aan de

grafische representatie in de view. Deze gelijkheid moet ook omgekeerd gelden, zodat we ons

geen zorgen meer hoeven te maken over het in orde brengen van deze gelijkheid. Dit gebeurt

immers automatisch. Niet alle voorwaarden zijn echter even triviaal. Soms zal het alsnog

nodig zijn om manueel in te grijpen. Vooral wanneer iets niet meer automatisch kan berekend

worden, meestal ten gevolge van gebruikersspecifieke invoer, zijn deze voorwaarden niet meer

gebaseerd op vaste parameters, maar kunnen deze varieren van situatie tot situatie.

De waarde van een knoop kan op twee manieren aangepast worden. Een andere knoop kan dit

expliciet doen (het push mechanisme, hierbij moet de andere knoop de eerste knoop kennen

en de methode setValue() oproepen), ofwel berekent de knoop zelf zijn staat altijd opniew

bij het opvragen ervan (het pull mechanisme, de eerste knoop kent de tweede en roept hiervan

de getValue() methode op).

De voorwaarden opslaan in een knoop zelf is echter geen flexibele oplossing. Op die manier

ontstaat er een grote hoeveelheid aan code die eigenlijk overbodig is. Conceptueel is dit ook

niet echt correct omdat elke knoop in principe hetzelfde is, met enkel eventueel een verschil

in staat. Bovendien zijn de voorwaarden enkel unidirectioneel gedefinieerd, waardoor de

bidirectionele voorwaarden (zoals twee knopen die steeds dezelfde waarde moeten hebben)

twee keer gedefinieerd moeten worden. Er is om die redenen gekozen om voorwaarden apart

de definieren. Deze worden verder relaties genoemd.

Knopen kunnen op die manier hun observers op de hoogte brengen van wijzigingen aan hun

staat. Zo kunnen die observers op de wijzigingen in die knoop reageren. Als deze observer

dan een object is dat meerdere knopen verzamelt, kan deze de staat van zijn andere knopen

ook veranderen, afhankelijk van de nieuwe staat van de eerste knoop. Dit brengt ons bij de

concrete implementatie van deze voorwaarden: de relaties.

3.3 De relaties

Voorwaarden tussen de knopen uitdrukken gebeurt dus aan de hand van een nieuw soort

object: het relatieobject. Dit is opnieuw een observer (luisteraar), die luistert naar de knopen

die het bevat. Als reactie op de wijziging van de staat van een van zijn knopen, kan het de

staat van de andere knopen aanpassen. Wat deze aanpassing inhoudt, hangt af van het type

Page 23: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 13

relatie. Er zijn twee basisrelaties gedefinieerd.

3.3.1 De basisrelaties

Er zijn twee basisrelaties gedefinieerd: een voor twee knopen (ABRelation), en een voor

drie knopen (ABCRelation). Beide relaties zijn abstract gedefinieerd en kunnen dus niet

rechtstreeks geınstantieerd worden. De update() methodes dienen oveschreven te worden

door de eigenlijke relaties.

Figuur 3.3: Klassenschema van de basisrelaties

De AB relatie De AB relatie bestaat uit twee knopen, A en B, die beide verplicht wij-

zigbaar zijn. Het type van de knopen van de relatie wordt gedefinieerd door de template

parameters bij de constructie van de relatie. De relatie kan in- en uitgeschakeld worden (het

kan bij grote wijzigingen handig zijn om bepaalde relaties tijdelijk uit te schakelen tijdens

die wijzigingen om oneindige lussen te voorkomen, of om ervoor te zorgen dat een knoop

maar een keer aangepast wordt met de goede waarde, eerder dan de waarde tientallen keren

onnodig opnieuw aan te passen tijdens een tussenbewerking).

Page 24: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 14

De ABC relatie De ABC relatie bestaat uit drie knopen, A, B en C, waarvan de eerste

verplicht constant, en de laatste twee verplicht wijzigbaar zijn. De implementatie is analoog

aan die van een AB relatie, waarbij de methode updateA() vervangen is door updateC(), dit

aangezien de waarde van knoop A constant is en dus niet gewijzigd kan worden.

3.3.2 Afgeleide (numerieke) relaties

De gelijkrelatie Deze relatie is de meest triviale en is afgeleid van ABRelation (vereist dus

het gebruik van twee knopen). De gelijkrelatie zorgt ervoor dat de betrokken knopen altijd

gelijk zijn aan elkaar. Wanneer de waarde van een knoop verandert, past de relatie de waarde

van de andere knoop aan en omgekeerd. De implementatie van de update() methodes wordt

gegeven in codevoorbeeld 3.2.

Codevoorbeeld 3.2: Implementatie van Equal

public class Equal<S> extends ABRelation<S , S>

{public Equal ( MutableValueNode<S> a , MutableValueNode<S> b)

{super ( a , b ) ;

}

@Override

public void updateB ( )

{b . setValue ( a . getValue ( ) , this ) ;

}

@Override

public void updateA ( )

{a . setValue (b . getValue ( ) , this ) ;

}}

De minimum/maximum relatie Aangezien beide relaties triviaal zijn, wordt enkel de

maximum relatie verder toegelicht. Deze relatie kan enkel nuttig zijn wanneer er meerdere

van deze relaties met dezelfde knoop A gedefinieerd zijn, en zorgt ervoor dat in knoop A

altijd de waarde terechtkomt die het maximum is van alle waarden B van deze relaties. De

implementatie is relatief eenvoudig en zorgt ervoor dat wanneer de waarde van de B knoop

wijzigt nagegaan wordt of deze nieuwe waarde groter is dan de huidige waarde van A. Als

dit het geval is, kan de waarde van A aangepast worden en is er geen verdere actie nodig. In

het andere geval moet een nieuw maximum gezocht worden, aangezien de vorige waarde van

B het vorige maximum kon zijn. De waarde van A wordt zodoende op de kleinst mogelijke

Page 25: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 15

waarde gezet. Vervolgens worden alle B’s gevraagd om hun waarde opnieuw door te geven

door updateB() op te roepen. Het is dus niet voldoende om enkel te controleren of de

waarde van een knoop B groter is dan die van knoop A. Deze werkwijze wordt geıllustreerd

in codevoorbeeld 3.3.

Codevoorbeeld 3.3: Implementatie van MaxRelation

@Override

public void updateA ( )

{//A moet enke l aangepast worden wanneer de waarde van B gro t e r i s dan

d ie van A

i f (b . getValue ( ) > a . getValue ( ) )

a . setValue (b . getValue ( ) , this ) ;

// In he t andere g e va l moet een nieuw maximum gevonden worden

else

//Bi j de knopen B wordt updateB () automatisch opgeroepen

a . setValue (new I n t e g e r ( I n t e g e r .MIN VALUE) ) ;

}

@Override

public void updateB ( )

{//Hier i s he t n i e t nodig om te con t ro l e r en op een nieuw maximum

// ( d i t zou immers een one ind ige l u s veroorzaken )

i f (b . getValue ( ) > a . getValue ( ) )

a . setValue (b . getValue ( ) , this ) ;

}

De somrelatie Een veelgebruikte relatie bestaande uit drie knopen die hier besproken

wordt is de somrelatie. Deze is afgeleid van ABCRelation. Hier is ervoor gekozen om de

waarde van knoop A ongewijzigd te laten bij het in orde brengen van de somvoorwaarde. Dit

wil zeggen dat bij het veranderen van de waarde van knoop A of B de waarde van C aangepast

wordt, maar bij het aanpassen van de waarde van knoop C wordt de waarde van knoop B

aangepast, en niet die van knoop A. Deze keuze is louter een afspraak en kon evengoed

andersom gekozen zijn zonder gevolg voor het graafsysteem. Zoals reeds aangehaald bestaat

deze relatie uit drie knopen, en zorgt deze ervoor dat de waarde van knoop C altijd gelijk

is aan de som van de waarde van knoop A en B. Zo nodig wordt de waarde van knoop B

of C aangepast. Deze relatie is uitermate geschikt voor het definieren van intervallen en in

combinatie met gelijkrelaties kunnen zelfs dynamisch gelinkte lijsten geımplementeerd worden.

Deze structuren worden hierna besproken. De implementatie van de somrelatie wordt gegeven

in codevoorbeeld 3.4.

Page 26: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 16

Codevoorbeeld 3.4: Implementatie van SumRelation

public class IntSumRelation extends ABCRelation<Integer , Integer , Integer>

{public IntSumRelation ( ValueNode<Integer> a , MutableValueNode<Integer> b

, MutableValueNode<Integer> c )

{super ( a , b , c ) ;

}

public void updateB ( )

{b . setValue ( c . getValue ( ) − a . getValue ( ) , this ) ;

}

public void updateC ( )

{c . setValue ( a . getValue ( ) + b . getValue ( ) , this ) ;

}}

De productrelatie Als laatste halen we nog de productrelatie aan. Deze ligt in lijn met de

somrelatie maar berekent in plaats van de som het product tussen knopen A en B, en houdt

het resultaat in knoop C bij.

Door het feit dat som- en productrelatie gedefinieerd zijn, zijn ook automatisch de verschil- en

quotientrelatie bepaald. Immers, wanneer bij een somrelatie knoop B een negatieve waarde

heeft, wordt er afgetrokken. Bij de productrelatie is er nog een speciaal geval: afronding. In

een situatie, die later behandeld wordt, wordt met deze afronding rekening gehouden in de

alternatieve versie van de productrelatie.

Figuur 3.4: Schematische voorstelling van de verschillende relaties

Page 27: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 17

3.3.3 Intervallen

De somrelatie ligt aan de basis van intervallen. Een interval bestaat uit een beginknoop

en een eindknoop. Hoeveel knopen ertussen liggen heeft in principe geen belang, maar in

deze uiteenzetting gaan we uit van twee soorten: een eenvoudig interval, dat bestaat uit drie

knopen, en een gelinkte lijst, die bestaat uit n knopen. Beide intervallen implementeren een

en dezelfde interface Interval <T> (waarbij T een template parameter is die het type van de

gebruikte knopen voorstelt).

Eenvoudige intervallen Een interval bestaat uit drie knopen: een beginknoop, een ver-

schilknoop en een eindknoop, en is een ‘verpakte’ somrelatie. Bij constructie worden de

knopen aangemaakt, en wordt een somrelatie gelegd tussen de drie knopen. Codevoorbeeld

3.5 toont de initialisatie van een interval voor gehele waarden (Integer).

Codevoorbeeld 3.5: Implementatie van een geheel interval

begin = new BasicValueNode<Integer >(0) ;

end = new BasicValueNode<Integer >(0) ;

d i f f e r e n c e = new BasicValueNode<Integer >(0) ;

new IntSumRelation ( begin , d i f f e r e n c e , end ) ;

Verder heeft een interval drie get()/set() methodes en ook drie methodes om de nodes zelf

op te vragen. Figuur 3.5 geeft een schematische voorstelling van een eenvoudig interval.

Figuur 3.5: Schematische voorstelling van een eenvoudig interval

Dynamisch gelinkte lijsten Eenvoudige intervallen zijn de bouwblokken voor een dyna-

misch gelinkte lijst. Deze lijst bestaat uit een aaneenschakeling van intervallen van hetzelfde

type (bijvoorbeeld Integer, Double). Deze aaneenschakeling wordt gerealiseerd met behulp

van gelijkrelaties (telkens tussen de eindknoop van een interval en de beginknoop van het

volgende interval). Het begin van het eerste interval is gekoppeld met de beginknoop van

de lijst en de eindknoop van het laatste interval is gekoppeld aan de eindknoop van die lijst.

Wanneer dan een interval, ergens in de lijst, smaller of breder wordt, worden automatisch alle

intervallen erna opgeschoven over de versmalde/verbreedde afstand. Ook bij tussenvoegen

of verwijderen worden de nodige intervallen opgeschoven. Een schematische voorstelling is

gegeven in figuur 3.6.

Page 28: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 18

Figuur 3.6: Schematische voorstelling van een dynamisch gelinkte lijst

Deze lijst wordt bijvoorbeeld gebruikt om de x-coordinaten van de symbolen op de notenbalk

bij te houden. Wanneer dan een symbool tussengevoegd wordt, worden alle symbolen erna

automatisch opgeschoven. Het is dan enkel nodig een interval tussen te voegen voor het

nieuwe symbool en een repaint() operatie van het paneel op te roepen. Het gebruik van

deze lijsten vereenvoudigt het uitlijnen van alle symbolen drastisch bij het tekenen van de

GUI.

Figuur 3.7: Klassenschema van de intervallen

Page 29: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 19

3.4 De observable graph

Wanneer we tenslotte alle bouwstenen verenigen kunnen we besluiten dat de knopen, in

combinatie met de relaties ertussen, leiden tot een hypergraaf (een verbinding kan verbonden

worden met meer dan een node, bijvoorbeeld de somrelatie), die bovendien observable is. Dit

wordt duidelijk aan de hand van volgend voorbeeld.

In het model wordt een noot opgeslagen als een interval met een bepaalde lengte en een

knoop met als waarde een rank (lijntje van notenbalk waarop of waartussen de noot getekend

wordt). De rank van een noot is relatief uitgedrukt tegenover de centrale do (Appendix A).

Er moet dus eerst geweten zijn op welke rank de centrale do ligt, alvorens de noot getekend

kan worden. Er is echter ook een sleutel opgeslagen in het model, die bepaalt welke rank

deze do heeft. Het komt er dan op neer om de centralCNode (knoop die de rank van de

centrale do bevat) samen met de rankNode (knoop die de rank van de noot bijhoudt) in

een somrelatie onder te brengen, waarvan het resultaat de rank op de notenbalk teruggeeft

(staffRankNode). Op dat moment kennen we de rank van de noot, maar nog niet de y positie

ervan. Er is dus ook een staffBaseNode (knoop die de y positie op het scherm van de onderste

lijn van de notenbalk bevat) nodig, alsook de waarde van de (constante) afstand tussen twee

notenbalklijnen (figuur 3.8).

Figuur 3.8: Voorbeeld van onrechtstreeks gekoppelde knopen

Om de uiteindelijke y positie van de noot te bepalen (voor de noot te kunnen tekenen),

definieren we een productrelatie tussen de staffRankNode en de constante afstand tussen de

notenbalklijnen, gedeeld door twee. Dit geeft als resultaat de staffOffsetNode. Tenslotte

creeren we nog een laatste somrelatie tussen de staffBaseNode en de staffOffsetNode, die de

uiteindelijke yNode als resultaat geeft. Als er dan door de gebruiker een functie setRank

() aangeroepen wordt op de desbetreffende noot, wordt alles automatisch goed hertekend,

aangezien de relaties hiervoor zorgen. Er is dus een onrechtstreekse verbinding tussen de noot

in het model, en de noot die getekend wordt op de partituur. Het gaat zelfs verder: in dit

geval wordt geen gewone productrelatie gebruikt, maar een die het resultaat in een richting

afrondt (in de richting van de staffRankNode). Hierdoor wordt bij het aanklikken van een

positie op de notenbalk voor het invoegen van een noot automatisch de rank het dichtste

Page 30: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 3. Het graafsysteem 20

bij het aangeduide punt bepaald, zonder dat hier nog expliciet berekeningen of zoekoperaties

moeten gebeuren.

Uit het vorige voorbeeld blijkt duidelijk de sterkte van het graafsysteem: werk dat optreedt

bij het wijzigen van een bepaalde variabele of bij een verzoek van de gebruiker zoveel mogelijk

automatisch laten uitvoeren, zonder dat hier expliciet nog extra functieaanroepen voor nodig

zijn. Dit verkleint tevens de kans dat er iets zou vergeten aangeroepen te worden. Een

nadeel van dit systeem is dat het zoeken naar een fout heel wat meer werk vereist, omdat het

meestal niet duidelijk waar het precies fout loopt. Soms treedt een fout op in een bepaalde

knoop, omdat een waarde in voorliggende knoop een foute waarde gekregen heeft. Ook zijn

niet alle relaties eenduidig bepaald en is er toch manuele tussenkomst vereist. Als voorbeeld

beschouwen we een gepunteerde vierde noot, die in muzikale tijd 48 + 24 ticks duurt en een

vierde noot, gekoppeld met een achtste noot, die in muzikale tijd eveneens 48 + 24 ticks duurt

(figuur 3.9). Het is dus niet eenduidig bepaald welke voorstelling gewenst is, en een manuele

operatie is vereist. Niettegenstaande voldoet het graafsysteem in het overgrote deel van de

gevallen aan de opgelegde vereisten.

Figuur 3.9: Voorbeeld van niet triviale relatie

Page 31: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4

Het model

In dit hoofdstuk wordt toegelicht hoe de informatie, die in de leadsheet getoond wordt, ge-

structureerd en opgeslagen wordt. Een van de groter struikelblokken is de verschillende schaal

waarop gegevens voorgesteld worden. In het gegevensmodel is alles gekoppeld aan tijdstem-

pels, maar in de view is er enkel sprake van plaatscoordinaten. Bovendien is de transformatie

niet altijd eenduidig of triviaal. Voor de koppeling van het gegevensmodel aan de view wordt

opnieuw gebruik gemaakt van relaties. Hoe dit precies in zijn werk gaat wordt besproken in

hoofdstuk 5.

In tegenstelling tot vele applicaties met een GUI, zal het MVC model1 niet strikt gevolgd

worden. In die zin dat door het gebruik van relaties de controller overbodig geworden is.

De rol van controller wordt verzorgd door het graafsysteem, dat alle wijzigingen aan het

gegevensmodel of de view automatisch opvangt. De controller is dus eerder impliciet aanwezig.

4.1 Het idee

Zoals reeds eerder vermeld, is het gegevensmodel volledig tijdsgebaseerd. Dit wil zeggen dat

er bepaalde acties moeten gebeuren (bijvoorbeeld een symbool tekenen of tekst invoegen) op

vastgelegde tijdstippen. Hoe worden deze tijdsgerelateerde gebeurtenissen nu opgeslagen en

gekoppeld? Aangezien er meerdere acties gekoppeld kunnen worden aan een tijdstempel, is

er geen een-op-een relatie mogelijk. Het is de bedoeling om de hoeveelheid aan redundante

informatie zoveel mogelijk te beperken. Dit is niet zo evident, aangezien een partituur een

complex gegeven is, gekenmerkt door overtollige informatie (veelal om de leesbaarheid te

bevorderen). Het maatcijfer bepaalt bijvoorbeeld impliciet de maatstrepen, tieing en beaming,

1MVC staat voor model-view-controller, en is een ontwerppatroon dat een applicatie opdeelt in drie delen:

het model (staat in voor het achterliggende datamodel), de view (de presentatie van het datamodel) en de

controller (de applicatielogica). Dit model zorgt ervoor dat de verschillende delen kunnen hergebruikt worden

en dat wijzigingen aan een deel kunnen gebeuren zonder dat de andere delen aangepast moeten worden (gebruik

van interfaces).

21

Page 32: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 22

en toch worden ze alle vier getekend. Een ander voorbeeld is de voortekening. Soms wordt op

een bepaalde plaats in de partituur toch een kruisteken expliciet nog eens herhaald, hoewel dit

niet nodig is. Zoals reeds aangehaald is dit vooral om de leesbaarheid te verhogen, maar dit

maakt het achterliggende model wel ingewikkelder. Het model zal dus flexibel moeten zijn.

Mede door dit toedoen is het model tijdens de ontwikkeling een aantal keer fundamenteel

gewijzigd. Het gebruikte model is volledig gesteund op relaties, maar aangezien de basis

onstaan is bij het eerste model, wordt eerst het model zonder relaties aangehaald. In de

daaropvolgende paragraaf worden de tekortkomingen van dat model, en hetgeen waaraan het

nieuwe model tegemoetkomt, behandeld.

4.2 Het model zonder relaties

In eerste instantie werd er een model uitgewerkt zonder relaties. Omdat dit model veel

gelijkenissen vertoont met het uiteindelijke model, met relaties, wordt het hier kort besproken.

In een volgende paragraaf wordt de transformatie van dit model naar het graafgebaseerde

model behandeld. Dit eerste model is gefundeerd op het model gebruikt bij MIDI2. Hierin

wordt elke toon bepaald door een START en STOP commando, en een toon klinkt zo lang er

geen STOP commando voor gegeven is, na het geven van het START commando. In het model

dat hier gebruikt wordt, worden deze commando’s impliciet gegeven. Als iets voor het gehele

stuk moet klinken (zoals de stemming en het maatcijfer in het gegeven voorbeeld), wordt

dit in elke tijdsperiode herhaald. Vooral bij het kopieren van tijdsstempels is dit belangrijk,

omdat dit dan geen extra werk vereist. Wanneer START en STOP commando’s zouden gebruikt

worden, moet voor elk element in elke tijdstempel nagegaan worden wanneer een START of

STOP commando gegeven werd voor elk element. Het nadeel van deze methode is redundantie,

maar dit is minder ongunstig bij editeeracties. Het gaat hier ook om een andere vorm van

redundantie dan die aangehaald in vorige paragraaf. De extra informatie die in dit geval

bewaard wordt kan geen conflict veroorzaken met andere opgeslagen gegevens, ze wordt enkel

nog eens herhaald.

Zoals reeds eerder vermeld is het achterliggende model volledig tijdsgebaseeerd. Er is enkel

sprake van tijdstempels (verder tijdscoordinaten genoemd). Dit in tegenstelling met het

model dat voor het tekenen van de elementen instaat, en enkel symbolen en ruimtelijke

coordinaten bevat. Dit systeem is ook het meest logische: de muziek, gerepresenteerd door zijn

muziekpartituur, is eigenlijk niets anders dan een opeenvolging van een of meerdere tonen, elk

met een eigen lengte. Of een toon voorgesteld wordt door een noot, dan wel door meerdere

noten die met elkaar verbonden zijn door middel van een verbindingsboog, doet voor het

achterliggende model niets ter zake. Dat is meer een representatiekwestie, en bijgevolg de

2Musical Instrument Digital Interface. Het is een digitaal systeem (en protocol) waarmee elektronische

(muziek)instrumenten in realtime muzikale informatie kunnen uitwisselen.

Page 33: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 23

verantwoordelijkheid van een bepaalde view. Dit impliceert dat er een vertaling moet kunnen

gebeuren tussen de verschillende modellen.

Het probleem dat hierbij opduikt is dat er geen een-op-een relatie bestaat tussen de tijds- en

positiecoordinaten. Dit is eenvoudig te illustreren aan de hand van volgend voorbeeld (figuur

4.1), waarbij we uitgaan van de eerste twee maten3.

Het is duidelijk dat de sleutel, voortekening en de eerste noot bij een en dezelfde tijdscoordinaat

horen. Niettegenstaande komt deze tijdstempel overeen met meerdere muzikale symbolen, die

telkens een andere x positie hebben. Hetzelfde geldt voor maatstrepen: in het model wordt

er zoveel mogelijk voor gekozen om enkel essentiele en zo weinig mogelijk redundante infor-

matie op te slaan. Hieruit volgt dat het in principe enkel nodig is om een maatcijfer mee te

geven aan een partituur in het model. Het bepalen van maatstrepen, alsook hun positie, kan

volledig overgelaten worden aan de view. Ook hier is een maatstreep eigenlijk een hulpmiddel

om een muziekstuk op te delen in kleinere delen en zo de leesbaarheid te verhogen.

Bij alle elementen hierboven opgesomd, duikt uiteindelijk een groot probleem op: dit is een

erg theoretische aanpak, en in de realiteit zal de gebruiker bepaalde acties willen uitvoeren

op een partituur, zodat niet meer mooi de regeltjes kunnen gevolgd worden. De wijzigingen

die aangebracht worden aan een view zouden bijgevolg bijgehouden kunnen worden in aparte

view-directions. Onder view-directions worden speciale regels verstaan, die toegepast worden

op het ideale model, en die de theoretische regels overschrijven met gebruiker specifieke.

Nemen we bijvoorbeeld een actie waarbij een gebruiker vier 16de noten in een maat van 4

4 wil invoeren. Deze worden automatisch gegroepeerd aan de hand van een beam. Of deze

beam boven of onder de noteheads valt, wordt automatisch bepaald door de toonhoogte van

de noten. Een gebruiker kan echter zelf beslissen om deze standaard regel te negeren en

manueel de beam naar de tegengestelde richting te slepen. Dit heeft geen belang voor het

onderliggende model, enkel voor de view. Dit kan dan als een aparte view-direction opgeslagen

worden.

3De twee eerste maten uit ’Vader Jacob’ (in Vlaanderen gekend als ’Broeder Jacob’), een kinderliedje dat

oorspronkelijk uit Frankrijk afkomstig is (http://nl.wikipedia.org/wiki/Vader_Jacob)

Figuur 4.1: Broeder Jacob

Page 34: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 24

4.2.1 Tijdstempels

Een tijdstempel bevat een bepaalde lengte. Doordat een tijdstempel ergens begint en er-

gens eindigt, kan het beschouwd worden als een tijdsinterval, met een begin-, verschil- en

eindcoordinaat. Het definieert dus een bepaalde tijdsperiode (bijvoorbeeld 1 seconde). In die

tijdsperiode kunnen bepaalde dingen gebeuren. Deze worden voorgesteld door elementen in

een hashtabel. Als sleutel wordt telkens de id van de deellijn4 gebruikt waarop deze actie

ingrijpt. Voor een notenbalk worden maximum drie deellijnen gebruikt.

� Stemming (sleutel en voortekening)

� Maatcijfer

� Melodie (tonen)

Een voorbeeld van twee maten van een partituur met overeenstemmend model wordt weer-

gegeven in figuur 4.2 en 4.3.

Bovenaan elke tijdstempel wordt de tijdsperiode in milliseconden aangegeven, waarvoor de

elementen die eronder staan, gelden. Daaronder worden vijf lijnen gedefinieerd.

� Een stemmingslijn: bepaalt een bepaalde stemming (hier is dit do klein5) en een be-

paalde sleutel (hier is dit de solsleutel6)

� Een akkoordlijn: bevat de akkoorden van de partituur, in elke tijdstempel wordt weerge-

geven welk akkoord op dat moment geldt; dit kan ofwel niets zijn (geen akkoord tonen),

ofwel een bepaald akkoord; als er een akkoord over meerdere tijdsperiodes loopt, wordt

dit in elke tijdsperiode aangegeven met hetzelfde akkoord, de view zal dit herkennen en

het akkoord maar een keer tonen over de volledige tijdsperiode;

� Een melodielijn: duidt aan welke toon in deze tijdsperiode gespeeld wordt, en kan als

waarde een geheel getal hebben, dat de index voorstelt van de toon (0 stelt de onderste

lijn van de notenbalk voor), of de waarde R (deze stelt een rust voor, er wordt dan geen

toon gespeeld)

� Een lyricslijn: net als de akkoordlijn geeft deze weer welke tekst in een bepaalde tijds-

periode moet weergegeven worden, en wordt deze herhaald als ze dezelfde blijft

� Een maatcijfer: in dit voorbeeld is dit 4 4, dit wil zeggen dat elke maat vier kwartnoten

lang is

4Een deellijn kan bijvoorbeeld een lyricslijn, akkoordlijn of melodielijn zijn5Het eerste element van een tijdstempel definieert hier drie mollen als voortekening, en deze bepalen op

hun beurt een bepaalde toonaard, zie C6Zie appendix A

Page 35: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 25

Figuur 4.2: Twee maten uit ’Neon’, geschreven door John Mayer.

Figuur 4.3: Voorstelling van de partituur (figuur 4.2) in het datamodel

Deze tijdstempels vormen de bouwblokken van een leadsheet in het datamodel. Deze tijd-

stempels worden ondergebracht in een structuur7, zodat ze gemakkelijk kunnen toegevoegd,

verwijderd en tussengevoegd worden. Een leadsheet bestaat uit verschillende van die bouw-

blokken, die bij het tekenen van de leadsheet chronologisch overlopen worden.

Voor de tijdstempels werd bewust een tijdsperiode gebruikt, en geen offset tegenover het be-

gin van de tijdlijn of tegenover de vorige tijdstempel. De reden hiervoor is dat de volgorde al

bepaald wordt door de achterliggende structuur, en bij een absolute offset8 zou de volgorde

dus twee keer vastliggen (een keer door de volgorde van de datastructuur, en een tweede keer

in de waarde van de absolute offset). Deze situatie wordt gevaarlijk wanneer er tijdstem-

pels verplaatst worden. Deze tijdstempels worden ondergebracht in een tijdlijn, waarvan de

structuur hierna kort besproken wordt.

4.2.2 Tijdlijn

De tijdlijn is de structuur waarin tijdstempels ondergebracht worden. Het is mogelijk om

tijdstempels toe te voegen, te verwijderen of te verplaatsen. In principe kan een tijdlijn elke

mogelijke structuur zijn waaraan elementen kunnen toegevoegd en opgevraagd worden, in

een bepaalde volgorde. In dit geval wordt dit geımplementeerd door een dubbel gelinkte lijst,

omdat deze de mogelijkheid biedt om snel terug te keren of vooruit te bewegen in de lijst. Bij

7Deze structuur kan eenvoudig veranderd worden, omdat gebruik gemaakt wordt van interfaces. In dit

geval wordt een dubbel gelinkte lijst gebruikt.8Met een absolute offset wordt de offset tegenover het begin van de tijdlijn bedoeld.

Page 36: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 26

een enkel gelinkte lijst kan het gebeuren dat eerst de gehele lijst (circulair) overlopen moet

worden om bij een bepaald element te komen (dit is het geval wanneer het gezochte element

zich vlak voor het huidige element bevindt). De volgorde van de tijdstempels wordt bepaald

door de gelinkte lijst, en niet door de waarde van de tijdstempels.

Dit gegevensmodel, waarbij tijdstempels ondergebracht worden in een enkele tijdslijn, bleek

al snel enkele gebreken te vertonen. Zo moet er bij het optreden van een actie in een tijdslijn

een tijdstempel gemaakt worden in elke tijdslijn, en op die manier kan de tijdslijn enorm

lang worden. Wanneer er bijvoorbeeld maar twee akkoordwijzigingen gebeuren, maar daarbij

ook een melodielijn gevoegd wordt, die tientallen verschillende noten bevat (en dus tien-

tallen tijdstempels vereist), wordt de te overlopen tijdslijn voor het tekenen van akkoorden

gefragmenteerd, terwijl dat eigenlijk niet echt nodig is. Verder is het ook niet handig dat

bij de tijdstempels een tijd in milliseconden bijgehouden wordt. Dit kan immers leiden tot

moeilijk kwantiseerbare tijdsperiodes (en kwantisatie is nodig bij het omzetten van reeele tijd

naar een nootsymbool). Tenslotte zijn aparte view-directions voor verbindinsbogen (tieing)

en beaming niet volledig correct omdat ze niet puur view-afhankelijk zijn (ze bepalen geen

positie van een bepaald symbool, puur muzikaal zijn ze zelfs rechtstreeks gekoppeld aan het

maatcijfer, omdat ze noten groeperen per tel). Bij de invoering van het graafsysteem werd

dit model, en dan vooral de tijdslijn, gewijzigd om aan deze noden tegemoet te komen. Hoe

dit verwezelijkt werd, wordt in de volgende paragrafen behandeld.

4.3 Het model met relaties

In deze paragraaf wordt toegelicht hoe van het originele model overgegaan werd naar een

model gebaseerd op relaties. Deze overgang valt uiteen in drie groter peilers: splitsing van

de tijdlijnen, gebruik van muzikale tijd en het opslaan van redundante gegevens. Eerst wordt

de grootste drijfveer behandeld voor de verschuiving naar een meer universeel model: samen-

werking.

4.3.1 Deel van een groter geheel

Een van de meest doorslaggevende redenen voor het herzien van het model is wellicht die

om een soort universeel basismodel te creeren. Dit basismodel kan gebruikt worden voor

dit eindwerk, dat zich toespitst op het editeren van een leadsheet, maar kan ook gebruikt

worden in het eindwerk dat nauw aansluit bij dit eindwerk9. Op die manier is het mogelijk

om van een leadsheet, gemaakt met de editor, de timing op microschaal aan te passen. Of

omgekeerd, de logica voor rhythm-by-tapping en het inlezen van midibestanden (figuur 4.4)

van het andere eindwerk gebruiken. Dit vereist geen extra werk omdat zowel de editor als

9Het eindwerk ’Microtiming’, geschreven en uitgevoerd door Jannes Plyson, is in samenwerking met dit

eindwerk verwezelijkt

Page 37: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 27

de logica die tapping en MIDI mogelijk maakt, gekoppeld zijn aan hetzelfde model. Op die

manier is het enkel een kwestie van de juiste functies op het juiste moment aan te roepen.

Als laatste is ook het afspelen van de partituur zelf overgelaten aan een ander eindwerk, en

moet er in de editor enkel de juiste knop toegevoegd worden die de nodige functies aanroept.

Het enige struikelblok dat dan nog overblijft is het aanduiden van de positie van het afspelen

in de leadsheet, door middel van een glijdende caret.

Figuur 4.4: Rhythm-by-tapping en inlezen van MIDI gegevens

4.3.2 Splitsing van de tijdlijnen

In het originele model werd er een tijdlijn gebruikt, bestaande uit tijdstempels die eigenlijk

een hashtabel waren. Bij de introductie van het graafsysteem werden ook dynamisch gelinkte

lijsten gedefinieerd. Deze lijsten bestaan op hun beurt uit intervallen met een begin-, verschil-

en eindcoordinaat. Net zoals tijdstempels dus. Elk type gegeven kan dus beschouwd worden

als een interval met extra informatie, afhankelijk van het type. Als we in het klassenschema

(figuur 4.5) de overervingen bekijken, wordt dit duidelijk.

Aangezien er per type een interval gedefinieerd is, werd er uiteindelijk voor gekozen om per

type een aparte tijdslijn te definieren, een sequentie genoemd (figuur 4.6). Deze sequentie

wordt geımplementeerd door een dynamisch gelinkte lijst. Zo zijn er voor een leadsheet zeven

verschillende sequenties mogelijk (en elke sequentie kan meerdere keren voorkomen).

� De akkoord sequentie: deze sequentie bestaat uit Chord objecten, met als inhoud het

desbetreffende akkoord

� De lyric sequentie: deze sequentie omvat Lyric objecten, die de lyric op een bepaald

moment definieren

� De sleutel sequentie: dit bepaalt welke sleutel er geldt voor de notenbalk op een bepaalde

tijd, en bestaat uit Clef objecten

� De sleutelsignatuur sequentie: bepaalt de voortekening, die bewaard wordt in KeySig-

nature objecten

Page 38: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 28

� De tijdsignatuur sequentie: bepaalt welk maatcijfer er geldt, en wordt opgeslagen in

TimeSignature objecten

� De toon sequentie: deze sequentie is de hoofdsequentie en bepaalt welke tonen er ge-

speeld worden op een bepaald moment; het is ook deze sequentie die dus gebruikt zal

worden om de leadsheet af te spelen, en bevat Tone objecten

� De beat sequentie: deze sequentie bevat de beats van een partituur, en is nauw verwant

met de tijdsignatuur; bovendien doet ze dienst als de container voor redundante infor-

matie zoals het opslaan van ties en beams; deze informatie wordt bijgehouden in Beat

objecten

Figuur 4.5: Klassenschema van de muzikale elementen

Over welk type sequentie het gaat, hangt af van het type gegevens dat er aan toegevoegd

worden. Bij de constructie van een sequentie, is het vereist een bepaald type op te geven en

vanaf dan is het enkel mogelijk om gegevens van dat specifieke type toe te voegen.

Page 39: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 29

Figuur 4.6: Schematische voorstelling van de sequenties

Page 40: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 30

In een leadsheet is er sprake van Parts en Partcollections. Een Part definieert een bepaald

instrument. Dit kan een melodielijn (voorgesteld door een notenbalk), een lyricslijn of een

akkoordlijn zijn. (bij voorbeeld 4.2 zijn er bijvoorbeeld drie Parts). In het geval van akkoor-

den en lyrics komt een Part overeen met exact een sequentie. Bij een notenbalk echter, is

dit niet het geval. Een notenbalk kan uit (maximaal) vijf sequenties bestaan. Er duikt dus

een nadeel op aan deze nieuwe aanpak: voor een notenbalk moeten verschillende sequenties

samengevoegd worden om ze te kunnen tekenen, en wanneer een getekende view moet opge-

slagen worden, moet deze gesplitst worden in meerdere sequenties. De samenvoegoperatie is

eenduidig bepaald en is eenvoudiger dan de splitsoperatie, omdat er van het gegevensmodel

meestal meerdere views mogelijk zijn, maar er van een view maar een correct gegevensmodel

is. Hoe deze operatie in zijn werk gaat wordt in het volgende hoofdstuk besproken. Een Part

bestaat dus uit verschillende sequenties, en zorgt ervoor dat elk van zijn sequenties altijd even

lang is. Wanneer een van zijn sequenties vergroot of verkleint, past deze klasse zijn andere

sequenties aan zodat de lengte van alle sequenties steeds gelijk blijft. Dit gebeurt aan de hand

van relaties. Verder kunnen verschillende parts met elkaar uitgelijnd worden (dit wil zeggen

dat elementen die op hetzelfde moment beginnen onder elkaar getekend worden). Als dat het

geval is, worden ze samen in een PartCollection ondergebracht.

4.3.3 Gebruik van muzikale tijd

Een volgende wijziging bestaat uit de keuze van tijdschaal gebruikt bij het opslaan van het

model. Er is voor geopteerd om muzikale tijd te gebruiken in plaats van reele tijd (bijvoorbeeld

in milliseconden). Bij muzikale tijd we kiezen we een basisgetal, in dit geval 192 (omdat dit

zowel deelbaar is door veelvouden van twee als van drie, en dit belangrijke getallen zijn binnen

de muziek). Vervolgens stellen we dit getal gelijk aan een noot (hier hebben we gekozen voor

een hele noot), en leiden we voor elke andere noot het bijbehorende getal af. In het model

gebruiken we deze getallen om voor te stellen hoe lang een bepaalde noot duurt.

Noottype Muzikale tijd

Helenoot 192

Halvenoot 96

Kwartnoot 48

Achtstenoot 24

Zestiendenoot 12

Eennootvaneentriool 16

Tabel 4.1: Muzikale termen

Deze getallen zijn reeds gekwantiseerd en zijn dus transformeerbaar naar een noot of een

Page 41: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 31

combinatie van noten. Bovendien zijn ze geheel, waardoor er geen problemen kunnen optreden

bij afronding. Maar hoe gebeurt het afspelen dan? Want dat is in reele tijd. De oplossing

is relatief simpel. Door gebruik te maken van relaties worden deze muzikale tijden gemapt

op reele tijden. Dit vereist geen extra werk omdat relaties ervoor zorgen dat zowel muzikale

als reele tijd gesynchroniseerd blijven. Het omzetten van muzikale naar reele tijd is opnieuw

triviaal omdat er maar een correcte reele representatie is. Problemen treden echter op wanneer

reele tijden moeten omgezet worden naar muzikale tijd, want dan is er kwantisatie nodig.

Deze kwantisatie valt buiten het bestek van dit eindwerk en wordt behandeld in het eindwerk

‘Microtiming’.

4.3.4 Het opslaan van redundante gegevens

Het uitgangspunt van het vorige model was dat alleen de nodige informatie opgeslagen zou

worden. Zo is het in principe niet nodig om maatstrepen op te slaan, omdat de positie van

deze maatstrepen impliciet bepaald worden door het maatcijfer.

Nemen we terug het voorbeeld uit figuur 4.2. Deze partituur heeft als maatcijfer 4 4. Dit wil

zeggen dat er vier tellen per maat zijn, die telkens zo lang duren als een vierde (kwart) noot.

Een kwartnoot duurt in muzikale tijd 48 ticks, zo dat bijgevolg een volledige maat 192 (4 *

48) ticks duurt. Er moet dus om de 192 ticks een maatstreep komen. Maar een maatcijfer

bepaalt ook dat de noten in de maat zo veel mogelijk gegroepeerd worden per 48 ticks (hier is

dit zo omdat een kwartnoot 48 ticks lang is). Deze gegevens geven automatisch aanleiding tot

tieing en beaming, omdat beide eigenlijk groeperingen zijn. Een beam groepeert een aantal

noten tot een tel (hier telkens groepjes van 48 ticks), en een tie groepeert noten die langer

zijn dan een tel, en dus gesplist moeten worden (noten drie en vier, zes en zeven, negen en

tien in voorbeeld 4.2).

Het maatcijfer bepaalt dus maatstrepen, tieing en beaming. Het probleem dat nu opduikt, is

dat niet alle partituren mooi de regeltjes volgen. Neem bijvoorbeeld een opmaat10 in voor-

beeld 4.7. Het systeem van hierboven is eenvoudigweg niet gemaakt om dit soort problemen

te ondersteunen. Daarom werd ervoor gekozen om toch een minimale hoeveelheid aan re-

dundante informatie op te slaan, onder de vorm van beats, en de bijhorende beatsequentie.

Ook deze aanpak beantwoordt niet aan alle noden11, maar helpt ons toch een groot eind

verder. Een beat is een interval met een boolean waarde isMeasureBeat(). Wanneer deze

functie true teruggeeft, wordt er een maatstreep getekend op die muzikale tijd (dit biedt een

oplossing voor opmaten). Verder worden alle noten per beat gegroepeerd door middel van

beaming (een beat komt dus in de meeste gevallen overeen met een tel), en wanneer noten

langer duren dan een tel, en dus tot twee tellen behoren, worden deze gesplitst en verbonden

10Sommige muziekstukken beginnen met een onvolledige maat (die in principe samen met de laatste maat

een volledige maat duurt, maar opniew is dit niet verplicht).11Bijvoorbeeld slurs. Dit is een tie tussen twee noten van verschillende toonhoogte

Page 42: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 4. Het model 32

met een tie. Op deze manier is het ook mogelijk om beaming en tieing te gebruiken, zelfs

wanneer er geen maatcijfer gedefinieerd is.

Figuur 4.7: Voorbeeld van een opmaat

Nu het model vastligt, moet er nog een manier bedacht worden om het effectief correct weer te

geven. Alvorens we overgaan naar de view zelf, behandelen we het tussenliggend systeem. Dat

is een soort doorgeefluik dat in staat is om tijdscoordinaten om te zetten in plaatscoordinaten

en omgekeerd. De meeste operaties gebeuren ook hier met behulp van relaties, maar omdat

niet alles altijd triviaal is, is er soms minimale tussenkomst nodig. In het MVC model zou

men dit de controller kunnen noemen.

Page 43: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5

De tussenliggende relaties

In het hoofdstuk 4 werd reeds aangehaald dat het door het gebruik van sequenties nodig was

om deze samen te voegen om een notenbalk te kunnen tonen, en dat gegevens uit de view

opgedeeld moeten worden in verschillende sequenties om ze te bewaren in het model. In dit

hoofdstuk zal het relatiesysteem tussen het model en de view, dat deze split- en merge-operatie

verzorgt, besproken worden. Een grafische voorstelling is gegeven in figuur 5.1.

Vooraleer we de uiteenzetting over het samenvoegen van sequenties beginnen, dient opgemerkt

te worden dat er een duidelijk onderscheid gemaakt wordt tussen een toon en een noot. Een

toon wordt hier gedefinieerd als een klank met een bepaalde toonhoogte. In het model wordt

alles voorgesteld als tonen. Wanneer we echter overgaan naar het notationele model (hetgeen

uiteindelijk getekend wordt), spreken we van noten. Een toon kan dan gesplitst worden in

meerdere noten. Noten zijn een visuele voorstelling van tonen. Een toon kan voorgesteld

worden door meerdere noten (die bijvoorbeeld gekoppeld of gepunteerd zijn), maar een noot

(eventueel gekoppeld of gepunteerd) wordt altijd voorgesteld door een toon. In figuur 5.2 zijn

vier notationele voorstellingen (met noten) gegeven voor een en dezelfde toonrepresentatie,

namelijk een sol met lengte 48.

Figuur 5.1: Koppeling tussen gegevensmodel en view (de controller)

33

Page 44: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5. De tussenliggende relaties 34

Figuur 5.2: Vier verschillende notationele voorstellingen van eenzelfde toon

5.1 De merge operatie

Voor het tekenen van noten met al hun elementen (hiermee wordt bedoeld de notehead, de

stem, de vlaggen, eventuele punten, beams en ties) zijn drie sequenties vereist.

Vooreerst is er de toonsequentie. Het enige dat deze sequentie bevat zijn opeenvolgende

intervallen met een bepaalde lengte. Deze intervallen hebben een extra dataveld met een base

40 rank1. Deze rank is altijd uitgedrukt tegenover de centrale do, en geeft dus niet aan op

welke lijn van de notenbalk de desbetreffende noot getekend moet worden.

Vervolgens is er de sleutelsequentie. Die bevat ook een aantal intervallen. In het meest

eenvoudige geval is dit een interval met een lengte gelijk aan de lengte van de sequentie. Dit

interval bevat een veld met het type sleutel2, de rank van de sleutel op de notenbalk, en de

rank waarop de centrale do komt te liggen. De toon- en sleutelsequentie bepalen dus al waar

noten op de notenbalk liggen en zijn dus muzikaal volledig in orde.

Dan is er nog de notationele kwestie. Deze behelst het groeperen van noten. Een noot met

muzikale lengte 36 kan bijvoorbeeld getekend worden als een gepunteerde noot van lengte 24,

maar evengoed als een noot van lengte 24, gekoppeld met een noot van lengte 12. Of drie

gekoppelde noten van lengte 36. Dit notationele aspect is daarom apart opgeslagen in een

beatsequentie. Deze bevat intervallen met een boolean waarde, die bepaalt of er een maat-

streep getekend moet worden. Als een toon overlapt met het begin of einde van een interval,

moet deze op die plaats gesplitst worden. Verder moeten binnen een beatinterval alle noten

zoveel mogelijk gegroepeerd worden. Omdat deze sequenties afzonderlijk niet zo veel beteke-

nis hebben (uiteraard is het perfect mogelijk dat er alleen een toonsequentie gedefinieerd is,

alle tonen worden dan zo eenvoudig mogelijk afgebeeld als noten), worden deze drie sequenties

gegroepeerd in een StaffElementSequence. Deze container zet tonen om naar noten, rekening

houdende met een sleutelsequentie en eventueel met een beatsequentie. Verder maakt hij

ties, beams en maatstrepen aan waar nodig. Op die manier kunnen verschillende noten een

en dezelfde toon voorstellen. In figuur 5.2 wordt een toon achtereenvolgens voorgesteld door

een, twee, twee en drie noten. De implementatie van de delete() methode van noot ziet er

uit als in codevoorbeeld 5.1. Aangezien het mogelijk is dat de toon voorgesteld wordt door

1De base 40 rank notatie is een manier om de hoogte van een toon, inclusief wijzigingstekens, vast te leggen

in een getal (http://www.ccarh.org/publications/reprints/base40/).2G, F of C sleutel

Page 45: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5. De tussenliggende relaties 35

meerdere noten, zal de noot de toon eerst korter maken met zijn eigen lengte (opgeslagen in

zijn notehead). Wanneer de toon dan een lengte nul heeft, mag deze verwijderd worden uit

de toonsequentie.

Codevoorbeeld 5.1: Implementatie van de delete() methode van een Note

public void d e l e t e ( )

{int l ength = noteHeadNode . getValue ( ) ;

tone . s e t D i f f e r e n c e ( tone . g e t D i f f e r e n c e ( ) − l ength )

i f ( tone . g e t D i f f e r e n c e ( ) == 0)

toneSequence . remove ( toneSequence . indexOf ( tone ) ) ;

}

Ongeveer hetzelfde scenario speelt zich af bij het wijzigen van de lengte van een noot (door

bijvoorbeeld de notehead aan te passen of het aantal vlagjes aan de stem te veranderen).

Hiervoor is echter geen methode nodig. Alle elementen van een noot worden bijgehouden in

knopen (codevoorbeeld 5.2).

Codevoorbeeld 5.2: Knopen van een Note die alle delen ervan opslaat

private MutableValueNode<Integer> noteHeadNode ;

private MutableValueNode<Integer> stemNode ;

private MutableValueNode<Integer> f lagNode ;

private MutableValueNode<Integer> dotNode ;

Deze knopen worden vervolgens meegegeven aan de view. Doordat de informatie opgeslagen

in elk van deze knopen voldoende is om het desbetreffende element te tekenen, en deze recht-

streeks mogen gewijzigd worden door de view bij een editeeractie, wordt de lengte van een

toon ook mee aangepast wanneer we bijvoorbeeld de notehead wijzigen.

Hetzelfde geldt voor de rank van een noot. Wanneer aan dezelfde toon meerdere noten

gekoppeld zijn, en de gebruiker wijzigt de rank van een van die noten, heeft dat tot gevolg

dat alle gekoppelde noten mee verschuiven. Dit omdat elk van de gekoppelde noten dezelfde

rankNode delen. Dit alles gebeurt zonder enige tussenkomst van de gebruiker of programmeur

en is volledig transparant.

Zoals eerder vermeld stelt de rank in een toon geen rank voor op de notenbalk. Hiervoor is

het nodig te weten op welke rank de centrale do zich bevindt, en bijgevolg dus welke sleutel

er geldt. Een noot heeft daarom een methode setClef(Clef clef), waar een sleutel kan

meegegeven worden. Aan deze sleutel wordt dan de centralCRankNode gevraagd, en deze

wordt samen met de rankNode van de toon gecombineerd tot een staffRankNode, op een

manier geıllustreerd in codevoorbeeld 5.3. De rank12Node stelt de MIDI rank voor en wordt

gebruikt om door te geven aan een MIDI Synthesizer en zo de tonen af te spelen.

Page 46: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5. De tussenliggende relaties 36

Codevoorbeeld 5.3: Berekening van de juiste positie op de notenbalk

Mus i ca l In t e rva l m u s i c a l I n t e r v a l = Base40 . t o Mu s i c a l I n t e r va l ( base40RankNode .

getValue ( ) ) ;

rankNode = new BasicValueNode<Integer >( m u s i c a l I n t e r v a l . getRank ( ) +

centralCRankNode . getValue ( ) ) ;

acc identa lNode = new BasicValueNode<Integer >( m u s i c a l I n t e r v a l . g e tAcc identa l ( ) ) ;

rank12Node = new BasicValueNode<Integer >( m u s i c a l I n t e r v a l . getRank12 ( ) ) ;

Tenslotte worden aan deze knopen observers gekoppeld, zodanig dat bij het wijzigen van

een van de knopen, de andere automatisch mee aangepast worden. Een voorbeeld van een

observer bij het wijzigen van de centralCRankNode is gegeven in codevoorbeeld 5.4.

Codevoorbeeld 5.4: Codevoorbeeld van observer

centralCRankNode . addObserver (new Observer ( )

{public void onNoti fy ( Object source )

{i f ( i sLocked ( ) )

return ;

requestLock ( ) ;

Mus i ca l In t e rva l m u s i c a l I n t e r v a l = Base40 . t o Mu s i c a l I n t e r va l (

base40RankNode . getValue ( ) ) ;

rankNode . setValue ( m u s i c a l I n t e r v a l . getRank ( ) + centralCRankNode .

getValue ( ) ) ;

rank12Node . setValue ( m u s i c a l I n t e r v a l . getRank12 ( ) ) ;

removeLock ( ) ;

}}) ;

De isLocked(), requestLock() en removeLock() functie blokkeert de andere observers van

centralCRankNode, om te vermijden dat bij het doorvoeren van de wijzigingen door cen-

tralCRankNode andere knopen centralCRankNode opnieuw zouden verwittigen dat er iets

gewijzigd is, en zo een oneindige lus zouden creeren. Door gebruik te maken van de tussen-

liggende sequentie StaffElementSequence voor een notenbalk, is er toch een een-op-een relatie

mogelijk tussen het tussenliggende model en de view (figuur 5.3). Het zal voor een notenbalk

ook enkel deze sequentie zijn waar de view zelf weet van heeft en zal manipuleren. Het aan-

passen van het werkelijke model gebeurt voor de view zelf volledig transparant, zodat zowel

de split- als merge-operatie onzichtbaar zijn voor de view. In dat opzicht is het tussenmodel

ook een soort view van de opgeslagen model, maar een view die nog geen rekening houdt met

het tekenen van de desbetreffende elementen. Dit is de taak van de view, die in hoofdstuk 6

besproken wordt.

Page 47: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5. De tussenliggende relaties 37

Figuur 5.3: Schematische voorstelling van het tussenliggende model

5.2 De split operatie

Dankzij het gebruik van relaties is er geen extra werk vereist voor de implementatie van de

split operatie. Alles wordt immers automatisch in orde gebracht door de aangelegde relaties.

We kunnen dus meteen overgaan naar de paragraaf die het mappen van muzikale tijd op x

coordinaten behandelt. Opnieuw is dit een soort view van het gegevensmodel, maar ook nu

wordt geen aandacht besteed aan het tekenen zelf.

5.3 Mappen van muzikale tijden op x posities

Nu alle elementen bepaald zijn die getekend moeten worden, dienen deze die tot dezelfde

PartCollection behoren en op dezelfde tick beginnen ook onder elkaar getekend te worden.

Deze functionaliteit (het mappen van ticks op x coordinaten) gebeurt door twee speciaal

daarvoor geschreven klassen: TicksToXMapper en RelationBuilder.

5.3.1 De TicksToXMapper

Deze klasse doet eigenlijk niets anders dan een map bijhouden die ticks afbeeldt op de gra-

fische voorstelling van een bepaald element (voor een Chord object is dit bijvoorbeeld een

tekstveld). De schematische voorstelling is weergegeven in figuur 5.4. Verder houdt deze ook

bij wat de gewenste breedte is van die grafische voorstelling. Op die manier kan later de

werkelijke breedte van het element bepaald worden. Wanneer er immers meerdere elementen

zijn die op dezelfde begintick starten en eindigen op dezelfde eindtick, wordt de breedte van

het breedste element genomen en worden alle andere elementen even breed gemaakt als dat

element (aan de hand van een maximum relatie). Als gegevensstructuur werd hier niet geko-

zen voor een gewone hashmap, maar voor een treemap. Deze heeft als voordeel dat naast de

woordenboekoperaties (zoeken, toevoegen en verwijderen) ook de volgorde van de elementen

Page 48: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5. De tussenliggende relaties 38

onderhouden wordt. Het is dan mogelijk om van een bepaalde tick de tick te vragen die er

net onder of boven ligt, of om het minimum of maximum te bekomen.

Figuur 5.4: Schematische voorstelling van de TicksToXMapper

Verder luistert deze klasse naar alle elementen die eraan toegevoegd werden, om de map aan te

passen wanneer van een element het begin (begintick), verschil (muzikale lengte, uitgedrukt

in ticks) of einde (eindtick) zou veranderen. Ook brengt ze zelf luisteraars op de hoogte

wanneer er iets verandert aan de map (bijvoorbeeld de RelationBuilder, die in de volgende

paragraaf behandeld wordt). Tenslotte stelt deze klasse de werkelijke breedte van een element

in. Zoals reeds eerder vermeld is de breedte van een element gelijk aan de maximum breedte

van alle componenten die beginnen op dezelfde begintick en eindigen op dezelfde eindtick.

Deze x posities met hun bijbehorende breedtes zijn opnieuw geımplementeerd met behulp

van knopen. Er zou hier evengoed een interval gekozen kunnen zijn, maar omdat er geen echt

voordeel mee gepaard gaat (dit interval maakt bijvoorbeeld niet rechtstreeks deel uit van een

lijst), werd hiervoor niet geopteerd.

5.3.2 De RelationBuilder

Van zodra er van de verschillende Parts een map gekend is die ticks afbeeldt op de elementen

met hun gewenste breedte, moeten deze gewenste breedtes nog aan elkaar gekoppeld worden

zodat en alle elementen juist onder elkaar uitgelijnd zijn, en dat alle elementen een breedte

hebben groter dan of gelijk aan hun gewenste breedte. Deze relaties worden gelegd, aangepast

en verwijderd door de RelationBuilder. Deze klasse moet dus enkel de TicksToXMappers

kennen van de Parts, en niet het Part zelf. De RelationBuilder luistert naar de verschillende

Page 49: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5. De tussenliggende relaties 39

TicksToXMappers en voegt relaties toe wanneer er een element toegevoegd werd aan de map,

of verwijdert relaties wanneer er een element uit verwijderd werd.

Deze klasse houdt opnieuw een treemap bij, die ticks afbeeldt op intervallen en elementen.

Deze ticks zijn een verzameling van alle ticks die voorkomen in alle Parts die toegevoegd

werden. De eindknoop van de intervallen stellen de x posities voor waar de respectievelijke

ticks voorkomen. De breedte van het interval stelt de breedte voor van elementen die beginnen

en eindigen op dezelfde tick, en dus geen echte muzikale duur hebben (bijvoorbeeld een sleutel,

een maatstreep of een voortekening). Er is een eenvoudig voorbeeld gegeven in figuur 5.5. In

dit voorbeeld is er sprake van drie parts. Het eerste Part heeft een element dat begint op

tick 0 en eindigt op tick 48. Als tweede hebben we een Part dat enkel een element heeft dat

begint op tick 0 en geen duur heeft. De laatste twee elementen zijn afkomstig van eenzelfde

Part en beginnen op tick 0 respectievelijk 24, en eindigen op tick 24 respectievelijk 48.

Figuur 5.5: Schematische voorstelling met een eenvoudig voorbeeld van een RelationBuilder

Wanneer nu een element toegevoegd wordt aan een sequentie, wordt het via relaties automa-

tisch toegevoegd aan de juiste TicksToXMapper. Deze voegt in zijn map een entry toe, met

als sleutel de tick waarop het element begint. De TicksToXMapper verwittigt op zijn beurt

de RelationBuilder van de PartCollection. Deze maakt in zijn map een entry bij voor de

tick waarop het element begint en waarop het element eindigt. Wanneer zo een entry reeds

bestaat, wordt het element toegevoegd aan de lijst met elementen die bijgehouden wordt per

entry in de map. Deze lijst wordt bijgehouden om te kunnen nagaan wanneer een entry defi-

nitief verwijderd mag worden (dit is het geval als deze lijst leeg is, omdat de entry dan door

geen enkel element nog gebruikt wordt).

Page 50: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 5. De tussenliggende relaties 40

Van zodra de entries aangemaakt zijn, moeten de x coordinaten van de tick waarop het element

begint en eindigt nog gekoppeld worden aan de x positie en de breedte van het element. In

dit geval zijn er twee mogelijkheden, afhankelijk van de duur van het element.

� Wanneer een element geen ’echte’ muzikale duur heeft, en de tick waarop het begint en

eindigt dus gelijk is, wordt de x positie van het element met een gelijkrelatie gekoppeld

aan de beginknoop van het interval horende bij de begintick. De breedte van het

element wordt met een maximumrelatie gekoppeld aan de breedte van hetzelfde interval.

� In het andere geval wordt de x positie van het element met een gelijkrelatie gekoppeld

aan de eindknoop van het interval horende bij de begintick. Vervolgens wordt een

somrelatie gelegd tussen die eindknoop en de gewenste breedte van het element. Het

resultaat wordt met een maximum relatie gekoppeld aan de eindknoop van het inter-

val dat hoort bij de eindtick. Tenslotte wordt de effectieve breedte van het element

met een gelijkrelatie gekoppeld aan het verschil van de eindknoop van het interval dat

overeenkomt met de eindtick en de eindknoop van het interval dat overeenkomt met

de begintick. Dit gebeurt aan de hand van een inversierelatie3 op het tweede element,

gevolgd door een somrelatie.

Op deze manier wordt er voor gezorgd dat alle elementen op de juiste plaats getekend worden,

en altijd voldoende plaats krijgen om zich volledig te kunnen tekenen. Deze elementen zijn

wrappers rond de eigenlijke voorstelling in het gegevensmodel en zijn in staat om zichzelf uit

te tekenen. Dit is een kwestie waar het volgende hoofdstuk over handelt.

3Een inversierelatie is een relatie die ervoor zorgt dat de waarde van de tweede knoop steeds gelijk is aan

de waarde van de eerste knoop, vermenigvuldigd met -1.

Page 51: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6

De view

In dit hoofdstuk wordt er dieper ingegaan op de laatste grote pijler van dit eindwerk. De

view is een belangrijk element voor een editor, omdat alles zo vlot en vloeiend mogelijk moet

kunnen gebeuren. De nadruk ligt vooral op de editeeracties en in welke mate deze instelbaar

zijn. Editeracties omvatten acties zoals tussenvoegen door slepen, verwijderen, toevoegen, un-

do/redo operaties, maar ook kopieren, plakken en knippen behoren tot deze categorie. Verder

zijn er ook verschillende views op een en dezelfde partituur mogelijk. De view die we zullen

behandelen is de afspeelmodus (dit is een soort ‘filmrol’ waarbij de volledige partituur als een

lange notenbalk getoond wordt, en waarbij bij het afspelen de notenbalk voorbij schuift). We

zullen eerst de algemene principes toelichten, en later verder gaan met het bespreken van de

meer technische kant en implementatie. Opnieuw heeft de architectuur van het ontwerp een

evolutie meegemaakt, en zijn er fundamentele wijzigingen gebeurd bij de overstap naar het

graafsysteem. Daarom wordt eerst het originele idee, met een coordinatensysteem, toegelicht.

Dit systeem vormt de opstap naar het systeem met knopen en relaties.

6.1 Het Coordinatensysteem

Bij het tekenen van symbolen, notenbalken, akkoorden, lyrics,... werd het snel duidelijk dat

het gebruik van gewone primitieve types1 voor coordinaten moeilijk haalbaar was. Dit wordt

voornamelijk veroorzaakt door het feit dat al deze voorgenoemde elementen op elk moment

kunnen verplaatst worden (hetzij door ze te verslepen, te verwijderen, in te voegen, of ander

gebruikersacties). De positie van een element is dus nooit vast en verandert voortdurend.

6.1.1 Eerste aanpak: het Graphics object

Het Graphics object wordt in Java gebruikt om zelf te tekenen op Java componenten. Initieel

was het zo dat elk element dat getekend kan worden, een methode paintComponent(Graphics

1Primitieve types zoals int, double, float en long

41

Page 52: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 42

g) implementeert. Deze methode werd dan opgeroepen door het ouderobject2 van het object,

zodat het in staat is om op het Graphics object te tekenen. Dit Graphics object bepaalt ook

een regio (figuur 6.1) van het paneel waarop getekend wordt. Zodoende verdeelt elk element

zijn regio op in subregio’s, en verdeelt die onder zijn eventuele kinderen. Die kunnen deze regio

opnieuw opdelen en verdelen, of er zelf op tekenen. Op deze manier verkijgen we een soort

boomstructuur, waarin elk blad uiteindelijk een regio, ergens op het paneel, toegewezen krijgt

waarop hij zichzelf kan tekenen. De ouder is dan telkens verantwoordelijk voor de positie van

zijn kinderen op het paneel. Het probleem dat hierbij optreedt is dat een bladelement daarom

niet direct zijn eigen absolute positie op het paneel kan bepalen. Voor het tekenen zelf is dit

niet onoverkomelijk, maar van zodra er gebruikersinteracties aan te pas komen leidt dit tot

het probleem dat een bladelement zijn eigen positie niet kan aangeven. Alle elementen (van

die regio) moeten dan overlopen worden om na te gaan op welk element geklikt werd.

Figuur 6.1: Illustratieve voorstelling van een regio van een paneel

6.1.2 Tweede aanpak: een apart coordinatensysteem

Eigenlijk werd hierbij voortgebouwd op de vorige aanpak, mits enkele aanpassingen. Elk ob-

ject dat zichzelf moet kunnen tekenen, implementeert nog steeds een methode paintComponent

(Graphics g), waar hij zichzelf op tekent. De berekening van de coordinaten gebeurt echter

anders. Er wordt nu niet meer telkens opgedeeld in gebieden, die dan doorgegeven wor-

den als graphics object. Aan elk van de elementen wordt nu telkens hetzelfde Graphics

object meegegeven, en dit is het graphics object van het gehele paneel. Een element krijgt

twee datavelden bij, van het type ICoordinate. Dit is een interface met als enige functie

getAbsoluteCoordinate(). Deze interface kan vervolgens geımplementeerd worden door

verschillende soorten coordinatenklassen.

� AbsoluteCoordinate: deze klasse heeft een dataveld, met als type IValue. Dit kan

bijvoorbeeld een double, maar tevens een int, float,... zijn. De implementatie van

de functie getAbsoluteCoordinate() is dan ook triviaal, en geeft de waarde van het

dataveld terug.

2In dit geval was dit een JPanel (een standaard Java Swing component).

Page 53: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 43

� RelativeCoordinate: deze klasse heeft zoals de vorige een gegevensveld van het type

IValue, en bijkomend ook een veld met een verwijzing naar een ander ICoordinate

(dit gegevensveld wordt offsetCoordinate genoemd). De implementatie van de functie

getAbsoluteCoordinate() is hier wel anders: hier wordt de waarde van het gegevens-

veld, vermeerderd met de waarde teruggegeven door de overeenkomstige functie van het

offsetCoordinate. Op deze manier kan een soort cascade van coordinaten onstaan: een

relatief coordinaat heeft een aantal voorliggende coordinaten die ook relatief zijn, of een

absoluut, of nog een ander type.

� StaffCoordinate: dit is een speciaal soort coordinaat, dat staffranks mapt op ‘echte’

coordinaten. Een noot kan op deze wijze gewoon de positie die ze heeft op een notenbalk

meegeven aan haar coordinaat en hoeft zich niets aan te trekken van plaats tussen de

lijnen van de notenbalk of het aantal lijnen van de notenbalk. Dit wordt afgehandeld

door het coordinatensysteem.

Het probleem dat bij deze aanpak niet opgelost wordt, is dat bij de wijziging van een element

toch nog onherroepelijk deze wijziging expliciet moet doorgegeven worden. Er is dus een

manuele ingreep nodig. Maar wanneer we dit coordinatensysteem nader bekijken, kunnen we

een absoluut coordinaat beschouwen als een knoop, en een relatief coordinaat als de eindknoop

van een interval. Deze intervallen kunnen we op hun beurt onderbrengen in een dynamisch

gelinkte lijst, die kan deel uitmaken van een andere gelinkte lijst, of kan gekoppeld worden aan

een knoop. Opnieuw onstaat de boomstructuur, die nu echter volledig autonoom zichzelf kan

onderhouden. De structuur van het systeem met knopen en relaties, wordt in de eerstvolgende

paragraaf toegelicht.

6.2 Het graafsysteem

6.2.1 Toegepast op Java Swing componenten

In de volgende stap wordt het graafsysteem ook toegepast op de view (dit omvat de gebruikte

panelen en tekstvelden). Vooreerst wordt er een speciaal paneel gecreeerd, dat afgeleid is van

een JPanel (figuur 6.2). Als eerste hebben we het NodePanel. Deze klasse is abstract en

kan dus niet direct geınstantieerd worden. Deze is rechtstreeks afgeleid van een JPanel, en

vereist in zijn constructor vier knopen: een voor de x positie, y positie, breedte en hoogte.

Vervolgens wordt de LayoutManager op null gezet, omdat een paneel dat zelf zijn grootte

en positie regelt geen LayoutManager nodig heeft om zichzelf uit te lijnen. Op die manier

verkrijgen we meer controle over de positie en grootte van het paneel. Verder overschrijven

we enkele methodes van een JPanel, en voegen we code toe die de knopen updatet wanneer

de locatie of grootte van het paneel verandert (codevoorbeeld 6.1).

Page 54: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 44

Figuur 6.2: Klassenschema van het NodePanel

Codevoorbeeld 6.1: Implementatie van het NodePanel

//Override se tLoca t i on ( x , y )

//Wanneer x/y g ew i j z i g d worden , moeten de knopen ook geA¼pdatet worden

@Override

public void s e tLocat i on ( int x , int y )

{super . s e tLocat i on (x , y ) ;

//Avoid propagat ion

i f ( x != getX ( ) )

xNode . setValue (new Double ( x ) ) ;

i f ( y != getY ( ) )

yNode . setValue (new Double ( y ) ) ;

}//Override the setBounds ( x , y , width , h e i g h t ) method

//Wanneer nieuwe grenzen g e d e f i n i e e r d worden , moeten de knopen ook geA¼pdatet

worden

@Override

public void setBounds ( int x , int y , int width , int he ight )

{super . setBounds (x , y , width , he ight ) ;

//Avoid propagat ion

i f ( x != getX ( ) )

xNode . setValue (new Double ( x ) ) ;

i f ( y != getY ( ) )

Page 55: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 45

yNode . setValue (new Double ( y ) ) ;

i f ( width != getWidth ( ) )

widthNode . setValue (new Double ( width ) ) ;

i f ( he ight != getHeight ( ) )

heightNode . setValue (new Double ( he ight ) ) ;

}//Override s e tP r e f e r r e dS i z e ( p r e f e r r e dS i z e ) method

@Override

public void s e t P r e f e r r e d S i z e ( Dimension p r e f e r r e d S i z e )

{super . s e t P r e f e r r e d S i z e ( p r e f e r r e d S i z e ) ;

widthNode . setValue ( p r e f e r r e d S i z e . getWidth ( ) ) ;

heightNode . setValue ( p r e f e r r e d S i z e . getHeight ( ) ) ;

}

Op dit moment worden de knopen wel geupdatet wanneer de positie of grootte van het paneel

verandert, maar luistert het paneel nog niet naar de knopen zelf. Wanneer de waarde van

die knopen verandert, moet deze verandering immers doorgevoerd worden in de positie of

grootte van het paneel. Voor deze functionaliteit staat het BasicNodePanel in. De reden

waarom deze functionaliteit niet rechtstreeks ondergebracht werd in NodePanel is omdat dit

NodePanel ook gebruikt wordt voor andere doeleinden, waarbij deze automatische aanpassing

niet op die manier vereist is. Hoe dan ook komt de implementatie van BasicNodePanel neer

op het toevoegen van vier luisteraars, op een manier geıllustreerd in codevoorbeeld 6.2.

Codevoorbeeld 6.2: Implementatie van het BasicNodePanel

xNode . addObserver ( new Observer ( )

{public void onNoti fy ( Object source )

{s e tLocat i on ( xNode . getValue ( ) . intValue ( ) , getY ( ) ) ;

}}) ;

yNode . addObserver ( new Observer ( )

{public void onNoti fy ( Object source )

{s e tLocat i on ( getX ( ) , yNode . getValue ( ) . intValue ( ) ) ;

}}) ;

widthNode . addObserver ( new Observer ( )

{public void onNoti fy ( Object source )

{setBounds ( getX ( ) , getY ( ) , widthNode . getValue ( ) . intValue ( ) ,

getHeight ( ) ) ;

Page 56: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 46

s e t P r e f e r r e d S i z e (new Dimension ( widthNode . getValue ( ) . intValue ( ) ,

getHeight ( ) ) ) ;

}}) ;

heightNode . addObserver ( new Observer ( )

{public void onNoti fy ( Object source )

{setBounds ( getX ( ) , getY ( ) , getWidth ( ) , heightNode . getValue ( ) .

intValue ( ) ) ;

s e t P r e f e r r e d S i z e (new Dimension ( getWidth ( ) , heightNode . getValue

( ) . intValue ( ) ) ) ;

}}) ;

De aandachtige lezer zal opmerken dat zowel bij codevoorbeeld 6.1 als 6.2 toch de methode

setPreferredSize() overschreven en aangeroepen wordt. Wanneer een NodePanel namelijk

toegevoegd wordt aan een ander - gewoon - paneel, waarvan de layout wel bepaald wordt door

een LayoutManager, is het belangrijk dat een NodePanel toch juist getekend wordt. Dit geldt

in de eerste plaats voor de dimensie van zo een paneel. Daarom wordt aan het paneel ook

een gewenste grootte meegegeven, waarmee de meeste LayoutManagers wel rekening houden

(dit is niet altijd het geval voor de setSize() of de setBounds() methodes).

6.2.2 Toegepast op het tekenen

Elementen die op een leadsheet getekend kunnen worden, worden opgedeeld in twee catego-

rieen. Enerzijds zijn er de tekstuele elementen, zoals akkoorden of lyrics, en anderzijds zijn er

de muzikale symbolen die kunnen voorkomen op een traditionele notenbalk. In dit ontwerp

is ervoor gekozen om de tekstuele elementen voor te stellen door gemodificeerde JTextPanels

en de notenbalk door gemodificeerde NodePanels. De eerste categorie zou evengoed kunnen

beschouwd kunnen worden als behorende tot de tweede categorie, zodat er maar een type

element zou zijn. Dit brengt wel de consequentie met zich mee dat voor de tekst zelf de ca-

ret moet geımplementeerd worden, alsook highlighting, kopieren, knippen, plakken en andere

editeeracties. Op deze stelling wordt in de overeenkomstige paragraaf kort ingegaan. Dit

terwijl deze acties allemaal al aanwezig zijn in de implementatie van een JTextField. Eerst

zal besproken worden hoe een JTextField aangepast werd om te voldoen aan de noden, en

vervolgens worden de aanpassingen aan een NodePanel beschreven, om een notenbalk met

zijn elementen te kunnen tekenen. Beide categorieen elementen implementeren een gemeen-

schappelijke interface IElement, zodat ze door de TicksToXMapper en RelationBuilder als

gelijk kunnen beschouwd worden (figuur 6.3).

Page 57: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 47

Figuur 6.3: Klassenschema van de elementen

Page 58: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 48

Eerste categorie: tekstvelden

Onder tekstvelden worden velden beschouwd waarin akkoord of lyrics kunnen ingegeven wor-

den. Bijna alles wordt op een leadsheet ’getekend’ met behulp van het Graphics object.

Hiervan worden methodes opgeroepen voor het tekenen van lijnen, tekstsymbolen (zoals mu-

zikale symbolen) en andere geometrische figuren. Er duikt echter een probleem op van zodra

gebruikersinvoer vereist is onder de vorm van tekst. Er zijn hier grossomodo twee pistes

mogelijk.

� Tekst wordt ook getekend op een panel met behulp van de methode drawString() van

het Graphics object. Als een gebruiker wenst de tekst te bewerken, liggen volgende

opties voor de hand.

– De gebruiker klikt of dubbelklikt op een stukje tekst (bijvoorbeeld een lyric of een

akkoord), en krijgt een popupvenster met een tekstvenster, waarin hem gevraagd

wordt om een nieuwe tekst in te geven). Niet alleen is dit voor de gebruiker een

omslachtige aanpak, het is ook esthetisch niet verantwoord. Deze methode werd

dus niet gebruikt.

– De gebruiker klikt of dubbelklikt op een stukje tekst, en er wordt een cursor ge-

tekend, gebruikersinput opgevangen en getoond. Dit is relatief veel werk, en bo-

vendien wordt op die manier iets gemaakt dat eigenlijk al bestaat. Dit strookt

niet met het ontwerpprincipe ‘hergebruik van code’, terwijl dit eigenlijk perfect

mogelijk is. Ook dit systeem werd dus niet gebruikt.

– De gebruiker klikt of dubbelklikt op het stukje tekst, en er wordt on-the-fly een

tekstveld over de tekst geplakt, waarbij de gebruiker een nieuwe tekst kan ingeven

en bevestigen. Ook dit is ontwerptechnisch niet geheel volgens de regels. Voor deze

optie werd alsook niet gekozen.

� Tekst wordt niet getekend, maar er worden ineens tekstvelden getekend, die ‘verdoken’

worden, zodat de gebruiker enkel een ‘echt’ tekstveld te zien krijgt van zodra hij een

tekst probeert te wijzigen.

Het is duidelijk dat de laatste optie de voorkeur geniet, en het is ook deze aanpak die we zullen

volgen, weliswaar in een licht gewijzigde vorm. Omdat een groot deel van de implementa-

tie overeenkomt voor zowel akkoorden als lyrics, worden de functies die voor beide velden

hetzelfde zijn ondergebracht in een abstracte klasse AbstractField (figuur 6.3). Deze klasse

vereist in de constructor een MusicalElement3 en knopen die de positie en de grootte van het

veld bepalen. Net zoals bij een NodePanel worden luisteraars toegevoegd die de positie en

grootte van het veld aanpassen wanneer een van die knopen verandert van waarde, en wor-

den de setLocation(), setBounds en setPreferredSize() methoden overschreven. Verder

3Dit kan een Chord of Lyric zijn.

Page 59: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 49

wordt een DocumentListener geımplementeerd. Deze zorgt ervoor dat bij het wijzigen van de

ingevoerde tekst, het Chord of Lyric element van het model ook aangepast wordt. Zo wordt

bij het wijzigen van tekst in de view onmiddellijk en automatisch het model mee aangepast.

Verder zijn er nog enkele extra functies aanwezig die selectie, highlighting en editeerbaarheid

beheren.

Tweede categorie: de notenbalk

Het tekenen van de notenbalk is meteen heel wat complexer dan tekst tonen. Dit komt vooral

omdat het bij het weergeven van tekst in principe enkel nodig is om de positionering af te

handelen (de breedte en het tekenen van tekst, caret en selectie gebeurt door het JTextField),

terwijl bij een notenbalk elk element manueel getekend moet worden. Dit gaat van de lijnen

van de notenbalk, de verschillende elementen van een nootsymbool tot de caret zelf. Ook

de gewenste breedte moet bepaald worden. Vooreerst is er van in het begin voor gekozen

om, net zoals bij tekst, alle symbolen in aparte panelen te tekenen, en niet een lang paneel te

gebruiken voor de notenbalk. Dit heeft twee redenen. Bij het gebruik van meerdere panelen is

het later eenvoudiger om een notenbalk over meerdere lijnen te spreiden, omdat de notenbalk

reeds gesplitst is in verschillende panelen. Als tweede reden kan aangehaald worden dat bij

het wijzigen van een symbool in de notenbalk enkel het betreffende paneel hertekend moet

worden, in plaats van de volledige notenbalk. Dit zorgt voor een snellere uitvoer van de

repaint() operatie.

Het PartPanel Een PartPanel is een licht gewijzigde implementatie van een BasicNodePa-

nel. Net als het BasicNodePanel is deze klasse afgeleid van NodePanel, maar als toevoeging

houdt deze klasse een gewenste grootte bij met behulp van knopen. Zo heeft een PartPanel

naast een werkelijke grootte ook een gewenste grootte, waarmee rekening gehouden wordt

bij het tekenen van het StaffPart. Doordat die gewenste grootte hier bepaald wordt door de

symbolen die deel uitmaken van het StaffPart (die overigens ook gebruik maken van knopen

om hun positie en grootte te bepalen), worden aparte knopen bijgehouden voor die gewenste

grootte, maar wordt voor het oproepen van setBounds() de werkelijke dimensie gebruikt.

Voorts regelt deze klasse ook enkele paneelspecifieke taken (zoals het highlighten of selecteren

van een paneel), zodat het StaffPart zich enkel moet bekommeren om het uitlijnen en tekenen

van symbolen en notenbalk.

Het StaffPart Het StaffPart tenslotte, is een paneel dat afgeleid is van het PartPanel (fi-

guur 6.3). Het is de taak van dit paneel om muzikale elementen te tekenen en te aligneren. In

de constructor vereist deze klasse twee extra parameters: de rootStaffBase en de postRoot-

StaffBase. Opniew zijn dit knopen, en in dit geval zijn deze dezelfde per part (enkel bij een

StaffPart worden deze effectief gedefinieerd). Hun functie is het bepalen van de y positie

van de onderste lijn van de notenbalk respectievelijk de afstand onder die lijn. Wanneer alle

Page 60: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 50

symbolen van de notenbalk qua grootte binnen de lijnen van de notenbalk vallen, is de eerste

gelijk aan de hoogte van de notenbalk, en is de tweede gelijk aan nul. Wanneer echter in

een van de StaffParts een symbool hoger ligt dan het hoogste punt van de notenbalk, moet

de volledige notenbalk naar beneden opgeschoven worden (en dus in alle StaffParts). De

rootStaffBase krijgt dan een waarde groter dan die van de hoogte van een notenbalk. Dit

komt omdat deze rootStaffBase meegegeven wordt aan een symbool dat getekend dient te

worden, waar de hoogte van dat symbool met een maximum relatie gekoppeld wordt aan

deze rootStaffBase. Exact hetzelfde gebeurt bij de postRootStaffBase voor de ruimte onder

de notenbalk. Ook hier is er geen extra werk meer nodig om de notenbalk in alle andere

StaffParts mee te verschuiven, dankzij het gebruik van de maximum relatie. Een symbool

zelf heeft naast een x en y coordinaat ook een pre en post waarde voor beide coordinaten.

Deze leggen de afstand voor respectievelijk achter dat coordinaat vast, en worden gebruikt

om het symbool correct uit te lijnen. Een voorbeeld met een kwartnoot is gegeven in figuur

6.4. Het systeem van de rootStaffBase en de postRootStaffBase wordt geıllustreerd in figuur

6.5, samen met de implementatiecode in codevoorbeeld 6.3.

Figuur 6.4: Schematische voorstelling van de pre en post waarden van een symbool

Figuur 6.5: Schematische voorstelling van de rootStaffBase en de postRootStaffBase

Codevoorbeeld 6.3: Implementatie van de rootStaffBase en de postRootStaffBase

//De ba s i s o f f s e t van een symbool ( o f f s e t t egenover de s t a f fBa s e )

MutableValueNode<Double> symbolBaseOffset = new BasicValueNode ( 0 . 0 ) ;

//De symbo lBaseOf fse t i s p o s i t i e f a l s he t symbool boven de s t a f fBa s e l i g t , en

n e g a t i e f in he t andere g e va l

new Double Inver s ionRe lat ion ( rankOf fset , symbolBaseOffset ) ;

Page 61: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 51

// S t e l de roo tS t a f fBase automatisch in

MutableValueNode<Double> preSymbolHeight = new BasicValueNode ( 0 . 0 ) ;

//Houd reken ing met de preY waarde van he t symbool

new DoubleSumRelation ( symbolBaseOffset , preYNode , preSymbolHeight ) ;

//De roo tS ta f fBase ( s t a f fBa s e gedee l d door a l l e symbolen van een no tenba l k ) ,

//moet g e l i j k z i j n aan he t maximum van de s t a f fBa s e s van a l l e symbolen

new DoubleMaxRelation ( s ta f fBase , preSymbolHeight ) ;

// S t e l de pos tRootS ta f fBase automatisch in

MutableValueNode<Double> postSymbolHeight = new BasicValueNode ( 0 . 0 ) ;

//Houd reken ing met de postY waarde van he t symbool

new DoubleSumRelation ( rankOffset , postYNode , postSymbolHeight ) ;

//De roo tPos tS ta f fBase ( po s tS t a f fBa se gedee l d door a l l e symbolen van een

notenba l k ) ,

//moet g e l i j k z i j n aan he t maximum van de po s tS t a f fBa s e s van a l l e symbolen

new DoubleMaxRelation ( postSta f fBase , postSymbolHeight ) ;

Verder moeten de gevraagde muzikale elementen ook getekend worden. Om dit te verwezelij-

ken worden deze elementen gekoppeld aan hun overeenkomstige symbolen. Door het invoeren

van de tussenlaag is er nu een een-op-een relatie tussen deze symbolen en hun overeenkomstige

element uit het tussenmodel. Deze symbolen zijn klassen met een paintSymbol(Graphics2D

g) methode die in staat zijn om zichzelf op de juiste plaats op het Graphics2D te tekenen.

Als eerste maakt het StaffPart dus het bijbehorende symbool aan voor een muzikaal element

en koppelt beide aan elkaar. Vervolgens wordt dit symbool toegevoegd aan een lijst, die

overlopen wordt bij het tekenen van het paneel en waarbij dan de paintSymbol(Graphics2D

g) methode van elk symbool opgeroepen wordt, met als Graphics2D object dat van het

paneel. Om dit te bereiken wordt de paintComponent(Graphics g) methode van het paneel

overschreven (codevoorbeeld 6.4).

Codevoorbeeld 6.4: Overschrijven van de paintComponent(Graphics g) methode

public void paintComponent ( Graphics g )

{super . paintComponent ( g ) ;

//Render deze component ind ien d i t nog n i e t gebeurd i s .

i f ( ! rendered )

renderComponent ( g ) ;

//Teken de l i j n e n van de no tenba l k

g . s e tCo lo r ( ViewConstants .STAFF COLOR) ;

for ( int i = 0 ; i < ViewConstants .STAFF LINE COUNT; i++)

g . drawLine (0 , ( int ) Math . c e i l ( r oo tS ta f fBa s e . getValue ( )

− i * ViewConstants . STAFF LINE SPACING) ,

getWidth ( ) , ( int ) Math . c e i l ( r oo tS ta f fBa s e .

getValue ( )

− i * ViewConstants . STAFF LINE SPACING) ) ;

//Teken de symbolen

Page 62: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 52

for ( IRankedStaffSymbol symbol : s ta f fSymbo l s )

symbol . paintSymbol ( ( Graphics2D ) g ) ;

// S t e l de gewenste g r oo t t e in

s e t P r e f e r r e d S i z e (new Dimension ( widthNode . getValue ( ) . intValue ( ) ,

heightNode . getValue ( ) . intValue ( ) ) ) ;

//Teken de care t

ca r e t . pa int ( ( Graphics2D ) g ) ;

}

Omdat een symbool bij initialisatie niet in staat is zijn grootte te bepalen zonder een Grap-

hics object ter beschikking te hebben, moet het StaffPart eerst gerendered worden. Dit wil

zeggen dat bij de eerste aanroep van de paintComponent(Graphics g) methode, eerst een

renderComponent(Graphics g) opgeroepen wordt, die het Graphics object meegeeft aan de

symbolen, waardoor die hun grootte kunnen berekenen. Vervolgens worden de lijnen van de

notenbalk getekend (deze worden eerst getekend omdat deze in de laag onder de symbolen

moeten getekend worden, op de achtergrond). Tenslotte kan de gewenste grootte bepaald

worden, en wanneer er geklikt is op het StaffPart wordt ook de caret getekend. De caret

wordt kort besproken in de volgende paragraaf.

De caret De caret is het knipperende vertikale streepje dat getoond wordt wanneer er

geklikt wordt tussen twee symbolen, en is vergelijkbaar met een caret gebruikt in een tekst-

verwerker. De Caret klasse is een extra hulpklasse voor het StaffPart. Deze caret wordt

afwisselend getoond en verborgen wanneer hij gezet wordt en heeft een paint(Graphics2D

g) methode die opgeroepen wordt door het StaffPart. Voor het pinkende effect wordt een

SwingTimer gebruikt die telkens het tijdsinterval verlopen is de caret toont of verbergt.

6.3 Het tekenen van de symbolen

Uiteindelijk zijn we aangekomen bij het tekenen van de symbolen zelf. Voor ’echte‘ muzi-

kale symbolen (zoals de sleutel, de vlaggen en de notehead), wordt het Fughetta lettertype4

gebruikt. Hiervoor wordt een (reeds geschreven) klasse Fughetta gebruikt, die in staat is

om TextGlyph objecten aan te maken en deze te tekenen op een Graphics object. Rond

dit TextGlyph object werd een wrapper geschreven, die afhankelijk is van het type sym-

bool. Het klassenschema wordt gegeven in figuur 6.6. Zoals te zien is in het klassenschema

(figuur 6.6), is er een gemeenschappelijke boveninterface ISymbol gedefinieerd. Deze inter-

face verzamelt alle methoden die gemeenschappelijk zijn voor een symbool en waarover elk

symbool moet beschikken om zichzelf te kunnen tekenen (op een notenbalk). Deze inter-

face wordt geımplementeerd door de abstracte klasse Symbol. Deze klasse staat in voor het

4Fughetta is een lettertype geschreven door Blake Hodgetts, voor gebruik met Finale (maar het is ook

compatibel met Sibelius). Het bevat een grote hoeveelheid aan muzikale symbolen zoals sleutels, noteheads,

maatcijfers enzovoort. (http://members.efn.org/ bch/fullpackage.html)

Page 63: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 53

Figuur 6.6: Klassenschema van de symbolen

Page 64: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 54

raamwerk omtrent eventuele extra aanroepen voor een repaint() verzoek. Panelen kunnen

zich met de methode addRepaintObserver(Observer o) inschrijven op repaint() verzoeken

van een symbool. Wanneer een symbool moet hertekend worden, kan het de interne functie

requestRepaint() aanroepen om expliciet een repaint() aan te vragen bij zijn luisteraars.

Vervolgens zijn er twee hoofdpistes die gevolgd kunnen worden. Enerzijds die van symbolen

die op de notenbalk zelf geplaatst worden (een StaffSymbol), en anderzijds symbolen die an-

dere symbolen groeperen, en dus meerdere symbolen overspannen (een GroupSymbol). Deze

twee pistes worden elk in een aparte paragraaf besproken.

6.3.1 De StaffSymbols

Een StaffSymbol is een symbool dat op een notenbalk kan geplaatst worden. Het is een sym-

bool dat rekening houdt met de eerder besproken rootStaffBase en postRootStaffBase. De

klasse hier direct van afgeleid is RankedStaffSymbol. Het verschil is zeer miniem, maar toch

werd het onderscheid gemaakt omdat bijvoorbeeld de vlaggen, die aan een stem van een noot

kunnen hangen, geen rank kunnen hebben, en dus ook niet onder de noemer RankedStaff-

Symbol kunnen vallen.

Een RankedStaffSymbol is een symbool dat bij constructie een rank meekrijgt, en automatisch

zijn y positie berekent aan de hand van die rank en de rootStaffBase. Dit gebeurt aan de

hand van relaties waardoor bij een wijziging van die rank de y positie automatisch herberekend

wordt. Deze werkwijze wordt geıllustreerd in codevoorbeeld 6.5.

Codevoorbeeld 6.5: Relaties tussen de ranknode enerzijds en de y positie anderzijds

//Deze rankNode g e l i j k s t e l l e n aan de gegeven rankNode ( d i t i s deze van

a fkoms t i g van he t model )

this . rankNode = new BasicValueNode<Integer >(0) ;

new Equal ( rankNode , this . rankNode ) ;

// In y p o s i t i e wordt a l t i j d een sprong gemaakt met de ha l v e l e n g t e tus sen twee

no t e n b a l k l i j n e n

ValueNode<Double> noteHeadSpacing = new BasicValueNode(− ViewConstants .

STAFF LINE SPACING / 2) ;

//De a f s tand tegenover de onders t e n o t e n b a l k l i j n

MutableValueNode<Double> rankOf f s e t = new BasicValueNode ( 0 . 0 ) ;

// In de r i c h t i n g van de rankNode moet he t r e s u l t a a t a fgerond worden want de

rank i s a l t i j d een g ehe e l g e t a l

new RoundMult ip l i cat ionRe lat ion ( noteHeadSpacing , rankNode , rankOf f s e t ) ;

//Tel de bekomen o f f s e t op b i j de y p o s i t i e van de onders t e l i j n van de

no tenba l k

new DoubleSumRelation ( s ta f fBase , rankOf fset , getYNode ( ) ) ;

De meeste symbolen zijn dan ook RankedStaffSymbols. Op dit niveau wordt nog eenmaal

een onderscheid gemaakt tussen symbolen. Deze die kunnen getekend worden door een sym-

Page 65: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 55

bool uit het lettertype (PrimitiveStaffSymbol), symbolen die samengesteld zijn uit meerdere

primitieve symbolen (ComplexStaffSymbol) en symbolen die niet bestaan uit een karakter uit

alfabet van het Fughetta lettertype (StemSymbol en LedgerLineSymbol).

Het PrimitiveStaffSymbol Deze klasse groepeert alle symbolen die kunnen getekend wor-

den met een symbool uit het Fughetta lettertype. De afgeleide klassen zorgen ervoor dat tel-

kens het juiste symbool geladen wordt, en de bovenklasse PrimitiveStaffSymbol zorgt ervoor

dat de grootte van het letterteken ingesteld wordt op de grootte van het symbool. Verder

zorgt ze ervoor dat het symbool effectief getekend wordt, zoals in codevoorbeeld 6.6 getoond

wordt.

Codevoorbeeld 6.6: Implementatie van PrimitiveStaffSymbol

protected void updateNodes ( )

{preXNode . setValue ( textGlyph . getBounds ( ) . getMinX ( ) ) ;

postXNode . setValue ( textGlyph . getBounds ( ) . getMaxX ( ) ) ;

preYNode . setValue(− textGlyph . getBounds ( ) . getMinY ( ) ) ;

postYNode . setValue ( textGlyph . getBounds ( ) . getMaxY ( ) ) ;

}

@Override

public void paintSymbol ( Graphics2D g )

{super . paintSymbol ( g ) ;

textGlyph . pa int ( g , Math . c e i l ( getX ( ) ) , Math . c e i l ( getY ( ) ) ) ;

}

Het ComplexStaffSymbol Deze klasse groepeert de eerder gedefinieerde PrimitiveStaff-

Symbols. Een duidelijk voorbeeld hiervan is een noot, die uit vele afzonderlijke elementen kan

bestaan. Het enige symbool dat altijd aanwezig is bij een noot is de notehead. Verder kan

een noot ook een stem, een of meerdere punten en vlaggen, en een wijzigingsteken hebben.

Wanneer een Note object meegegeven wordt aan een NoteSymbol wordt dan ook eerst be-

paald welke elementen getekend worden en wat hun type is (er zijn bijvoorbeeld verschillende

noteheads en wijzigingstekens). Maar wanneer een Note object verandert, moeten eventueel

ook de symbolen van het NoteSymbol aangepast worden, en dat is waarvoor dit NoteSym-

bol instaat. In de ComplexStaffSymbol klasse worden de methoden die de grootte van het

NoteSymbol vastleggen verzameld (codevoorbeeld 6.7). Om de grootte van een ComplexStaff-

Symbol te bepalen worden de grenzen van al deze symbolen toegevoegd aan een Rectangle2D

(codevoorbeeld 6.8).

Page 66: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 56

Codevoorbeeld 6.7: Implementatie van ComplexStaffSymbol

protected void updateNodes ( )

{preXNode . setValue ( getX ( ) − r e c t a n g l e . getMinX ( ) ) ;

postXNode . setValue ( r e c t a n g l e . getMaxX ( ) − getX ( ) ) ;

preYNode . setValue ( getY ( ) − r e c t a n g l e . getMinY ( ) ) ;

postYNode . setValue ( r e c t a n g l e . getMaxY ( ) − getY ( ) ) ;

//Vraag e x p l i c i e t om het symbool t e her tekenen

requestRepa int ( ) ;

}

Codevoorbeeld 6.8: Bepalen van de grootte van een ComplexStaffSymbol

private void ca lcu lateBounds ( )

{// I n i t i a l i s e e r grenzen

r e c t a n g l e = new Rectangle2D . Double ( getX ( ) , getY ( ) , 0 , 0) ;

//Bereken grenzen

i f ( acc identa lSymbol != null )

r e c t a n g l e . add ( acc identa lSymbol . getBounds ( ) ) ;

i f ( noteHeadSymbol != null )

r e c t a n g l e . add ( noteHeadSymbol . getBounds ( ) ) ;

i f ( stemSymbol != null )

r e c t a n g l e . add ( stemSymbol . getBounds ( ) ) ;

for ( ISta f fSymbol f lagSymbol : f lagSymbols )

r e c t a n g l e . add ( f lagSymbol . getBounds ( ) ) ;

for ( ISta f fSymbol dotSymbol : dotSymbols )

r e c t a n g l e . add ( dotSymbol . getBounds ( ) ) ;

//Update de knopen ( pas grenzen toe )

updateNodes ( ) ;

}

6.3.2 De GroupSymbols

Tenslotte zijn er de GroupSymbols. Deze symbolen hebben geen rank en verzamelen ver-

schillende andere symbolen. Als voorbeeld kunnen we ties en beams aanhalen. Groepe-

ringssymbolen hebben een aantal methodes om andere symbolen toe te voegen of te ver-

wijderen uit een groep. Bij een TieSymbol is dit bijvoorbeeld setLeftSymbol(ISymbol

symbol) en setRightSymbol(ISymbol symbol). Wat de implementatie van de paintSymbol

(Graphics2D g) inhoudt is afhankelijk van het GroupSymbol en het zou ons hier te ver leiden

deze voor elk symbool apart te bespreken. Wel houden ze allemaal rekening met de positie

van de toegevoegde symbolen. Als we als voorbeeld het TieSymbol nemen, wordt de positie

van de noteheads van de twee toegevoegde symbolen (links en rechts) gebruikt als startpunt

respectievelijk eindpunt van de boog tussen de noten.

Page 67: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 57

6.4 Een extraatje: Scribbles

Tot slot van dit hoofdstuk zullen we een extra functionaliteit van de editor behandelen,

Scribbles gedoopt. Omdat het in de editor (op dit moment) enkel mogelijk is om een leadsheet

te bekijken in filmrol modus5 (figuur 6.7), is de hoogte van de GUI betrekkelijk klein tegenover

zijn breedte. Ook is het uitgangspunt van de editor net dat een leadsheet incrementeel,

door samenwerking van verschillende mensen, opgebouwd wordt. Om deze samenwerking

te bevorderen en gemakkelijker te maken, is het mogelijk om onder de leadsheet notities6

te plakken door te dubbelklikken onder de leadsheet. Verder kunnen deze verschoven en

aangepast worden. Iemand die akkoorden intypt kan dan bijvoorbeeld bij de juiste akkoorden

een notitie plakken met de tekst ‘strofe’, ‘refrein’, ‘brug’ en ‘solo’. Zo kan een tekstschrijver

zijn tekst optimaal afstemmen op de ingevoerde akkoorden. Een voorbeeld van een notitie is

gegeven in figuur 6.8.

Figuur 6.7: Schematische voorstelling van een filmrolview

Figuur 6.8: Voorbeeld van een notitie

5Dit wil zeggen dat de leadsheet op een lange lijn getoond wordt, en dat men moet scrollen om doorheen

de partituur te navigeren.6Deze notities worden scribbles genoemd in plaats van notes om naamsverwarring met een note (noot) te

vermijden.

Page 68: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 6. De view 58

Page 69: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 7

Deployment

Zoals reeds aangehaald in de inleiding zal het programma online beschikbaar gemaakt worden.

Het is de bedoeling dat de gebruiker zich geen zorgen hoeft te maken over het downloaden

of installeren van het programma. Aangezien als programmeertaal Java gekozen werd, zijn

er diverse oplossingen mogelijk. Een eerste optie die voor de hand lag, was het gebruik van

de applet technologie. Er zijn dan maar een minimaal aantal aanpassingen nodig, omdat een

JPanel evengoed aan een Canvas kan toegevoegd worden, die op zijn beurt dan ingevoegd

kan worden in een Applet. Omdat deze aanpak ietwat verouderd is, is er gezocht naar een

alternatief. Dat alternatief werd gevonden bij Java WebStart.

Java WebStart is een technologie ontworpen om applets op termijn te vervangen. Het voordeel

van deze nieuwere technologie is dat het programma niet langer in de webbrowser zelf draait,

maar zoals een gewone Java applicatie in staat is om stand-alone uitgevoerd te worden1. Dit

brengt met zich mee dat alle bronnen van de computer benut kunnen worden. Zo is het (in

tegenstelling tot applets) bijvoorbeeld mogelijk om gebruik te maken van MIDI, wat bij dit

soort applicatie een groot voordeel is. Verder wordt de applicatie automatisch up-to-date

gehouden door het Java WebStart framework.

Naast het gecompileerde JAR bestand, is er een extra bestand nodig om het programma

gebruiksklaar te maken voor de Java WebStart technologie. Dat bestand wordt het JNLP2

bestand genoemd. Het betreft een XML bestand, gedefinieerd door een XML Schema. Het

JNLP bestand bestaat uit een verzameling regels die exact bepalen hoe de applicatie gestart

moet worden. Verder bevat dit bestand informatie zoals de locatie van het JAR bestand, de

naam van de Main class van de applicatie, samen met andere parameters voor het programma.

Wanneer de clientbrowser goed geconfigureerd is, geeft hij het JNLP bestand door aan de

1Standaard worden Java WebsStart applicaties ’restricted’ uitgevoerd, waardoor ze geen toegang hebben

tot sommige systeembronnen, zoals lokale bestanden. Deze restricties kunnen echter eenvoudig opgeheven

worden door de Java WebStart applicatie te ondertekenen met behulp van de jarsigner tool (deze is standaard

aanwezig bij de JDK)2Java Network Launching Protocol

59

Page 70: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 7. Deployment 60

JRE3, die vervolgens de applicatie download op de clientcomputer en ze vervolgens uitvoert.

De gebruiker kan er dan later zelfs voor kiezen om een snelkoppeling op het bureaublad te

plaatsen die rechtstreeks de Java WebStart service aanspreekt, nakijkt of de gedownloadde

versie van het programma de nieuwste is, en het programma tenslotte uitvoert. Als de

ontwikkelaar dit toelaat, is het zelfs mogelijk de applicatie volledig offline uit te voeren (het

JAR bestand wordt dan bijgehouden in een cache).

Aangezien de applicatie ontwikkeld werd in de NetBeans programmeeromgeving, is het de-

ployment van de applicatie met behulp van Java WebStart geen probleem. NetBeans is zelf

in staat dit JNLP bestand op te bouwen en de applicatie te ondertekenen, zodat slechts een

minimum aan extra werk vereist is. Een voorbeeld van het JNLP bestand gebruikt voor

testdoeleinden is terug te vinden in codevoorbeeld 7.1.

Codevoorbeeld 7.1: Het JNLP bestand gebruikt voor testdoeleinden

<?xml version=” 1 .0 ” encoding=”UTF−8” standalone=”no”?>

< !−− Locat i e van he t de JAR bestanden en he t JNLP bes tand −−><j n l p codebase=” f i l e : /C:/ Users /Rik%20Bauwens/Documents/ NetBeansProjects /

Masterproef / java /JFonia/ d i s t /” h r e f=” launch . j n l p ” spec=”1.0+”>

< !−− Extra in fo rmat i e in verband met de a p p l i c a t i e −−><i n fo rmat ion>

< t i t l e>JFonia</ t i t l e>

<vendor>Rik Bauwens</ vendor>

<homepage h r e f=””/>

<d e s c r i p t i o n>JFonia</ d e s c r i p t i o n>

<d e s c r i p t i o n kind=” shor t ”>JFonia</ d e s c r i p t i o n>

</ in fo rmat ion>

< !−− Er wordt op de achtergrond ( t ransparant voor de g e b ru i k e r )

nagegaan o f er updates b e s ch i k baar z i j n −−><update check=”background”/>

< !−− Rechten waarover he t programma b e s c h i k t i n s t e l l e n −−><s e c u r i t y>

<a l l−permi s s i ons />

</ s e c u r i t y>

< !−− Namen van de g e b r u i k t e JAR bestanden −−><r e s o u r c e s>

< j 2 s e version=”1.5+”/>

<j a r h r e f=”JFonia . j a r ” main=” true ”/>

<j a r h r e f=” l i b / g e r v i l l . j a r ”/>

<j a r h r e f=” l i b /TarsosDSP . j a r ”/>

</ r e s o u r c e s>

< !−− Klassebes tand waarin he t hoofdprogramma z i c h b e v ind t aanduiden −−><app l i c a t i on−desc main−c l a s s=” org . j f o n i a . view . main . MainFrame”>

</ app l i c a t i on−desc>

</ j n l p>

3Java Runtime Environment

Page 71: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 7. Deployment 61

Van zodra het JNLP bestand aangemaakt en het JAR bestand gecompileerd en ondertekend

is, komt het er enkel op aan deze bestanden op een webserver te plaatsen. Om de applicatie

tenslotte beschikbaar te stellen voor het publiek, kan op een website een link voorzien worden

naar het JNLP bestand. Van zodra een gebruiker op deze link klikt, wordt het JNLP bestand

gedownload en automatisch geopend door de Java WebStart module. Omdat er op deze

manier niet op voorhand gecontroleerd wordt of Java wel degelijk gınstalleerd is op de machine

van de gebruiker, is het beter om met behulp van JavaScript eerst te controleren of Java

aanwezig is, en indien dit niet het geval is de gebruiker door te sturen naar de downloadpagina.

Dit kan op de manier geıllustreerd in codevoorbeeld 7.2.

Codevoorbeeld 7.2: Voorbeeld van een JavaScript fragment om de applicatie te starten

<s c r i p t s r c=” h t t p : // java . com/ j s / deployJava . j s ”></ s c r i p t>

<s c r i p t>

deployJava . createWebStartLaunchButton ( ” launch . j n l p ” )

</ s c r i p t>

Als het enkel gewenst is de applicatie lokaal te testen, kan evenzeer gekozen worden om

rechtstreeks het JAR bestand uit te voeren vanuit de console door middel van de commando-

opdracht java -jar JFonia.jar. Wanneer Java echter correct geconfigureerd werd, is het

meestal mogelijk gewoon te dubbelklikken op dit JAR bestand om het uit te voeren.

Page 72: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 7. Deployment 62

Page 73: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 8

Conclusies en perspectieven

Als afsluitend hoofdstuk wordt nog kort behandeld wat deze applicatie nu eigenlijk biedt als

deel van een groter project en wat de mogelijke uitbreidingen zijn. Aangezien muziek een heel

complex gegeven is, blijft er zeker nog ruimte voor verbetering en aanpassing van de editor.

Tenslotte wordt kort het betaprogramma aangehaald, dat georganiseerd is met als doel een

zo gebruiksvriendelijke en intuıtief mogelijke editor te bouwen.

8.1 Een stukje van de taart

Zoals reeds eerder vermeld werd, is het de bedoeling deze editor te integreren in een grotere

applicatie, die meer functionaliteiten biedt. Op deze manier zou de editor een component

of module kunnen zijn, die kan aan- of uitgeschakeld worden in deze ’verzamel’ applicatie.

In het geval van het eindwerk van Jannes Plyson, wordt de partituurweergave van de editor

bijvoorbeeld gebruikt om bij het aanpassen van een bepaald ritme, dit ritme ook daadwerkelijk

in noten te tonen. Het is mogelijk dat de toonhoogte van deze noten onbepaald is, maar het

ritme kan wel aangegeven worden, alsook het maatcijfer. Zo kan deze module gebruikt worden

in elke applicatie, gebouwd op de graafstructuur, die een partituur moet kunnen tonen (en

eventueel zelfs bewerken). Op dezelfde manier verzamelt de editor uiteindelijk ook de modules

die instaan voor het tonen en bewerken van een notenbalk, het tappen van een ritme met

behulp van een toetsenbord (of microfoon) en het afspelen van een leadsheet. De editor zelf

is in dat opzicht ook een ’grotere’ applicatie die een aantal modules verzamelt om bepaalde

functionaliteiten te bieden aan de eindgebruiker. De enige reden waardoor dit mogelijk is, is

het gezamelijke gebruik van de graafstructuur met zijn bijbehorende knopen en relaties, die

uiteindelijk alles op de correcte manier verbindt.

63

Page 74: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 8. Conclusies en perspectieven 64

8.2 Uitbreidmogelijkheden

Zoals reeds eerder aangehaald is, is muziek zo complex dat er nog ontelbare mogelijkheden zijn

om deze editor uit te breiden. Net zoals een spreektaal zijn er bij muzikale notatie tientallen

verschillende dialecten om muziek te noteren (bijvoorbeeld akkoordnamen, naamgeving van

noten met letters of nootnamen). Ook de editor zelf kan nog uitgebreid worden. Een betere

foutcontrole van ingevoerde gegevens zou een optie kunnen zijn (als het maatcijfer bijvoor-

beeld 4 4 is, niet toelaten dat een maat langer of korter duurt dan de opgelegde tijd). Verder

kan de gebruiker de mogelijkheid gegeven worden om alle elementen van een partituur zelf

nog een beetje op te schuiven tegenover hun oorspronkelijke (automatisch berekende) positie.

Overigens kan er ook een andere view op het model gedefinieerd worden, bijvoorbeeld een

die de leadsheet automatisch formatteert om er een afdruk van te maken (parts worden dan

eventueel gesplitst over meerdere lijnen). Ook zou de ondersteuning van meerdere formaten

en standaarden ondersteund kunnen worden (bijvoorbeeld ook opslaan in het MusicXML for-

maat). Rechtstreeks inspelen met een MIDI instrument is in principe ook geen grote stap,

omdat MIDI bestanden reeds geopend kunnen worden. Als laatste zou het ook interessant

zijn om de mogelijkheid te bieden een gewone geluidsopname aan de leadsheet toe te voegen.

Denken we bijvoorbeeld aan een zanglijn, die dan mee kan afgespeeld worden met de andere

instrumenten, waarvan de melodie ingegeven is met behulp van noten. De voorbeelden hier

gegeven zijn slechts een greep uit de ontelbare uitbreidingen die mogelijk zijn.

8.3 Het betaprogramma

Omdat het bij een editor heel belangrijk is dat alles zo intuıtief mogelijk opgebouwd is, hebben

we een kleinschalig marktonderzoek gedaan onder de vorm van een betaversie. We hebben de

afgewerkte versie van het programma online geplaatst, en hebben daarbij een contactformulier

voorzien. Mensen hadden de mogelijkheid om het programma online te testen (de distributie

gebeurde met behulp van Java WebStart1). Wanneer ze bij het gebruiken van de editor

problemen ondervonden, of bepaalde dingen minder gebruiksvriendelijk vonden, konden ze dit

laten weten met behulp van dit formulier. Deze informatie kan belangrijk zijn voor eventuele

toekomstige versies van dit programma of voor een mogelijke uitbreiding. Hieronder wordt

een summier overzicht gegeven van de meest opmerkelijke bevindingen.

� In het begin blijkt het voor de meeste gebruikers even wennen aan het selectiesysteem

met de caret. Van zodra ze het systeem doorhebben (de selectie ’sleept’ achter de caret),

vindt de overgrote meerderheid het een handig systeem, omdat er zo snel een selectie

gemaakt kan worden.

1Door gebruik te maken van de Java WebStart technologie is het mogelijk om alleenstaande Java applicaties

de distribueren over een netwerk. Java WebStart zorgt ervoor dat altijd de meest recente versie van de applicatie

gebruikt wordt, en dat bij het uitvoeren gecontroleerd wordt of de juiste versie van de JRE aanwezig is.

Page 75: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 8. Conclusies en perspectieven 65

� De overgrote meerderheid vond gewenste functies relatief snel weer, maar zogenaamde

tooltips of iets dergelijks zouden hier en daar handig zijn (bijvoorbeeld bij de notatiebalk,

waarvan de inhoud kan veranderen door op knoppen te klikken).

� De rhythm-by-tapping functie schijnt populair te zijn bij zowel muzikanten als niet-

muzikanten, omdat het de invoer van een partituur danig kan versnellen.

� Aan sommige editeeracties (onder andere kopieren, knippen en plakken) kan nog ver-

betering aangebracht worden.

� Een leadsheet laden kan soms lang duren, waardoor de GUI soms even blokkeert. Dit

is uiteraard niet wenselijk.

� Het afspelen van een leadsheet verloopt redelijk vlot, en er kan gewisseld worden van

instrument tijdens het afspelen. Ook tijdens het afspelen oogt de GUI rustig (er wordt

dan door de leadsheet gescrold). Het zou echter handig zijn moest ook de plaats waar

het afspelen moet beginnen kan aangeduid worden (nu begint het afspelen telkens bij

het begin, enkel wanneer er gepauzeerd wordt begint het afspelen opnieuw waar gestopt

werd).

Page 76: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Hoofdstuk 8. Conclusies en perspectieven 66

Page 77: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage A

Muzikale termen

In onderstaande tabel worden enkele veel voorkomende muzikale termen verduidelijkt.

A la

B si

C do

D re

E mi

F fa

G sol

Tabel A.1: Muzikale termen

Centrale do: voor de voorstelling van noten wordt gebruik gemaakt van de (licht gewijzigde)

base40 rank voorstelling1. In deze voorstelling wordt de rank van elke noot bijgehouden

tegenover de centrale do (ook wel C4 genoemd). Op een traditionele notenbalk met een

solsleutel, staat deze noot op het eerste hulplijntje onder de notenbalk.

1Base40 pitches/intervals, Hewlett (http://www.ccarh.org/publications/reprints/base40/). De variant ge-

bruikt in deze editor neemt als rank voor de centrale do 0, terwijl in de originele implementatie voor 103

gekozen werd.

67

Page 78: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage A. Muzikale termen 68

Page 79: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage B

Muzikale symbolen

Hieronder is een tabel met verschillende muzikale symbolen gegeven, aangepast overgenomen

van Wikipedia.1

Notenbalk / Staff

Hulplijnen / Ledger lines

Maatstreep / Bar

Herhalingstekens / Repeat signs

Verbindingsboog / Tie

Verbindingsboog / Slur

Tabel B.1: Muzikale symbolen

Figuur B.1: De delen van een noot

1http://en.wikipedia.org/wiki/List_of_musical_symbols en http://en.wikipedia.org/wiki/List_

of_musical_symbols

69

Page 80: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage B. Muzikale symbolen 70

Page 81: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage C

Kwintencirkel

Hieronder is de kwintencirkel gegeven, gebruikt in de harmonieleer om onder andere de toon-

aard af te leiden aan de hand van de voortekening.

Figuur C.1: De kwintencirkel

71

Page 82: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage C. Kwintencirkel 72

Page 83: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage D

Beknopte handleiding

Hieronder werd een beknopte (visuele) handleiding voor de editor afgedrukt die de basisacties

verzamelt en de meest gebruikte knoppen aanduidt.

Figuur D.1: Beknopte handleiding

73

Page 84: Incremental Leadsheet Editor - Proximususers.skynet.be/fa251387/Incremental_Leadsheet_Editor/Over_files/l… · Tenslotte gaat mijn dank oprecht uit naar iedereen die op enige manier

Bijlage D. Beknopte handleiding 74