...

Επιβλέπων Καθηγητής : κ. Ακουµιανάκης ∆ηµοσθένης Γρηγορακάκη Αιµιλία Α.Μ. 1292

by user

on
Category: Documents
29

views

Report

Comments

Transcript

Επιβλέπων Καθηγητής : κ. Ακουµιανάκης ∆ηµοσθένης Γρηγορακάκη Αιµιλία Α.Μ. 1292
ΤΕΧΝΟΛΟΓΙΚΟ ΕΚΠΑΙ∆ΕΥΤΙΚΟ Ι∆ΡΥΜΑ ΚΡΗΤΗΣ
ΣΧΟΛΗ ΤΕΧΝΟΛΟΓΙΚΩΝ ΕΦΑΡΜΟΓΩΝ
ΤΜΗΜΑ ΕΦΑΡΜΟΣΜΕΝΗΣ ΠΛΗΡΟΦΟΡΙΚΗΣ & ΠΟΛΥΜΕΣΩΝ
Θέµα : « Εικονική Αναπαράσταση Μουσικών Κοινοτήτων Στο ∆ιαδίκτυο »
Επιβλέπων Καθηγητής : κ. Ακουµιανάκης ∆ηµοσθένης
Επιµέλεια : Ευθυµίου Μιχαλίτσα Α.Μ. 1220
Γρηγορακάκη Αιµιλία Α.Μ. 1292
Κρήτη, Ιανουάριος 2009
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Περιεχόμενα
1. Εκφώνηση ...........................................................................................................................7
2. Παραπλήσιες εργασίες........................................................................................................8
2.1 ABC4J...........................................................................................................................9
2.2 Impro-Visor.................................................................................................................13
2.3 JFugue .........................................................................................................................14
2.4 JMusic .........................................................................................................................16
2.5 JFrets ...........................................................................................................................17
2.6 Οδηγίες λήψης κώδικα εφαρµογών ............................................................................19
2.6.1 Λήψη κώδικα JFugue Music Notepad από NetBeans ........................................19
2.6.2 Λήψη κώδικα JFrets από NetBeans .....................................................................20
3. Μουσικοί κανόνες.............................................................................................................22
4. Προδιαγραφές πτυχιακής εργασίας ..................................................................................41
5. Ανάλυση του κώδικα score-editor ....................................................................................43
5.1 Αρχείο: Main.java.......................................................................................................46
5.2 Αρχεία: DPianoStave,Dstave,DGrandStave,DTrebleStave ........................................47
5.3 Αρχεία: DNoteEditor και DStaveActionHandler .......................................................51
5.4 Αρχεία: Dot1.java, Main.form, ScoreEditor.form ......................................................53
5.5 Αρχείο: ScoreEditor.java ............................................................................................55
6. Υλοποίηση ........................................................................................................................56
6.1 Μετρονόµος ................................................................................................................56
6.2 Βελτίωση αρχείου: ScoreEditor.java ..........................................................................58
6.3 Βελτίωση αρχείου: Main.java.....................................................................................63
6.4 Αρχείο: Constants.java................................................................................................68
6.5 Αρχείο: GuitarNeck.java.............................................................................................70
6.6 Αρχείο: DStave.java....................................................................................................79
6.7 ∆ιάδραση ανάµεσα στην παρτιτούρα και την εικονική κιθάρα..................................83
6.8 Ανοιχτές χορδές ..........................................................................................................88
6.9 ∆ηµιουργία Ant Script ................................................................................................96
6.10 Μετατροπή εφαρµογής σε Applet ..........................................................................102
6.11 ∆ηµιουργία Ιστοσελίδας .........................................................................................111
7. Σύνοψη και Συµπεράσµατα ............................................................................................120
8. Βιβλιογραφία ..................................................................................................................121
Παράρτηµα 1.......................................................................................................................124
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
2
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήματα
Σχήµα 2-1: Παρτιτούρα µε βάση το ABC4J.......................................................................... 9
Σχήµα 2-2: Απεικόνιση παρτιτούρας ABC4J µε νότες και µουσικό κλειδί. ....................... 10
Σχήµα 2-3: Απεικόνιση παρτιτούρας ABC4J µετά την προσθήκη µπαρών. ....................... 10
Σχήµα 2-4: Απεικόνιση παρτιτούρας ABC4J µετά την προσθήκη του µέτρου................... 11
Σχήµα 2-5: Απεικόνιση παρτιτούρας ABC4J µετά την εισαγωγή tie και slurs................... 11
Σχήµα 2-6: Παρτιτούρα ABC4J χωρίς στοίχιση. ................................................................ 12
Σχήµα 2-7: Παρτιτούρα ABC4J µε πλήρη στοίχιση............................................................ 12
Σχήµα 2-8: ∆ιεπαφή της εφαρµογής Impro-Visor............................................................... 13
Σχήµα 2-9: ∆ιεπαφή της εφαρµογής JFrets. ........................................................................ 17
Σχήµα 2-10: Ο µετρονόµος του JFrets................................................................................. 18
Σχήµα 2-11: Παράθυρο Netbeans για το checkout του JFugue Music Notepad. ................ 20
Σχήµα 2-12: Παράθυρο Netbeans για το checkout του JFrets............................................. 21
Σχήµα 3-1: Μουσικό πεντάγραµµο...................................................................................... 22
Σχήµα 3-2: ∆ιαστήµατα µουσικού πενταγράµµου. ............................................................. 22
Σχήµα 3-3: Κλειδιά του ΣΟΛ. ............................................................................................. 23
Σχήµα 3-4: Κλειδιά του ΦΑ................................................................................................. 23
Σχήµα 3-5: Κλειδιά του ΝΤΟ. ............................................................................................. 23
Σχήµα 3-6: Κλειδί του ΣΟΛ της 2ης γραµµής...................................................................... 24
Σχήµα 3-7: Οι φθόγγοι του πενταγράµµου. ......................................................................... 24
Σχήµα 3-8: Οκτάβα ή ογδόη. ............................................................................................... 24
Σχήµα 3-9: Κλίµακα (σκάλα του ΝΤΟ)............................................................................... 25
Σχήµα 3-10: Τόνοι και ηµιτόνια. ......................................................................................... 25
Σχήµα 3-11: Σχήµατα φθογγοσήµων. .................................................................................. 26
Σχήµα 3-12: Ολόκληρο........................................................................................................ 27
Σχήµα 3-13: ∆ιαίρεση ολόκληρου σε 2 µισά....................................................................... 27
Σχήµα 3-14: ∆ιαίρεση ολόκληρου σε 4 τέταρτα. ................................................................ 28
Σχήµα 3-15: ∆ιαίρεση ολόκληρου σε 8 όγδοα. ................................................................... 28
Σχήµα 3-16: Ισοδυναµίες ολόκληρου. ................................................................................. 29
Σχήµα 3-17: Ισοδυναµίες µισού........................................................................................... 30
Σχήµα 3-18: Ισοδυναµίες τετάρτου. .................................................................................... 30
Σχήµα 3-19: Ισοδυναµίες ογδόου. ....................................................................................... 31
Σχήµα 3-20: Ισοδυναµίες δεκάτου έκτου. ........................................................................... 31
Σχήµα 3-21: Ισοδυναµία τριακοστού δευτέρου................................................................... 32
Σχήµα 3-22: Ισοδυναµία αξίας κάθε φθογγοσήµου............................................................. 32
Σχήµα 3-23: Γραφή φθογγοσήµων στο πεντάγραµµο. ........................................................ 33
Σχήµα 3-24: Μουσικό µέτρο στο πεντάγραµµο. ................................................................. 33
Σχήµα 3-25: Μουσική σύνθεση σε µέτρο 2:4...................................................................... 34
Σχήµα 3-26: Ισοδυναµία ολόκληρου παρεστιγµένου. ......................................................... 35
Σχήµα 3-27: Ισοδυναµίες παρεστιγµένων φθογγοσήµων.................................................... 35
Σχήµα 3-28: Πίνακας σχηµάτων φθογγοσήµων και παύσεων............................................. 36
Σχήµα 3-29: Παρεστιγµένες και δις παρεστιγµένες παύσεις............................................... 36
Σχήµα 3-30: Απεικόνιση φθογγοσήµου ΝΤΟ δίεση στο πεντάγραµµο. ............................. 37
Σχήµα 3-31: Αντιστοιχία φθογγοσήµων στην ταστιέρα της κιθάρας.................................. 38
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
3
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 4-1: ∆ιεπαφή αρχικού score editor. .......................................................................... 41
Σχήµα 5-1: ∆οµή αρχείων του score editor. ........................................................................ 43
Σχήµα 5-2: Προσθήκη βιβλιοθήκης JMusic στον score editor............................................ 44
Σχήµα 5-3: Exception του score editor. ............................................................................... 45
Σχήµα 5-4: Uml διάγραµµα κλάσεων των staves του score editor...................................... 47
Σχήµα 5-5: Attributes του DStave.java................................................................................ 49
Σχήµα 5-6: Απεικόνιση του JComboBox του score editor.................................................. 50
Σχήµα 5-7: Παράθυρο επεξεργασίας των ............................................................................ 51
Σχήµα 5-8: Popup menu του score editor. ........................................................................... 52
Σχήµα 5-9: Γραφικό περιβάλλον κλάσης View................................................................... 54
Σχήµα 5-10: Παράθυρο επιλογής µουσικού οργάνου. ........................................................ 55
Σχήµα 5-11: Απεικόνιση κουµπιών του score editor........................................................... 55
Σχήµα 5-12: Κώδικας εισαγωγής τυχαίων νοτών στην παρτιτούρα.................................... 55
Σχήµα 6-1: Package structure µετρονόµου. ......................................................................... 56
Σχήµα 6-2: Παράθυρο µετρονόµου. .................................................................................... 57
Σχήµα 6-3: Μενού µε κουµπιά του score editor. ................................................................. 58
Σχήµα 6-4: Exception διαγραφής τελευταίας νότας σε άδεια παρτιτούρα. ......................... 58
Σχήµα 6-5: Look & Feel εφαρµογής.................................................................................... 63
Σχήµα 6-6: Μενού File. ....................................................................................................... 64
Σχήµα 6-7: Μενού Tools...................................................................................................... 64
Σχήµα 6-8: Μενού Help....................................................................................................... 64
Σχήµα 6-9: Μήνυµα στο ‘About’......................................................................................... 64
Σχήµα 6-10: Παράθυρο επιλογής αρχείου για αποθήκευση. ............................................... 67
Σχήµα 6-11: Οι εικόνες του Constants.java......................................................................... 68
Σχήµα 6-12: Εικονική κιθάρα JFrets. .................................................................................. 70
Σχήµα 6-13: Απεικόνιση τωνµεγεθών των κουµπιών που υλοποιήθηκαν. ......................... 70
Σχήµα 6-14: Πρώτο prototype της εικονικής κιθάρας........................................................ 70
Σχήµα 6-15: ∆εύτερο prototype της εικονικής κιθάρας. ..................................................... 71
Σχήµα 6-16: Τρίτο prototype της εικονικής κιθάρας........................................................... 71
Σχήµα 6-17: Απεικόνιση οβάλ σχήµατος στο prototype της εικονικής κιθάρας................. 72
Σχήµα 6-18: Wood texture ταστίερας της κιθάρας.............................................................. 72
Σχήµα 6-19: Εικονική αναπαράσταση µπράτσου κιθάρας. ................................................. 72
Σχήµα 6-20: Πάνελ κουµπιών εικονικής κιθάρας. .............................................................. 73
Σχήµα 6-21: Πάνελ εικονικής κιθάρας. ............................................................................... 73
Σχήµα 6-22: Νότες στην ταστιέρα της κιθάρας................................................................... 73
Σχήµα 6-23: ∆ιεπαφή εικονικής κιθάρας............................................................................. 74
Σχήµα 6-24: Μουσικά σύµβολα που έπρεπε να επαναδηµιουργηθούν. .............................. 79
Σχήµα 6-25: Απεικόνιση επιλεγµένης νότας (αλλαγή χρώµατος)....................................... 82
Σχήµα 6-26: Αντιστοιχία νότας E της 1η γραµµής στην ταστιέρα της κιθάρας. ................. 86
Σχήµα 6-27: Αντιστοιχία νότας E της 1ης γραµµής στην εφαρµογή.................................... 86
Σχήµα 6-28: Το RGB της πρώτης χορδής. .......................................................................... 88
Σχήµα 6-29: Το RGB της δεύτερης χορδής......................................................................... 88
Σχήµα 6-30: Το RGB της τρίτης χορδής. ............................................................................ 89
Σχήµα 6-31: Το RGB της τέταρτης χορδής. ........................................................................ 89
Σχήµα 6-32: Το RGB της πέµπτης χορδής. ......................................................................... 89
Σχήµα 6-33: Το RGB της έκτης χορδής. ............................................................................. 90
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
4
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-34: Απεικόνιση 1ης χορδής ανοιχτής. .................................................................... 90
Σχήµα 6-35: Απεικόνιση 2ης χορδής ανοιχτής. .................................................................... 90
Σχήµα 6-36: Απεικόνιση 3ης χορδής ανοιχτής. .................................................................... 91
Σχήµα 6-37: Απεικόνιση 4ης χορδής ανοιχτής. .................................................................... 91
Σχήµα 6-38: Απεικόνιση 5ης χορδής ανοιχτής. .................................................................... 91
Σχήµα 6-39: Απεικόνιση 6ης χορδής ανοιχτής. .................................................................... 91
Σχήµα 6-40: Αντιστοιχία νότας Ε 4ου διαστήµατος στην εφαρµογή.................................. 93
Σχήµα 6-41: Αντιστοιχία νότας D στην εφαρµογή.............................................................. 94
Σχήµα 6-42: Αντιστοιχία νότας C - sharp στην εφαρµογή. ................................................. 95
Σχήµα 6-43: Λίστα µε tasks που υποστηρίζει το script. .................................................... 100
Σχήµα 6-44: Απεικόνιση εκτέλεσης εντολής ‘ant clean’................................................... 100
Σχήµα 6-45: Απεικόνιση εκτέλεσης εντολής ‘ant jar’. ...................................................... 101
Σχήµα 6-46: Μήνυµα λάθους της Java Console. ............................................................... 103
Σχήµα 6-47: Exception: diamouses.ui.scoreEditor.Main cannot be cast to
java.applet.Applet. .......................................................................................................... 104
Σχήµα 6-48: Στοιχεία που ακολουθούν το κλειδί ασφαλείας. ........................................... 105
Σχήµα 6-49: Αρχείο .keystore............................................................................................ 106
Σχήµα 6-50: Αρχείο scoreeditor.cer................................................................................... 106
Σχήµα 6-51: Μήνυµα στο χρήστη που αφορά τα δικαιώµατα του Applet. ....................... 108
Σχήµα 6-52: Παράθυρο ‘More Information’. .................................................................... 109
Σχήµα 6-53: Στοιχεία που συνοδεύουν το πιστοποιητικό ασφαλείας. .............................. 109
Σχήµα 6-54: Απεικόνιση Save Dialog για αποθήκευση παρτιτούρας. .............................. 110
Σχήµα 6-55: Περιβάλλον διαχείρισης Joomla. .................................................................. 111
Σχήµα 6-56: Template ιστοσελίδας. .................................................................................. 112
Σχήµα 6-57: Κεντρικό µενού της σελίδας. ........................................................................ 113
Σχήµα 6-58: Κεντρική σελίδα............................................................................................ 114
Σχήµα 6-59: Σελίδα ‘Είσοδος στην τάξη’.......................................................................... 115
Σχήµα 6-60: Πίνακας ελέγχου διαχειριστή φόρουµ. ......................................................... 116
Σχήµα 6-61: Σελίδα ‘Φόρουµ’. .......................................................................................... 117
Σχήµα 6-62: Φόρµα εγγραφής ........................................................................................... 117
Σχήµα 6-63: Σελίδα ‘Βοήθεια’. ......................................................................................... 119
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
5
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Πίνακες
Πίνακας 2-1: Παραπλήσια πακέτα λογισµικού στη µουσική τεχνολογία. ............................ 8
Πίνακας 2-2: Λίστα µουσικών οργάνων JFugue. ................................................................ 15
Πίνακας 3-1: ∆ιεθνής ονοµατολογία ακκόρντων. ............................................................... 39
Πίνακας 3-2: Είδη ακκόρντων. ............................................................................................ 39
Πίνακας 3-3: Σηµειογραφίες ακκόρντων............................................................................. 40
Πίνακας 6-1: Λίστα των tasks που υλοποιούνται στο αρχείο build.xml. ............................ 97
Πίνακας 6-2: ∆ικαιώµατα πρόσβασης στις ∆ηµόσιες Συζητήσεις. ................................... 118
Πίνακας 6-3: Επίπεδο πρόσβασης χρηστών στις σελίδες.................................................. 119
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
6
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
1. Εκφώνηση
Η πτυχιακή αυτή εργασία έχει σκοπό τη δηµιουργία µιας εφαρµογής σε Java όπου ο
χρήστης θα µπορεί να συνθέτει µουσική και να την αναπαράγει. Η εφαρµογή χωρίζεται σε
δυο µέρη.
Το πρώτο κοµµάτι αφορά την σύνθεση µουσικής σε παρτιτούρα, ώστε ο χρήστης να
εξοικιωθεί µε τους βασικούς κανόνες της µουσικής. Η εφαρµογή θα δίνει τη δυνατότητα
στο χρήστη να εισάγει νότες,παύσεις, καθώς και να καθορίζει το µουσικό όργανο µε το
οποίο επιθυµεί να συνθέσει. Επίσης θα µπορεί να αναπαράγει τη µουσική που σύνθεσε.
Το δεύτερο κοµµάτι αφόρα την οπτική αναπαράσταση του µουσικού οργάνου και την
οπτική απεικόνιση των νοτών σε αυτό. Ο χρήστης θα έχει την δυνατότητα να επιλέγει µια
νότα από την παρτιτούρα και να βλέπει τη θέση που έχει η συγκεκριµένη νότα στο
µουσικό όργανο. Αυτό έχει ως σκοπό την εύκολη κατανόηση και εκµάθηση της θεωρίας
της µουσικής και την αντιστοιχία µε το µουσικό όργανο.
Η πτυχιακή αυτή εργασία έχει υλοποιηθεί για µουσικά όργανα που ανήκουν στην
κατηγορία "κιθάρα".
Η διαδικασία ολοκλήρωσης της εργασίας αποτελείται από τα ακόλουθα βήµατα:
α) Αναζήτηση εργαλείων ανοιχτού κώδικα και µελέτη των δυνατοτήτων τους,
β) Μελέτη της υπάρχουσας εφαρµογής (score editor),
γ) Σχεδιασµός της νέας εφαρµογής
δ) Ανάπτυξη και υλοποίηση της εφαρµογής της πτυχιακής εργασίας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
7
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2. Παραπλήσιες εργασίες
Μετά από σχετική έρευνα και µελέτη αρκετών project στον παγκόσµιο ιστό, τα
περισσότερα εκ των οποίων ήταν τύπου ανοιχτού λογισµικού, θα παρουσιαστούν αυτά τα
οποία είναι πιο κοντά µε την πτυχιακή εργασία και µπορούν να µας βοηθήσουν για να
παραχθούν ιδέες οι οποίες θα αντιγραφούν και θα υλοποιηθούν στα πλαίσια της εργασίας
αυτής.
Σε γενικότερες γραµµές τα projects αυτά µπορούν να τοποθετηθούν σε δύο (2) κύριες
κατηγορίες. Η πρώτη κατηγορία αφορά βιβλιοθήκες σε Java που παρέχουν µηχανισµούς
για αναπαραγωγή ή σύνθεση µουσικής. Η κατηγορία αυτή θα ονοµάζεται για τη συνέχεια
της πτυχιακής ‘µουσικές βιβλιοθήκες’. H δεύτερη κατηγορία αφορά ολοκληρωµένες
εφαρµογές που έχουν γραφτεί από µουσικούς ή για µουσικούς για να βοηθήσουν τους
χρήστες τους στην εξάσκηση των µουσικών τους ικανοτήτων.
Από την πρώτη κατηγορία θα επιλεχθεί η κατάλληλη µουσική βιβλιοθήκη ώστε να
χρησιµοποιηθεί κατά την υλοποίηση της πτυχιακής αυτής εργασίας. Από τη δεύτερη
κατηγορία θα παρουσιαστούν οι πιο ευφυής ιδέες και οι πιο λειτουργικές υλοποιήσεις
διεπαφών των εφαρµογών µε τον χρήστη.
Τα πακέτα λογισµικού που πληρούν τις παραπάνω προϋποθέσεις, και επιλέχθηκαν µέσα
από λίστες βιβλιοθηκών και πακέτων λογισµικού [13] παρουσιάζονται στον Πίνακα 2-1.
Όνοµα
ABC4J [2]
Impro-Visor [6]
JFugue [7]
Java MIDI Kit [8]
jMusic [9]
jFrets [10]
∆υνατότητες
Κάνει parse παίζει και προβάλει παρτιτούρες
κάνοντας χρήση της ABC notation [3].
Εφαρµογή για συνθέτες µουσικής jazz.
Βιβλιοθήκη για αναπαράσταση µουσικής µε
χαρακτήρες, και αναπαραγωγής ήχων.
Βιβλιοθήκη για εφαρµογές MIDI
Βιβλιοθήκη
Εφαρµογή για εκµάθηση κιθάρας
Licence
GNU GPL v2
GPL
Open Source
GNU GPL
GNU GPL
GNU GPL v2
Πίνακας 2-1: Παραπλήσια πακέτα λογισµικού στη µουσική τεχνολογία.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
8
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2.1 ABC4J
Από το ABC4J µπορούµε να λάβουµε ενδιαφέροντα διδάγµατα µιας και το ABC notation
έχει απλοποιήσει τα πράγµατα πάρα πολύ. Στο Σχήµα 2-1 παρουσιάζεται παρτιτούρα µε
βάση το ABC4J.
Σχήµα 2-1: Παρτιτούρα µε βάση το ABC4J.
Ας δούµε τα βήµατα που απαιτούνται για την παραγωγή της παραπάνω παρτιτούρας. [4]
Το πρώτο βήµα είναι η δηµιουργία ενός αρχείου που θα περιέχει το κλειδί και τις νότες.
X:0
T:A simple scale exercise
K:D
CDEFGABcdefggfedcBAGFEDC
Με τη χρήση του παρακάτω κώδικα µπορούµε να εµφανίσουµε την πρώτη µας
παρτιτούρα.
import javax.swing.JFrame;
import abc.notation.Tune;
import abc.parser.TuneParser;
import abc.ui.swing.JScoreComponent;
public static void main (String[] arg) {
String tuneAsString = "X:0\nT:A simple scale
exercise\nK:D\nCDEFGABcdefggfedcBAGFEDC\n";
Tune tune = new TuneParser().parse(tuneAsString);
JScoreComponent scoreUI =new JScoreComponent();
scoreUI.setTune(tune);
JFrame j = new JFrame();
j.add(scoreUI);
j.pack();
j.setVisible(true);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
9
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Στο Σχήµα 2-2 φαίνεται η παρτιτούρα που θα προκύψει αν τρέξουµε τον παραπάνω
κώδικα.
Σχήµα 2-2: Απεικόνιση παρτιτούρας ABC4J µε νότες και µουσικό κλειδί.
Είναι εύκολο να παρατηρηθεί ότι το abc notation δεν ξεχωρίζει τις νότες από µόνο του. Για
να βελτιώσουµε την παραπάνω παρτιτούρα πρέπει για αρχή να τοποθετηθούν µπάρες |
X:0
T:A simple scale exercise
K:D
CDEF|GABc|defg|gfed|cBAG|FEDC
Στο Σχήµα 2-3 φαίνεται η παρτιτούρα µετά την χρήση των µπαρών.
Σχήµα 2-3: Απεικόνιση παρτιτούρας ABC4J µετά την προσθήκη µπαρών.
Το επόµενο βήµα είναι να χρησιµοποιήσουµε το time signature M:4:4 και να
οµαδοποιήσουµε τις νότες ανά δύο. Το τελευταίο το επιτυγχάνουµε αφήνοντας κενά
ανάµεσα στις νότες. Στο Σχήµα 2-4 απεικονίζεται η παρτιτούρα µετά την προσθήκη του
µέτρου και την οµαδοποίηση.
X:0
T:A simple scale exercise
M:4/4
K:D
CD EF|GA Bc|de fg|gf ed|cB AG|FE DC
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
10
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 2-4: Απεικόνιση παρτιτούρας ABC4J µετά την προσθήκη του µέτρου.
Το µόνο που µένει για να επιτευχθεί το επιθυµητό αποτέλεσµα είναι η εισαγωγή tie και
slurs. Αυτό επιτυγχάνετε µε χρήση κατάλληλων παρενθέσεων που εξηγούν από ποια νότα
να ανοίγει ένα slur και σε ποια να κλείνει. Να σηµειωθεί ότι για γειτονικές νότες η χρήση
µιας απλής παύλας αρκεί. Έτσι χρησιµοποιώντας το παρακάτω abc notation πετυχαίνουµε
το οπτικό αποτέλεσµα που φαίνεται στο Σχήµα 2-5 και επιθυµούσαµε εξ αρχής.
X:0
T:A simple scale exercise
M:4/4
K:D
(CD EF|G)A Bc|de fg-|gf ed|cB A(G|FE DC)
Σχήµα 2-5: Απεικόνιση παρτιτούρας ABC4J µετά την εισαγωγή tie και slurs.
Η βιβλιοθήκη abc4j παρέχει πολλές περισσότερες δυνατότητες από αυτές που ειπώθηκαν
µέχρι τώρα. Πρώτον µπορεί να δηµιουργήσει παρτιτούρες µε χρήση Java αντικειµένων
π.χ.:
Note note_d = new Note(Note.D);
Η παραπάνω δυνατότητα δεν θεωρείται κάτι το αξιοσηµείωτο και δε θα γίνει επέκταση της
τεχνοτροπίας στην πτυχιακή εργασία. Μια πολύ ενδιαφέρον δυνατότητα της abc4j είναι η
διαχείριση παρτιτούρων.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
11
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 2-6: Παρτιτούρα ABC4J χωρίς στοίχιση.
Η παρτιτούρα που παρουσιάζεται στο Σχήµα 2-6 θα µπορούσε να θεωρηθεί άψογη
(οπτικά) από πολλές απόψεις. Όµως υπάρχει χώρος για βελτίωση της παρουσίασής της.
Και συγκεκριµένα όσον αφορά στο justification. ∆ηλαδή στο να ξεκινάει η κάθε γραµµή
της παρτιτούρας και να τελειώνει στο ίδιο σηµείο. Αυτό που στα ελληνικά ονοµάζουµε
‘Πλήρη στοίχιση’. Αυτό µπορεί να επιτευχθεί µε τη βιβλιοθήκη abc4j µε τον παρακάτω
κώδικα:
JScoreComponent jscore = new JScoreComponent();
jscore.setJustification(true);
jscore.setTune(tune);
Μετά την προσθήκη του παραπάνω κώδικα έχουµε το οπτικό αποτέλεσµα στο Σχήµα 2-7
που είναι πραγµατικά άψογο.
Σχήµα 2-7: Παρτιτούρα ABC4J µε πλήρη στοίχιση.
Τέλος αξίζει να αναφερθεί ότι η abc4j διαθέτει δυνατότητες για αναπαραγωγή των
παρτιτούρων αλλά και για µετατροπή τους σε αρχεία MIDI [5].
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
12
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2.2 Impro-Visor
Η εφαρµογή Impro-Visor (βλέπε Σχήµα 2-8) είναι µια αξιέπαινη προσπάθεια που
συντελείται εδώ και µερικά χρόνια στο κολλέγιο Harvey Mudd από καθηγητή και οµάδα
φοιτητών που έχει καταπλήξει τον κόσµο της µουσικής τεχνολογίας και της Java. Η οµάδα
αυτή έχει δηµιουργήσει λογισµικό ανοιχτού κώδικα σχεδιασµένο για να βοηθάει
µουσικούς jazz να συνθέτουν και να ακούν solo. Στηρίζεται στη θεωρία ότι τα ρυθµικά
κοµµάτια (π.χ. πιάνο, µπάσο, drums) που συνοδεύουν τη µουσική jazz µπορούν να
δηµιουργηθούν αυτόµατα από chords.
Σχήµα 2-8: ∆ιεπαφή της εφαρµογής Impro-Visor.
Το πλήθος των δυνατοτήτων του προγράµµατος αυτό είναι τεράστιο και πιθανώς καλύπτει
τις ανάγκες και του πιο απαιτητικού συνθέτη. ∆ιαθέτει δυνατότητες για αρµονίες για
διαφοροποιηµένα pitches, για loops, drag and drop functionality για µεταφορά στοιχείων,
αλλαγή κλειδιού και πολλά άλλα.
Ένα από τα πιο ενδιαφέροντα tricks του λογισµικού αυτού είναι η χρήση slots. Με τρόπο
παρόµοιο µε το Macromedia Flash, η παρτιτούρα αποτελείται από έναν αριθµό από άδεια
slots µέσα στα οποία ο χρήστης µπορεί να τοποθετήσει µουσικά σύµβολα (νότες, παύσεις
κτλ).
Τέλος τονίζεται ότι χρησιµοποιεί τη βιβλιοθήκη JMusic που θα αναφερθεί στη συνέχεια.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
13
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2.3 JFugue
Το JFugue είναι ένα API (Application Programming Interface) που µπορεί να
χρησιµοποιηθεί για πολλαπλές χρήσεις: εµφάνιση παρτιτούρας, αναπαραγωγή και
ηχογράφηση σε MIDI, χρήση πολλαπλών οργάνων και χρησιµοποιεί δική του υλοποίηση
από MusicStrings.
Γενικά, αποτελεί µια ολοκληρωµένη πλατφόρµα που µπορεί να δώσει λύσεις ακόµα και
στις πιο απαιτητικές εργασίες. Το βάθος στο οποίο έχει µελετηθεί η µουσική τεχνολογία
και λογική είναι αξιοσηµείωτο, καθώς παρέχει δυνατότητες για ταυτόχρονη χρήση
πολλαπλών οργάνων.
Χρησιµοποιεί δική της υλοποίηση από MusicStrings, ένα notation παρόµοιο µε το ABC
notation. Το ξεπερνάει όµως από πολλές απόψεις. Άλλωστε το abc notation δηµιουργήθηκε
το 1991 µε σκοπό τη διάδοση µελωδιών και ρυθµών που «έγραψαν ιστορία» µε όσο το
δυνατόν πιο απλό τρόπο. Ναι µεν στηρίζεται το abc σε κανονικοποιηµένες οντότητες που
γίνονται parsed και validate από BNF συντακτικούς κανόνες [11], αλλά δεν υποστηρίζει
πολλαπλά voices, καθώς και ορισµό µουσικών οργάνων. Βέβαια έχουν δηµιουργηθεί
extensions του ABC notation που υλοποιούν τις παραπάνω δυνατότητες.
Συµπερασµατικά το notation του JFugue είναι σαφώς ανώτερο και καλύπτει τεράστια
γκάµα δυνατοτήτων. Στον Πίνακα 2-2 παρουσιάζεται η χαρακτηριστική λίστα από
µουσικά όργανα που υποστηρίζει.
Piano
0 PIANO or
ACOUSTIC_GRAND
1 BRIGHT_ACOUSTIC
2 ELECTRIC_GRAND
3 HONKEY_TONK
4 ELECTRIC_PIANO or
ELECTRIC_PIANO1
5 ELECTRIC_PIANO2
6 HARPISCHORD
7 CLAVINET
Guitar
24 GUITAR or
NYLON_STRING_GUITAR
25 STEEL_STRING_GUITAR
26 ELECTRIC_JAZZ_GUITAR
27 ELECTRIC_CLEAN_GUITAR
28 ELECTRIC_MUTED_GUITAR
29 OVERDRIVEN_GUITAR
30 DISTORTION_GUITAR
31 GUITAR_HARMONICS
Chromatic Percussion
8 CELESTA
9 GLOCKENSPIEL
10 MUSIC_BOX
11 VIBRAPHONE
12 MARIMBA
13 XYLOPHONE
14 TUBULAR_BELLS
15 DULCIMER
Organ
16 DRAWBAR_ORGAN
17 PERCUSSIVE_ORGAN
18 ROCK_ORGAN
19 CHURCH_ORGAN
20 REED_ORGAN
21 ACCORIDAN
22 HARMONICA
23 TANGO_ACCORDIAN
Bass
32 ACOUSTIC_BASS
33
ELECTRIC_BASS_FINGER
34 ELECTRIC_BASS_PICK
35 FRETLESS_BASS
36 SLAP_BASS_1
37 SLAP_BASS_2
38 SYNTH_BASS_1
39 SYNTH_BASS_2
Strings
40 VIOLIN
41 VIOLA
42 CELLO
43 CONTRABASS
44 TREMOLO_STRINGS
45 PIZZICATO_STRINGS
46 ORCHESTRAL_STRINGS
47 TIMPANI
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
14
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Ensemble
48 STRING_ENSEMBLE_1
49 STRING_ENSEMBLE_2
50 SYNTH_STRINGS_1
51 SYNTH_STRINGS_2
52 CHOIR_AAHS
53 VOICE_OOHS
54 SYNTH_VOICE
55 ORCHESTRA_HIT
Brass
56 TRUMPET
57 TROMBONE
58 TUBA
59 MUTED_TRUMPET
60 FRENCH_HORN
61 BRASS_SECTION
62 SYNTHBRASS_1
63 SYNTHBRASS_2
Reed
64 SOPRANO_SAX
65 ALTO_SAX
66 TENOR_SAX
67 BARITONE_SAX
68 OBOE
69 ENGLISH_HORN
70 BASSOON
71 CLARINET
Pipe
72 PICCOLO
73 FLUTE
74 RECORDER
75 PAN_FLUTE
76 BLOWN_BOTTLE
77 SKAKUHACHI
78 WHISTLE
79 OCARINA
Synth Lead
80 LEAD_SQUARE or
SQUARE
81 LEAD_SAWTOOTH or
SAWTOOTH
82 LEAD_CALLIOPE or
CALLIOPE
83 LEAD_CHIFF or CHIFF
84 LEAD_CHARANG or
CHARANG
85 LEAD_VOICE or VOICE
86 LEAD_FIFTHS or FIFTHS
87 LEAD_BASSLEAD or
BASSLEAD
Ethnic
104 SITAR
105 BANJO
106 SHAMISEN
107 KOTO
108 KALIMBA
109 BAGPIPE
110 FIDDLE
111 SHANAI
Synth Pad
88 PAD_NEW_AGE or
NEW_AGE
89 PAD_WARM or WARM
90 PAD_POLYSYNTH or
POLYSYNTH
91 PAD_CHOIR or CHOIR
92 PAD_BOWED or BOWED
93 PAD_METALLIC or
METALLIC
94 PAD_HALO or HALO
95 PAD_SWEEP or SWEEP
Synth Effects
96 FX_RAIN OR RAIN
97 FX_SOUNDTRACK or
SOUNDTRACK
98 FX_CRYSTAL or
CRYSTAL
99 FX_ATMOSPHERE or
ATMOSPHERE
100 FX_BRIGHTNESS or
BRIGHTNESS
101 FX_GOBLINS or
GOBLINS
102 FX_ECHOES
Percussive
112 TINKLE_BELL
113 AGOGO
114 STEEL_DRUMS
115 WOODBLOCK
116 TAIKO_DRUM
117 MELODIC_TOM
118 SYNTH_DRUM
119 REVERSE_CYMBAL
Πίνακας 2-2: Λίστα µουσικών οργάνων JFugue.
Η παραπάνω λίστα οργάνων έχει βρεθεί στο βιβλίο «The complete Guide to JFugue» [12].
Επίσης να τονιστεί ότι για κάθε µουσικό όργανο υπάρχει κατάλληλο notation για κάθε
δυνατότητα του οργάνου. Για παράδειγµα στα drums µπορεί ο χρήστης να καθορίσει µέχρι
και την ένταση µε την οποία πατιέται το Foot Pedal:
X[Foot_Pedal]=1345
Εν τέλει η βιβλιοθήκη JFugue παρέχει όλες τις δυνατότητες, αλλά και πολλές παραπάνω
από αυτές που παρέχει το abc4j σε όλους τους τοµείς και αποτελεί σηµείο εκκίνησης για
οποιαδήποτε project µουσικής τεχνολογίας που χρειάζεται να υλοποιηθεί σε Java.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
15
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2.4 JMusic
Η βιβλιοθήκη της JMusic παρέχει µια σειρά από εργαλεία χρήσιµα τόσο σε συνθέτες
µουσικής όσο και σε προγραµµατιστές που επιθυµούν να αναπτύξουν εφαρµογές που
στηρίζονται στη µουσική τεχνολογία στη Java. Επίσης παρέχει ένα ολόκληρο framework
για υποβοηθούµενη σύνθεση µουσικής από υπολογιστή, για σύνθεση µουσικών οργάνων
και ανάλυση µουσικής.
Παρέχει µεθόδους για οργάνωση, µετάλλαξη και ανάλυση µουσικών δεδοµένων. Οι
παρτιτούρες της JMusic µπορούν να γίνουν render σε MIDI αρχεία, αλλά και σε άλλα
format µουσικών αρχείων για αποθήκευση και αναπαραγωγή. Μπορεί επίσης να
αποθηκεύσει XML αρχεία ή ακόµα και .jm αρχεία και υποστηρίζει real-time JavaSound
[14], QuickTime [15] και MidiShare [16] formats. Μάλιστα επειδή είναι γραµµένη εξ’
ολοκλήρου σε Java, µπορεί να χρησιµοποιηθεί σε οποιοδήποτε λειτουργικό σύστηµα.
Ο αριθµός των projects που στηρίζονται στη βιβλιοθήκη αυτή είναι τεράστιος. Πέρα από
το Impro-Visor που παρουσιάστηκε στο κεφάλαιο 2.2 έχει χρησιµοποιηθεί στα:
CodeSounding [17], Red Wine Music [18], JM-Etude [19] και σε πολλά άλλα. Αυτό
δείχνει ότι αποτελεί µια δοκιµασµένη υλοποίηση αρκετά ώριµη για να χρησιµοποιηθεί σε
πραγµατικές εφαρµογές.
Μετά από λεπτοµερή µελέτη των διαθέσιµων τεχνολογιών, η JMusic αποτελεί µια από τις
καλύτερες υποψήφιες τεχνολογίες για οποιαδήποτε εφαρµογή που χρησιµοποιεί Java
Sounds, και οι δυνατότητές της θα παρουσιαστούν αναλυτικότερα στη συνέχεια της
πτυχιακής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
16
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2.5 JFrets
To JFrets (βλέπε Σχήµα 2-9) είναι ένα πακέτο λογισµικού ανοιχτού κώδικα που
δηµιουργήθηκε από τον Matt Warman. Αποτελεί µια προσπάθεια για δηµιουργία ενός
εργαλείου που θα βοηθήσει τον χρήστη στην εκµάθηση κιθάρας.
Το πρόγραµµα αυτό µπορεί να βοηθήσει έναν αρχάριο χρήστη να εντοπίσει τις θέσεις στις
οποίες πρέπει να τοποθετήσει τα δάχτυλά του για να παίξει ένα chord. Μπορεί επίσης να
βοηθήσει έναν µουσικό να γράψει παρτιτούρες για τη µουσική που συνθέτει σε
ηλεκτρονική µορφή.
Σχήµα 2-9: ∆ιεπαφή της εφαρµογής JFrets.
Σε αυτή την εφαρµογή ο χρήστης µπορεί να κάνει interact µε το ποντίκι πάνω στην
ταστιέρα της κιθάρας. Αν πατήσει αριστερό κλικ σε ένα σηµείο στην ταστιέρα ακούγεται η
εκάστοτε νότα στην κιθάρα και εµφανίζεται ένας κύκλος µε το όνοµα της νότας που
ακούστηκε.
Το αξιόλογο σηµείο της συγκεκριµένης εφαρµογής είναι ο τρόπος µε τον οποίο
υλοποιήθηκε η ταστιέρα ώστε να αλληλεπιδρά µε το χρήστη. Αυτό που έγινε περιληπτικά
είναι να δηµιουργηθεί ένα πάνελ όπου µέσα φορτώνεται η εικόνα της ταστιέρας της
κιθάρας και πάνω από αυτή υλοποιήθηκε ένα JTable το οποίο έχει 6 γραµµές και 23
στήλες (όσα και τα διαστήµατα της ταστιέρας της κιθάρας) όπου κάθε κελί αντιστοιχεί
στην νότα της κιθάρας.
Το JTable είναι transparent και όταν ο χρήστης πατά πάνω σε ένα σηµείο στην ουσία
πατά σε ένα κελί του πίνακα. Επίσης γράφεται αυτόµατα και η ταµπλατούρα από κάτω.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
17
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Η εφαρµογή διαθέτει επιπλέον µετρονόµο όπως φαίνεται στο Σχήµα 2-10, για να βοηθήσει
στο «συντονισµό» του µουσικού σε ορισµένο µέτρο. Μετρονόµος είναι ένα µηχάνηµα που
κρατάει το µέτρο στο κοµµάτι που παίζει κανείς. Είναι απαραίτητο σε όλα τα µουσικά
όργανα και στην ουσία παράγει ήχο κάθε συγκεκριµένα δευτερόλεπτα που καθορίζει ο
χρήστης. Ο ήχος είναι σαν τους χτύπους του ρολογιού.
Σχήµα 2-10: Ο µετρονόµος του JFrets.
Επίσης διαθέτει δυνατότητες αναπαραγωγής και αποθήκευσης της µουσικής που συνθέτει
ο συνθέτης.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
18
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2.6 Οδηγίες λήψης κώδικα εφαρμογών
Για να αποκτήσει κανείς τον κώδικα των παραπάνω εφαρµογών θα πρέπει να κάνει χρήση
CVS [20], Subversion [21] repositories ή να τον κατεβάσει από αντίστοιχες σελίδες στο
Ίντερνετ. Το CVS και το Subversion αποτελούν concurrent version systems που δίνουν τη
δυνατότητα σε προγραµµατιστές να εργάζονται ταυτόχρονα στον κώδικα ενός project. Για
τη λήψη του κώδικα των εφαρµογών που παρουσιάστηκαν µέχρι τώρα, υπάρχει σε
ορισµένα projects η δυνατότητα απόκτησης του κώδικα µόνο µέσα από τα συστήµατα
αυτά.
Όσον αφορά τα repositories υπάρχουν αρκετά εργαλεία τα οποία µπορούν να
χρησιµοποιηθούν για τη λήψη του κώδικα. Αναγκαία προϋπόθεση είναι ο χρήστης να
ανοίξει λογαριασµό στο http://dev.java.net/
2.6.1 Λήψη κώδικα JFugue Music Notepad από NetBeans
Με τη χρήση του εργαλείου NetBeans [22] η διαδικασία είναι η ακόλουθη:
Επιλέγουµε από το µενού Versioning
CVS
Checkout..
Στο παράθυρο που εµφανίζεται τοποθετούµε τα στοιχεία του λογαριασµού και του project
που επιθυµούµε να κατεβάσουµε :pserver:[email protected]:/cvs και πατάµε
next.
Στο Σχήµα 2-11 εµφανίζεται το παράθυρο µετά την σωστή καταχώρηση των παραπάνω
στοιχείων.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
19
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 2-11: Παράθυρο Netbeans για το checkout του JFugue Music Notepad.
Γράφετε στο πεδίο module nbjfuguesupport και στη συνέχεια επιλέγετε την τοποθεσία που
θέλετε να αποθηκευτεί ο κώδικας στον υπολογιστή σας. Πατάτε finish περιµένετε µέχρι να
ολοκληρωθεί το checkout και στη συνέχεια τρέχετε τον κώδικα στον υπολογιστή σας.
2.6.2 Λήψη κώδικα JFrets από NetBeans
Με τη χρήση του εργαλείου NetBeans η διαδικασία είναι η ακόλουθη:
Επιλέγουµε από το µενού Versioning
Subversion
Checkout..
Στο παράθυρο που εµφανίζεται τοποθετούµε τα στοιχεία του λογαριασµού και του project
που επιθυµούµε να κατεβάσουµε https://jfrets.dev.java.net/svn/jfrets και πατάµε next.
Στο Σχήµα 2-12 παρουσιάζεται το παράθυρο µετά την σωστή καταχώρηση των παραπάνω
στοιχείων.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
20
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 2-12: Παράθυρο Netbeans για το checkout του JFrets.
Eπιλέγετε την τοποθεσία που θέλετε να αποθηκευτεί ο κώδικας στον υπολογιστή σας και
πατάτε finish. Όταν ολοκληρωθεί το checkout προσθέτετε στον κώδικα της εφαρµογής την
βιβλιοθήκη jdom και τρέχετε τον κώδικα.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
21
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
3. Μουσικοί κανόνες
Όπως κάθε γλώσσα έχει τα γράµµατα και τους κανόνες της, το ίδιο έχει και η µουσική µε
τη διαφορά ότι στη µουσική αντί για γράµµατα χρησιµοποιούµε επτά διαφορετικούς
µουσικούς ήχους (φωνές) µε τις πιο κάτω ονοµασίες :
Ελληνική γραφή:
ΝΤΟ-ΡΕ-ΜΙ-ΦΑ-ΣΟΛ-ΛΑ-ΣΙ
Λατινική γραφή:
C-D-E-F-G-A-B
Οι µουσικοί αυτοί ήχοι παράγονται από τα διάφορα µουσικά όργανα ή από τη φωνή του
ανθρώπου, όταν αυτός τραγουδάει και έχουν ένα ορισµένο ύψος. Τους ήχους αυτούς τους
ονοµάζουµε µουσικούς φθόγγους και γράφονται στο πεντάγραµµο µε ειδικά σχήµατα,
που εκφράζουν τη διάρκειά τους και λέγονται φθογγόσηµα ή ξενόγλωσσα, νότες (notes).
Υπάρχουν και άλλοι ήχοι που δεν έχουν ένα καθορισµένο ύψος, όπως οι θόρυβοι και οι
κρότοι.
Καταλήγουµε λοιπόν στο συµπέρασµα ότι:
α) Μουσικός φθόγγος είναι ο ήχος (φωνή) που έχει ένα καθορισµένο ύψος.
β) Θόρυβος - κρότος είναι ο ήχος που δεν έχει ένα καθορισµένο ύψος.
γ) Φθογγόσηµο ή νότα είναι το σχήµα µε το οποίο γράφουµε το µουσικό φθόγγο στο
πεντάγραµµο.
Πεντάγραμμο
Πεντάγραµµο είναι το σύνολο από 5 οριζόντιες και παράλληλες γραµµές που απέχουν η
µια από την άλλη το ίδιο (βλέπε Σχήµα 3-1).
Σχήµα 3-1: Μουσικό πεντάγραµµο.
Από τις πέντε γραµµές του πενταγράµµου σχηµατίζονται τέσσερα διαστήµατα, όπως
φαίνεται στο Σχήµα 3-2.
∆ιάστηµα λέγεται η απόσταση που χωρίζει τη µια γραµµή από την άλλη.
Σχήµα 3-2: ∆ιαστήµατα µουσικού πενταγράµµου.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
22
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Από πού εξαρτάται η ονομασία των φθόγγων
Η ονοµασία των φθόγγων εξαρτάται από τη θέση που είναι γραµµένοι στο πεντάγραµµο
και από το όνοµα και τη θέση του Κλειδιού.
Κλειδί (Γνώμονας)
Κλειδί της µουσικής ή γνώµονας είναι ένα σηµείο που γράφεται στην αρχή κάθε
πενταγράµµου και, ανάλογα µε τη θέση του, προσδιορίζει το ύψος και το όνοµα ενός
ορισµένου φθόγγου, και σύµφωνα µε αυτόν ονοµάζουµε και τους άλλους.
Τα Κλειδιά της µουσικής είναι τα εξής:
1. ∆ύο κλειδιά του ΣΟΛ (στη 2η και στην 1η γραµµή) τα οποία φαίνονται στο Σχήµα 3-3.
α) 2ης γραµµής
β)1ης γραµµής
Σχήµα 3-3: Κλειδιά του ΣΟΛ.
2. ∆ύο κλειδιά του ΦΑ (στην 4η και στην 3η γραµµή) που παρουσιάζονται στο Σχήµα 3-4.
α) 4ης γραµµής
β)3ης γραµµής
Σχήµα 3-4: Κλειδιά του ΦΑ.
3. Τέσσερα κλειδιά του ΝΤΟ(στην 1η, 2η, 3η και 4η γραµµή) που απεικονίζονται στο
Σχήµα 3-5.
α) 1ης γραµµής
β)2ης γραµµής
γ)3ης γραµµής
δ)4ης γραµµής
Σχήµα 3-5: Κλειδιά του ΝΤΟ.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
23
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Κλειδί του ΣΟΛ της 2ης γραμμής
Σχήµα 3-6: Κλειδί του ΣΟΛ της 2ης γραµµής.
Λέγεται της δεύτερης γραµµής γιατί στο γράψιµό του κάνει ένα τύλιγµα πάνω στη
δεύτερη γραµµή του πενταγράµµου, παριστάνοντας έτσι ένα φθογγόσηµο στρογγυλό πάνω
στη δεύτερη γραµµή (βλέπε Σχήµα 3-6).
Όλοι οι φθόγγοι
Στο Σχήµα 3-7 παρουσιάζονται όλοι οι φθόγγοι.
α) Κάτω από το πεντάγραµµο β) µέσα στο πεντάγραµµο γ) πάνω από το πεντάγραµµο
Σχήµα 3-7: Οι φθόγγοι του πενταγράµµου.
Οκτάβα (Ογδόη)
Η απόσταση ανάµεσα σε δύο φθόγγους που έχουν το ίδιο όνοµα και βρίσκονται σε δύο
γειτονικές σειρές λέγεται οκτάβα (ογδόη) γιατί η απόσταση αυτή περιλαµβάνει 8
φθόγγους, δηλαδή στο Σχήµα 3-8, η απόσταση από το ΝΤΟ της πρώτης σειράς µέχρι το
ΝΤΟ της δεύτερης σειράς λέγεται οκτάβα ή ογδόη κ.ο.κ.
Σχήµα 3-8: Οκτάβα ή ογδόη.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
24
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Κλίμακα (Σκάλα)
Κλίµακα λέγεται η διαδοχή 8 συνεχών φθόγγων που ανεβαίνουν και κατεβαίνουν. Στο
Σχήµα 3-9 παρουσιάζεται η κλίµακα του ΝΤΟ.
Σχήµα 3-9: Κλίµακα (σκάλα του ΝΤΟ).
Ηχητικές αποστάσεις στους φθόγγους της κλίμακας
Οι ηχητικές αποστάσεις σε δύο γειτονικούς φθόγγους της κλίµακας είναι µεγάλες και
µικρές. Οι µεγάλες λέγονται τόνοι και οι µικρές ηµιτόνια (βλέπε Σχήµα 3-10). Ηµιτόνιο
είναι η µισή φωνή, και τόνος η ολόκληρη φωνή. Ο τόνος έχει δύο ηµιτόνια δηλαδή 2 µισές
φωνές. Στην κλίµακα ΝΤΟ όλες οι αποστάσεις µεταξύ τους είναι µεγάλες (τόνοι), εκτός
από το ΜΙ - ΦΑ και το ΣΙ - ΝΤΟ που είναι µικρές (ηµιτόνια). Γι’ αυτό το λόγο όταν
τραγουδάµε την κλίµακα ανεβαίνοντας, στο ΜΙ - ΦΑ και στο ΣΙ - ΝΤΟ δεν υψώνουµε
πολύ τη φωνή µας γιατί οι αποστάσεις αυτές είναι µικρές (ηµιτόνια).
Το ίδιο γίνεται και στο κατέβασµα, που βρίσκουµε αυτούς τους φθόγγους ανάποδα, ΦΑ ΜΙ και ΝΤΟ - ΣΙ, και εδώ δεν χαµηλώνουµε πολύ τη φωνή µας.
Σχήµα 3-10: Τόνοι και ηµιτόνια.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
25
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Τις µικρές αποστάσεις τις βλέπουµε καλύτερα στο πιο πάνω παραστατικό σχήµα της
κλίµακας (σκάλας), όπου την παρουσιάζουµε σαν σκάλα σπιτιού. Αν προσέξουµε,
βλέπουµε ότι οι αποστάσεις από το ΜΙ ως το ΦΑ και από το ΣΙ ως το ΝΤΟ είναι
µικρότερες, γιατί τα σκαλοπάτια ΦΑ και ΝΤΟ είναι κατά το µισό χαµηλότερα από τα
άλλα.
Αξίες φθογγοσήμων
Παρατηρούµε ότι οι φθόγγοι που ανήκουν σε µία µουσική σύνθεση, όταν παίζονται από
διάφορα µουσικά όργανα ή τραγουδιούνται από ανθρώπινες φωνές, διαρκούν άλλοι
περισσότερο και άλλοι λιγότερο. Η διάρκειά τους αυτή - η αξία τους - είναι ανάλογη µε το
σχήµα µε το οποίο τα φθογγόσηµα είναι γραµµένα στο πεντάγραµµο.
Άρα καταλήγουµε στον εξής ορισµό:
Αξίες είναι οι διάρκειες των φθόγγων που παριστάνονται στο πεντάγραµµο µε
διάφορα σχήµατα φθογγοσήµων, και ανάλογα µε το σχήµα κάθε φθογγοσήµου
καθορίζεται η διάρκεια κάθε φθόγγου.
Στο Σχήµα 3-11 απεικονίζονται τα σχήµατα των φθογγοσήµων. Συνολικά είναι επτά.
Σχήµα 3-11: Σχήµατα φθογγοσήµων.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
26
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Διάρκεια φθογγοσήμων
Από τα φθογγόσηµα που αναφέραµε πιο πάνω, τη µεγαλύτερη διάρκεια την έχει το
ολόκληρο, µετά ακολουθεί το µισό, που έχει τη µισή διάρκεια από το ολόκληρο, µετά το
τέταρτο που έχει διάρκεια ίση µε το ένα τέταρτο του ολόκληρου κ.ο.κ. Έτσι φτάνουµε στη
µικρότερη διάρκεια, που είναι το εξηκοστό τέταρτο και έχει διάρκεια ίση µε το ένα
εξηκοστό τέταρτο του ολόκληρου.
Διαιρέσεις ολόκληρου και υποδιαιρέσεις αυτών
1. Ένα oλόκληρο µπορούµε να το διαιρέσουµε σε µισά, σε τέταρτα, σε όγδοα, σε δέκατα
έκτα, σε τριακοστά δεύτερα και σε εξηκοστά τέταρτα. Για να καταλάβουµε πιο καλά αυτές
τις διαιρέσεις, παροµοιάζουµε το ολόκληρο µε ένα στρογγυλό πορτοκάλι όπως φαίνεται
στο Σχήµα 3-12, π.χ.
Σχήµα 3-12: Ολόκληρο.
2. Αν τώρα το πορτοκάλι το κόψουµε στη µέση όπως µας δείχνει το πιο κάτω σχήµα, θα
έχουµε 2 κοµµάτια από το µισό πορτοκάλι. Άρα το ολόκληρο διαιρείται σε 2 µισά όπως
απεικονίζεται στο Σχήµα 3-13.
Σχήµα 3-13: ∆ιαίρεση ολόκληρου σε 2 µισά.
3. Αν το κόψουµε στα τέσσερα θα έχουµε 4 κοµµάτια και το κάθε κοµµάτι το λέµε
τέταρτο, όπως φαίνεται στο Σχήµα 3-14. Άρα το ολόκληρο διαιρείται σε 4 τέταρτα όπως
µας δείχνει το πιο κάτω σχήµα.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
27
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 3-14: ∆ιαίρεση ολόκληρου σε 4 τέταρτα.
4. Αν το κόψουµε στα οκτώ θα έχουµε 8 κοµµάτια όπως απεικονίζεται στο Σχήµα 3-15,
και το κάθε κοµµάτι το λέµε όγδοο. Άρα το ολόκληρο διαιρείται σε 8 όγδοα όπως µας
δείχνει το πιο κάτω σχήµα.
Σχήµα 3-15: ∆ιαίρεση ολόκληρου σε 8 όγδοα.
Το ανάλογο µπορεί να γίνει αν κόψουµε το πορτοκάλι σε 16, σε 32 και σε 64 κοµµάτια.
∆ηλαδή το ολόκληρο διαιρείται σε 16 δέκατα έκτα, ή σε 32 τριακοστά δεύτερα ή σε 64
εξηκοστά τέταρτα.
Πιο κάτω παρουσιάζουµε αναλυτικά µε τι ισούται η κάθε αξία φθογγοσήµου και την
κανονική τους γραφή στο πεντάγραµµο.
1. Με τι ισούται το ένα ολόκληρο
2
4
8
), ή µε 4 τέταρτα ( ), ή µε 8 όγδοα ( ), ή
2
4
8
16
32
δέκατα έκτα ( ), ή µε 32 τριακοστά δεύτερα ( ), ή µε 64 εξηκοστά τέταρτα
16
32
(βλέπε Σχήµα 3-16).
Το ολόκληρο ισούται µε τα 2 µισά (
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
µε 16
(
64
)
64
28
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 3-16: Ισοδυναµίες ολόκληρου.
ΣΗΜΕΙΩΣΗ: Τα όγδοα, τα δέκατα έκτα, τα τριακοστά δεύτερα και τα εξηκοστά τέταρτα,
για καλή οπτική ανάγνωση και για συντοµία στο γράψιµό τους, ενώνονται µεταξύ τους µε
γραµµές. Με µία γραµµή τα όγδοα, µε 2 τα δέκατα έκτα, µε 3 τα τριακοστά δεύτερα και µε
4 τα εξηκοστά τέταρτα, όπως τα βλέπουµε στο πιο πάνω σχήµα.
Έχουµε περιθώριο να ενώσουµε από δυο και πάνω.
2. Με τι ισούται το ένα μισό
2
4
8
), ή µε 4 όγδοα ( ), ή µε 8 δέκατα έκτα ( ), ή µε 16
4
8
16
16
32
τριακοστά δεύτερα ( ), ή µε 32 εξηκοστά τέταρτα (
) (βλέπε Σχήµα 3-17).
32
64
Το µισό ισούται µε 2 τέταρτα (
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
29
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 3-17: Ισοδυναµίες µισού.
3. Με τι ισούται το ένα τέταρτο
2
4
), ή µε 4 δέκατα έκτα ( ), ή µε 8 τριακοστά
8
16
8
16
δεύτερα ( ), ή µε 16 εξηκοστά τέταρτα (
)(βλέπε Σχήµα 3-18).
32
64
Το ένα τέταρτο ισούται µε 2 όγδοα (
Σχήµα 3-18: Ισοδυναµίες τετάρτου.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
30
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
4. Με τι ισούται το ένα όγδοο
Το ένα όγδοο ισούται µε 2 δέκατα έκτα (
εξηκοστά τέταρτα (
2
4
), ή µε 4 τριακοστά δεύτερα ( ), ή µε 8
16
32
8
)(βλέπε Σχήµα 3-19).
64
Σχήµα 3-19: Ισοδυναµίες ογδόου.
5. Με τι ισούται το ένα δέκατο έκτο
Το ένα δέκατο έκτο ισούται µε 2 τριακοστά δεύτερα (
2
4
), ή µε 4 εξηκοστά τέταρτα (
)
32
64
(βλέπε Σχήµα 3-20).
Σχήµα 3-20: Ισοδυναµίες δεκάτου έκτου.
6. Με τι ισούται το ένα τριακοστό δεύτερο
Το ένα τριακοστό δεύτερο ισούται µε 2 εξηκοστά τέταρτα (
2
) όπως φαίνεται στο Σχήµα
64
3-21.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
31
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 3-21: Ισοδυναµία τριακοστού δευτέρου.
Με τι ισούται η αξία του φθογγοσήμου
(από τη μεγαλύτερη στην αμέσως μικρότερη)
Από ότι είδαµε σε όλες τις διαιρέσεις αξιών, καταλήγουµε στο συµπέρασµα ότι η
µεγαλύτερη αξία ισούται µε δύο της αµέσως µικρότερης όπως απεικονίζεται στο Σχήµα
3.22.
Σχήµα 3-22: Ισοδυναµία αξίας κάθε φθογγοσήµου.
Γραφή φθογγοσήμων
Οι φθόγγοι, σε όποια θέση και αν γραφτούν στο πεντάγραµµο, µπορούν να πάρουν, για τον
καθορισµό της διάρκειάς τους, όλα τα σχήµατα των φθογγοσήµων.
Οι ουρές των σχηµάτων µισού, τετάρτου, ογδόου, δεκάτου έκτου, τριακοστού δεύτερου
και εξηκοστού τετάρτου, όπως απεικονίζεται στο Σχήµα 3-23. ∆ηλαδή:
Οι ουρές των φθογγοσήµων, που βρίσκονται από την τρίτη γραµµή του πενταγράµµου και
κάτω, γράφονται προς τα πάνω και δεξιά του φθογγοσήµου. Και στα φθογγόσηµα που
βρίσκοντα από την τρίτη γραµµή του πενταγράµµου και πάνω γράφονται προς τα κάτω κι
αριστερά του φθογγοσήµου, αρκεί να αποτελούν µονοφωνία.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
32
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 3-23: Γραφή φθογγοσήµων στο πεντάγραµµο.
Μουσικό μέτρο - Διαστολή
Κάθε µουσική σύνθεση που γράφεται στο πεντάγραµµο χωρίζεται κατά διαστήµατα µε
κάθετες γραµµές που λέγονται διαστολές. Η απόσταση, που χωρίζει τη µια διαστολή από
την άλλη, λέγεται µουσικό µέτρο· αλλά και η απόσταση από το κλειδί ως τη διαστολή
λέγεται και αυτή µέτρο. Το πρώτο, λοιπόν, µέτρο του πενταγράµµου γίνεται από µια
διαστολή.
Μουσικό µέτρο λέγεται η απόσταση µεταξύ δύο διαστολών, και διαστολή λέγεται η
κάθετη διαχωριστική γραµµή.
Όταν τελειώνει µία µουσική σύνθεση, στο τελευταίο της µέτρο η δεξιά διαστολή γράφεται
διπλή, όπως φαίνεται στο Σχήµα 3-24. Η δεύτερη γραµµή της διπλής διαστολής γράφεται
παχύτερη.
Σχήµα 3-24: Μουσικό µέτρο στο πεντάγραµµο.
ΣΗΜΕΙΩΣΗ: Η διπλή διαστολή µπορεί να γραφτεί και σε ένα ενδιάµεσο µέρος µιας
µουσικής σύνθεσης. Αυτό γίνεται για να χωρίσει το τέλος µιας µουσικής φράσης.
Αριθμός μέτρου
Στην αρχή κάθε µουσικής σύνθεσης, µετά το κλειδί και στα αριστερά του πρώτου µέτρου,
2 3 4
γράφεται ένας κλασµατικός αριθµός, π.χ. , , κ.λ.π.
4 4 4
Αυτός ο αριθµός δίνει: πρώτον, το όνοµα του µέτρου και, δεύτερον, το ίσο άθροισµα των
2
αξιών που θα έχει κάθε µέτρο. Αν π.χ. έχουµε στην αρχή µιας µουσικής σύνθεσης
λέµε
4
ότι η σύνθεση αυτή είναι γραµµένη σε µέτρο δύο τετάρτων και το κάθε µέτρο θα έχει
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
33
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2
3
, αν έχουµε
λέµε ότι η σύνθεση είναι γραµµένη σε µέτρο τριών
4
4
3
τετάρτων και το κάθε µέτρο θα έχει άθροισµα αξιών κ.ο.κ.
4
άθροισµα αξιών
Βλέπουµε λοιπόν ότι ο κλασµατικός αυτός αριθµός, επιβάλει να έχουν όλα τα µέτρα το
ίδιο άθροισµα αξιών σύµφωνα µε την δική του αξία.
1ο µέτρο
2ο µέτρο
3ο µέτρο
4ο µέτρο
Σχήµα 3-25: Μουσική σύνθεση σε µέτρο 2:4.
2
, και τα
4
µέτρα της έχουν διάφορες αξίες. Κάνουµε τώρα την επαλήθευση για να δούµε µήπως
υπάρχει κάποιο λάθος. Εξετάζουµε το 1ο µέτρο και βλέπουµε ότι έχει ένα µισό. Το µισό
2
έχει . Άρα είναι σωστό. Το 2ο µέτρο έχει δύο τέταρτα χωρισµένα, άρα είναι σωστό. Το
4
3ο µέτρο έχει 2 όγδοα και ένα τέταρτο. Τα δύο όγδοα δεν µας κάνουν ένα τέταρτο; Και ένα
2
τέταρτο χωριστά, άρα . Το 4ο µέτρο έχει 4 όγδοα. Τα δύο όγδοα µας κάνουν ένα
4
2
τέταρτο. Και ένα τέταρτο που µας κάνουν τα άλλα δύο όγδοα, γίνονται . Άρα και αυτό
4
το µέτρο είναι σωστό.
Όπως βλέπουµε στο Σχήµα 3-25, η µουσική σύνθεση είναι γραµµένη σε µέτρο
Παρεστιγμένα φθογγόσημα
Το φθογγόσηµο που έχει δεξιά του µια στιγµή ( ) λέγεται παρεστιγµένο. Η στιγµή αυτή
λέγεται στιγµή διαρκείας και αυξάνει τη διάρκεια του φθογγοσήµου κατά το µισό της
πραγµατικής του αξίας. Στο Σχήµα 3-27 απεικονίζονται οι ισοδυναµίες των παρεστιγµένων
φθογγοσήµων.
Αν π.χ. έχουµε ένα φθογγόσηµο σε µισό παρεστιγµένο ( ) και θέλουµε να µάθουµε πόσα
τέταρτα έχει, για να το βρούµε θα κάνουµε το εξής: Θα βρούµε πρώτα πόσα τέταρτα έχει η
πραγµατική του αξία και µετά θα προσθέσουµε από αυτό που θα βρούµε το µισό. Εδώ
2
λοιπόν το µισό έχει πραγµατική αξία
και ένα τέταρτο που µας αυξάνει η στιγµή (γιατί
4
2
1
3
3
το µισό είναι από τα το ) γίνεται . Άρα ένα µισό παρεστιγµένο έχει .
4
4
4
4
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
34
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Αν τώρα θέλουµε να µάθουµε ένα ολόκληρο παρεστιγµένο ( ) πόσα τέταρτα έχει θα
4
2
πούµε: Το ολόκληρο χωρίς στιγµή µας κάνει
και
που µας αυξάνει η στιγµή σύνολο
4
4
6
, όπως φαίνεται στο Σχήµα 3-26.
4
Σχήµα 3-26: Ισοδυναµία ολόκληρου παρεστιγµένου.
Σχήµα 3-27: Ισοδυναµίες παρεστιγµένων φθογγοσήµων.
Παύσεις
Παύσεις ονοµάζουµε τα σηµεία εκείνα που µας δείχνουν τον ανάλογο χρόνο διακοπής
(σιωπής), στην πορεία ενός µουσικού κοµµατιού. Όσα σχήµατα έχουµε για τις διάρκειες
των φθογγοσήµων άλλα τόσα έχουµε και για τις διάρκειες των παύσεων. Η διαφορά είναι
ότι τα σχήµατα των παύσεων µας καθορίζουν διάρκεια διακοπής χωρίς ήχο, ενώ τα
σχήµατα των φθογγοσήµων µας καθορίζουν διάρκεια µε ήχο.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
35
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Κάθε διάρκεια φθογγοσήµου έχει και την αντίστοιχη παύση της. Στο Σχήµα 3-28
παρουσιάζονται αναλυτικά τα σχήµατα των παύσεων µαζί µε τα σχήµατα διαρκείας των
φθογγοσήµων.
Σχήµα 3-28: Πίνακας σχηµάτων φθογγοσήµων και παύσεων.
Η παύση ολόκληρου και η παύση µισού κατά το σχήµα είναι ίδιες µε τη διαφορά ότι η
παύση του ολόκληρου γράφεται κάτω ακριβώς από την τέταρτη γραµµή του
πενταγράµµου, ενώ του µισού πάνω ακριβώς από την τρίτη γραµµή µε µια παύλα.
Οι άλλες παύσεις δεν έχουν ορισµένη θέση για το γράψιµό τους στο πεντάγραµµο.
Ανάλογα µε τη θέση που έχουν τα φθογγόσηµα πριν ή µετά την παύση, γράφεται και η
παύση στο ανάλογο ύψος του πενταγράµµου.
Όπως κάθε αξία φθογγοσήµου υποδιαιρείται σε 2 ή και περισσότερες αξίες, το ίδιο γίνεται
και µε τις αξίες των παύσεων.
Π.χ. µια παύση ολόκληρου είναι ίση µε 2 παύσεις µισού ή µε 4 παύσεις τετάρτου ή µε 8
παύσεις ογδόου ή µε 16 παύσεις δεκάτου έκτου κ.ο.κ.
Οι παύσεις επίσης µπορούν να γραφούν παρεστιγµένες και δις παρεστιγµένες όπως και τα
φθογγόσηµα όπως στο Σχήµα 3-29.
Σχήµα 3-29: Παρεστιγµένες και δις παρεστιγµένες παύσεις.
Σημεία αλλοίωσης
Σηµεία αλλοίωσης λέγονται τα σηµεία αυτά που γράφονται αριστερά των φθόγγων και
µεταβάλλουν (αλλοιώνουν) το ύψος τους. Τα σηµεία αυτά είναι απλά και διπλά.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
36
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Απλά σημεία αλλοίωσης
Τα απλά σηµεία αλλοίωσης ανεβάζουν ή κατεβάζουν το ύψος των φθόγγων κατά ένα
ηµιτόνιο (µισή φωνή) και είναι:
α) η δίεση (#) που ανεβάζει το φθόγγο ένα ηµιτόνιο,
β) η ύφεση ή µπεµόλ
που κατεβάσει το φθόγγο ένα ηµιτόνιο και
γ) η αναίρεση που επαναφέρει ένα αλλοιωµένο φθόγγο στο φυσικό του ύψος.
Διπλά σημεία αλλοίωσης
Τα διπλά σηµεία αλλοίωσης ανεβάζουν ή κατεβάζουν το ύψος των φθόγγων κατά δύο
ηµιτόνια, δηλαδή ένα τόνο και είναι:
α) η διπλή δίεση ( ) που ανεβάζει το φθόγγο κατά δύο ηµιτόνια (ένα τόνο),
β) η διπλή ύφεση
που κατεβάζει το φθόγγο κατά δύο ηµιτόνια (ένα τόνο) και
που επαναφέρει ένα αλλοιωµένο φθόγγο µε διπλή δίεση ή διπλή
γ) η διπλή αναίρεση
ύφεση, στο φυσικό του ύψος.
(Η διπλή αναίρεση σπάνια χρησιµοποιείται).
Για να ονοµάσουµε ένα φθόγγο µε δίεση, µε ύφεση ή αναίρεση πρέπει το σηµείο
αλλοίωσης να βρίσκεται στα αριστερά του φθόγγου, όπως απεικονίζεται στο Σχήµα 3-30.
Σχήµα 3-30: Απεικόνιση φθογγοσήµου ΝΤΟ δίεση στο πεντάγραµµο.
Η δίεση ανήκει στο δεύτερο ΝΤΟ. Για να προφέρουµε τώρα αυτούς τους φθόγγους θα
πούµε: ΝΤΟ, ΝΤΟ#. Όπως βλέπουµε για να πούµε το φθόγγο µε τη δίεση, λέµε πρώτα το
φθόγγο και µετά τη δίεση και ας είναι γραµµένη πρώτα η δίεση, δηλαδή δε λέµε ποτέ δίεση
ΝΤΟ αλλά ΝΤΟ δίεση. Το ίδιο γίνεται και για την ύφεση, την αναίρεση καθώς και για τα
διπλά σηµεία αλλοίωσης.
Αντιστοιχία φθογγοσήμων στην ταστιέρα της κιθάρας
Στο Σχήµα 3-31 παρουσιάζεται η αντιστοιχία των φθογγοσήµων (νοτών) του
πενταγράµµου στις θέσεις της ταστιέρας (µπράτσου) της κιθάρας. Συγκεκριµένα
απεικονίζεται η οπτική αναπαράσταση της ταστιέρας της κιθάρας µε τις χορδές, τα τάστα
και τα φθογγόσηµα που αντιστοιχούν σε κάθε τάστο της χορδής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
37
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 3-31: Αντιστοιχία φθογγοσήµων στην ταστιέρα της κιθάρας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
38
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Τρόπος ανάγνωσης του Chord - Lexicon
Ονοµατολογία: Το αρχικό λατινικό στοιχείο ενός ακκόρντου αντιπροσωπεύει την
ονοµατολογία του, όπως απεικονίζεται στον Πίνακα 3-1.
Α
Β
C
D
:
:
:
:
Λα
Σι
Ντο
Ρε
E : Μι
F : Φα
G : Σολ
Πίνακας 3-1: ∆ιεθνής ονοµατολογία ακκόρντων.
Τα στοιχεία που παραθέτονται στον Πίνακα 3-2 αντιπροσωπεύουν το είδος του:
A
Am
A maj7
Am maj 7
A7
Αm 7
Α6
Αm 6
Α9
Αm 9
Α6
: Λα (µατζόρε) (όταν η ονοµατολογία του ακκόρντου δεν συνοδεύεται από
άλλη ένδειξη εννοείται ότι το ακκόρντο είναι µατζόρε).
: Λα µινόρε (minor).
: Λα µατζόρε µεγάλης εβδόµης (major 7).
: Λα µινόρε µεγάλης εβδόµης.
: Λα (µατζόρε) εβδόµης (µικρής).
: Λα µινόρε εβδόµης.
: Λα (µατζόρε) έκτης.
: Λα µινόρε έκτης.
: Λα (µατζόρε) ενάτης.
: Λα µινόρε ενάτης.
: Λα (µατζόρε) έκτης - ενάτης.
9
Α 11
Α 13
Α+
Α +7
Α 7
Α° 7
A#9
Α sus4
Α 7sus4
:
:
:
:
:
:
:
:
:
Λα (µατζόρε) ενδεκάτης.
Λα (µατζόρε) δεκάτης τρίτης.
Λα αυξηµένη.
Λα αυξηµένη µε εβδόµη.
Λα ελαττωµένη µε εβδόµη.
Λα ελαττωµένη µε εβδόµη ελαττωµένη (diminuita).
Λα (µατζόρε) µε µεγάλη ενάτη.
Λα (µατζόρε) µε τετάρτη (suspended 4th - πρόσθετη 4η).
Λα (µατζόρε) εβδόµης µε τετάρτη.
Πίνακας 3-2: Είδη ακκόρντων.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
39
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Τα ακκόρντα που δίνονται στο CHORD – LEXICON µπορεί σε κάποιες εκδόσεις να τα
συναντήσετε µε διαφορετική σηµειογραφία, για το λόγο αυτό παραθέτουµε στον Πίνακα 33 τις γνωστότερες αντιστοιχίες.
A maj 7
Α 7
Α° 7
Α +7
A9
ΑM 7
Αm 7 (b5)
Α°
Α 7+
A add9
Α6
A 6 (add9)
A#7
Am 7(-5)
A dim
A 7 (#5)
A 7 (add9)
A dim
A 7(+5)
9
Am
A+
Ab5
A 7 (add11)
A aug
A (dim5)
A #5
A (-5)
A +5
Πίνακας 3-3: Σηµειογραφίες ακκόρντων.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
40
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
4. Προδιαγραφές πτυχιακής εργασίας
Η πτυχιακή αυτή εργασία έχει ως στόχο την δηµιουργία µιας ηλεκτρονικής µουσικής
κοινότητας για την εκµάθηση κιθάρας. Έχοντας ως γνώµονα την εύκολη και γρήγορη
εκµάθηση της κιθάρας ακόµα και από έναν αρχάριο µαθητή, καταλήξαµε στη δηµιουργία
µιας διεπάφης που θα παρέχει στο χρήστη οπτική απεικόνιση των νοτών που υπάρχουν στο
πεντάγραµο στην ταστιέρα της κιθάρας. Με αυτό τον τρόπο πετύχαµε την γρήγορη
εξοικείωση του µαθητή µε τις νότες του πενταγράµµου και την αντιστοιχία τους στην
κιθάρα.
Συγκεκριµένα ο score editor όπως µας δόθηκε παρείχε την εξής λειτουργικότητα στο
χρήστη:
1. Σύνθεση σε µουσικό πεντάγραµµο
2. Επιλογή µουσικού οργάνου από τη λίστα µουσικών οργάνων που παρέχει η
βιβλιοθήκη JMusic
3. Εναλλαγή παρτιτούρας
4. Επιλογή νότας/ων από το πεντάγραµο( multiple selection) µε κόκκινη ένδειξη της
επιλογής στο πάνω µέρος της παρτιτούρας
5. Προσθήκη / ∆ιαγραφή / Μετακίνηση νότας στην παρτιτούρα
6. Καθαρισµό παρτιτούρας
7. Αναπαραγωγή παρτιτούρας
Αν και ο score editor φαίνεται να καλύπτει ένα ευρύ φάσµα λειτουργιών, στην πράξη
υπήρχαν αδυναµίες. Όταν τρέξαµε την εφαρµογή για πρώτη φορά διαπιστώσαµε ότι είχε
bugs. Επίσης, ο σχεδιασµός και η επιλογή των components που συνθέτουν την διεπαφή του
score editor που παρουσιάζεται στο Σχήµα 4-1, δεν ήταν ο καλύτερος για την
λειτουργικότητα που παρείχε η εφαρµογή.
Σχήµα 4-1: ∆ιεπαφή αρχικού score editor.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
41
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Μετά από λεπτοµερή µελέτη του κώδικα που µας δόθηκε, αποφασίσαµε να διορθώσουµε
τις αδυναµίες που υπήρχαν, και να βελτιώσουµε τον κώδικα της εφαρµογής ώστε να
παρέχει την ίδια λειτουργικότητα, µειώνοντας παράλληλα τις γραµµές του κώδικα.
Έτσι µετά την ολοκλήρωση της πτυχιακής αυτής εργασίας η εφαρµογή που θα έχει
υλοποιηθεί θα δίνει στο χρήστη τις εξής δυνατότητες:
1. Σύνθεση σε µουσικό πεντάγραµµο
2. Επιλογή µουσικού οργάνου από λίστα µουσικών οργάνων που ανήκουν στην
κατηγορία «κιθάρα»
3. Εστίαση στο πάνω και το κάτω µέρος της παρτιτούρας µε εκάστοτε επιλογή από το
χρήστη (εναλλαγή παρτιτούρας σε Treble / Bass)
4. Επιλογή νότας από το πεντάγραµο µε ταυτόχρονη αλλαγή του χρώµατος της
επιλεγµένης νότας (κόκκινο) και εµφάνιση των θέσεων της νότας στην ταστιέρα της
κιθάρας
5. Προσθήκη / ∆ιαγραφή / Μετακίνηση νότας στην παρτιτούρα
6. Χρήση µετρονόµου
7. Καθαρισµό παρτιτούρας
8. Αναπαραγωγή παρτιτούρας
9. Αποθήκευση παρτιτούρας
Η διεπαφή της εφαρµογής θα περιέχει µενού File όπου µέσα θα υπάρχει ‘Clear Stave’,
‘Save Stave’, ‘Play Stave’ και ‘Exit’. Θα σχεδιαστεί µενού Τοοls όπου µέσα σε αυτό θα
τοποθετηθούν εργαλεία όπως ο Μετρονόµος καθώς και µενού Help.
Μόλις τρέχει η εφαρµογή θα δηµιουργείται ένα κεντρικό Panel που θα αποτελείται από
δύο Panels.Το πάνω θα είναι ο editor (η παρτιτούρα) και από κάτω θα είναι το Panel µε την
ταστιέρα της κιθάρας.
Τέλος, η εφαρµογή θα ενσωµατωθεί σε ιστοσελίδα που θα καλύπτει τις ανάγκες µιας
ηλεκτρονικής κοινότητας που αφορά την εκµάθηση κιθάρας. Συγκεκριµένα θα παρέχει τις
εξής δυνατότητες στο χρήστη:
•
•
•
•
•
Εγγραφή στην σελίδα
Ηλεκτρονική τάξη όπου ο χρήστης θα πειραµατίζεται µε την εφαρµογή
Λήψη αρχείων θεωρίας και ασκήσεων που έχει ανεβάσει ο καθηγητής
Φόρουµ, για συζήτηση µε µαθητές και καθηγητές
Βοήθεια µε οδηγίες χρήσης της εφαρµογής
Η ιστοσελίδα θα σχεδιαστεί ώστε µόνο οι εγγεγραµένοι χρήστες (µαθητές ή καθηγητές) να
έχουν πρόσβαση σε όλες τις ενότητες της ιστοσελίδας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
42
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
5. Ανάλυση του κώδικα score-editor
Ο score editor που µας δόθηκε αποτελείται από εννιά αρχεία Java, ένα φάκελο που περιέχει
τις εικόνες της εφαρµογής, δύο αρχεία τύπου form και τη βιβλιοθήκη JMusic.jar που
βρίσκεται στο φάκελο Libraries. Στο Σχήµα 5-1 παρουσιάζεται η δοµή των αρχείων του
score editor.
Σχήµα 5-1: ∆οµή αρχείων του score editor.
Είναι απαραίτητο πριν τρέξουµε την εφαρµογή για πρώτη φορά να ορίσουµε την ύπαρξη
της βιβλιοθήκης JMusic.jar όπως φαίνεται στο Σχήµα 5-2.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
43
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 5-2: Προσθήκη βιβλιοθήκης JMusic στον score editor.
Αφού τρέξουµε το πρόγραµµα θα παρατηρήσουµε σταδιακά κάποιες αδυναµίες του. Το
πιο προφανές bug της εφαρµογής που µάλιστα πετάει και exceptions(βλέπε Σχήµα 5-2)
εµφανίζεται όταν έχουν αφαιρεθεί όλες οι νότες και ο χρήστης πατήσει το κουµπί
Remove Last Note.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
44
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 5-3: Exception του score editor.
Μια εύκολη λύση στο παραπάνω πρόβληµα είναι να γίνεται disabled το κουµπί ‘Remove
Last Note’ όταν δεν υπάρχουν νότες στο πεντάγραµµο. Ας αφήσουµε όµως τις αδυναµίες
της εφαρµογής και ας µελετήσουµε τον τρόπο µε τον οποίο σχεδιάστηκε. Ας δούµε κάθε
αρχείο Java ξεχωριστά.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
45
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
5.1 Αρχείο: Main.java
Εδώ βρίσκεται ο κώδικας που είναι απαραίτητος για την εκκίνηση της εφαρµογής. Η
κλάση Main είναι τύπου JFrame και στη main µέθοδο, την µέθοδο που καλείται όταν
τρέχει η κλάση αυτή καλείται ο constructor της Main, ο οποίος αρχικοποιεί τον
ScoreEditor και κατόπιν τον τοποθετεί στην οθόνη του χρήστη.
public class Main extends javax.swing.JFrame {
/** Creates new form Main */
public Main() {
initComponents();
ScoreEditor score = new ScoreEditor();
getContentPane().add(score, BorderLayout.CENTER);
pack();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this
method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code
">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE
);
pack();
}// </editor-fold>
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Main().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
46
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
5.2 Αρχεία: DPianoStave,Dstave,DGrandStave,DTrebleStave
Ας δούµε τα επόµενα 4 αρχεία µε χρήση ενός λογισµικού που δηµιουργεί και παρουσιάζει
UML Diagrams [1] το Rational Rose [23].
DPianoStave
DGrandStave
DStave
DTrebleStave
Σχήµα 5-4: Uml διάγραµµα κλάσεων των staves του score editor.
Τα παραπάνω 4 αρχεία παρουσιάζονται µαζί για να εξηγηθεί η τεχνοτροπία και ο αρχικός
σχεδιασµός τους. Παρατηρούµε ότι υπάρχουν 3 διαφορετικές παρτιτούρες. Η πρώτη για
πιάνο, η δεύτερη για stave και η τρίτη για τρέµπλο. Οι τρεις παραπάνω κλάσεις (βλέπε
Σχήµα 5-4) που αναπαριστούν παρτιτούρες υλοποιούν το αντικείµενο DStave.
Εδώ πρέπει να παρουσιάσουµε µια από τις ιδιότητες της Java καθώς και όλων των
αντικειµενοστραφών γλωσσών προγραµµατισµού. Η ιδιότητα αυτή ονοµάζεται
κληρονοµικότητα [24] ή inheritance στα αγγλικά.
Η ιδιότητα αυτή µπορεί να περιγραφεί µε ένα απλό παράδειγµα. Ας υποθέσουµε ότι
θέλουµε να περιγράψουµε όλους τους πολιτισµούς του γαλαξία µας και ότι υπάρχουν
άνθρωποι, αρειανοί και δεκάδες άλλοι πολιτισµοί. Στην αντικειµενοστραφή γλώσσα πρέπει
να δηµιουργήσουµε ένα αντικείµενο για κάθε είδος πολιτισµού. Μπορούµε εύκολα να
παρατηρήσουµε ότι όλα τα όντα έχουν κάποια κοινά χαρακτηριστικά, όπως όνοµα, ηλικία
και φύλλο. Αντί λοιπόν στο κάθε αντικείµενο να έχουµε τον παρακάτω κώδικα:
// Variables
int age;
String name;
String sex;
// Setters & Getters
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
47
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
Τον τοποθετούµε σε ένα αντικείµενο το οποίο ονοµάζουµε On.java για παράδειγµα. Για
κάθε πολιτισµό χρειάζεται ένα αντικείµενο. Το κάθε αντικείµενο κάνει extend το
αντικείµενο «µπαµπά» (το parent object On.java) και «κληρονοµεί» τον κώδικα που
παρουσιάσαµε παραπάνω.
Έτσι αποφεύγεται η ύπαρξη του ίδιου κώδικα σε 10αδες ή ακόµα και εκατοντάδες αρχείααντικείµενα Java.
Το χαρακτηριστικό της κληρονοµικότητας έχει χρησιµοποιηθεί και στον αρχικό scoreeditor. Τα κοινά χαρακτηριστικά όλων των παρτιτούρων έχουν τοποθετηθεί στο αρχείο
DStave.java και κάθε ιδιαίτερη παρτιτούρα κάνει extend το αρχείο αυτό και κληρονοµεί
τον κώδικα του.
Έτσι στο DStave.java έχουµε τα ακόλουθα attributes τα οποία είναι κοινά για όλα τα
πεντάγραµµα και απεικονίζονται στο Σχήµα 5-5.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
48
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Το Dstave είναι ένα αρκετά περίπλοκο
αντικείµενο µε 650 γραµµές κώδικα, δεκάδες
µεταβλητές και µεθόδους.
Ένα από τα χαρακτηριστικά του είναι ότι
περιέχει 33 µεταβλητές τύπου java.awt.Image.
Περιέχει µεταβλητές για τα offset, τα margin,
το µέτρο, το κλειδί, το τίτλο, µεθόδους για το
pitch, το beat για προσθήκη και αφαίρεση
παύσεων, για διαγραφή της τελευταίας νότας
και άλλες χρήσιµες µεταβλητές και µεθόδους.
Πρέπει να τονισθεί µια από τις µεταβλητές που
περιέχει
και
είναι
τύπου
jm.music.data.Phrase. Μέσα σε αυτή
τη
µεταβλητή
τοποθετείται
το
JMusicString, ένα String στο notation της
βιβλιοθήκης JMusic που περιέχει τα µουσικά
δεδοµένα.
Ένας αποτελεσµατικότερος τρόπος σχεδίασης
του DStave θα ήταν τοποθετώντας σε άλλα
αντικείµενα µέρος του κώδικα ώστε να
υπάρχουν περισσότερα, αλλά µικρότερα σε
όγκο αντικείµενα, όπου το καθένα θα περιέχει
συγκεκριµένη δόµη και χρήση.
Σχήµα 5-5: Attributes του DStave.java.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
49
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Μελετώντας τα child-objects παρατηρούµε ότι το κάθε ένα περιέχει περίπου 300 γραµµές
κώδικα εκ των οποίων οι 250 βρίσκονται στη µέθοδο paint και αφορούν την εµφάνιση
της παρτιτούρας στην οθόνη, και την αντίστοιχη θέση του κάθε µουσικού συµβόλου.
Τέλος, να σχολιαστεί ότι στην εφαρµογή ενώ το JComboBox δείχνει 4 παρτιτούρες (βλέπε
Σχήµα 5-6)
Σχήµα 5-6: Απεικόνιση του JComboBox του score editor.
Στην πράξη υπάρχουν µόνο 3 διαφορετικές παρτιτούρες.
if(item.equalsIgnoreCase("Grand Stave")){
scorePanel.remove(stave);
stave = new DGrandStave(phr);
scorePanel.add(stave,BorderLayout.CENTER);
}else if(item.equalsIgnoreCase("Piano Stave")){
scorePanel.remove(stave);
stave = new DPianoStave(phr);
scorePanel.add(stave,BorderLayout.CENTER);
}else if(item.equalsIgnoreCase("Treble Stave")){
scorePanel.remove(stave);
stave = new DTrebleStave(phr);
scorePanel.add(stave,BorderLayout.CENTER);
}else if(item.equalsIgnoreCase("Bass Stave")){
scorePanel.remove(stave);
stave = new DPianoStave(phr);
scorePanel.add(stave,BorderLayout.CENTER);
}
Το DPianoStave.java χρησιµοποιείται και στο ‘Bass Stave’ και στο ‘Piano Stave’.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
50
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
5.3 Αρχεία: DNoteEditor και DStaveActionHandler
Ξεκινώντας από το αρχείο DNoteEditor.java παρατηρούµε ότι δε χρησιµοποιήθηκε
ποτέ στον score-editor, καθώς είναι commented out ο κώδικας που εµφανίζει το control
που ανοίγει το παράθυρο που απεικονίζεται στο Σχήµα 5-7. Για να εµφανιστεί το
παράθυρο χρειάστηκε να κάνουµε uncomment ορισµένες γραµµές κώδικα στο
DStaveActionHandler.
Αυτό
που
παρατηρούµε
στο
DNoteEditor.java είναι ότι εµφανίζει στοιχεία
ώστε ο χρήστης να κάνει edit τις
παραµέτρους µιας νότας και συγκεκριµένα:
Να αλλάξει τη µουσική νότα
Να τροποποιήσει την τιµή του ρυθµού της
νότας
Να αλλάξει την ένταση µε την οποία θα
παίξει η νότα
Να αλλάξει το duration της
Να αλλάξει το offset
Να αλλάξει το pan
Ο κώδικας αυτού του αρχείου είναι µέρος της
βιβλιοθήκης JMusic.
Σχήµα 5-7: Παράθυρο επεξεργασίας των
παραµέτρων µιας νότας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
51
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
O κώδικας που έπρεπε να γίνει uncomment για να εµφανιστεί ο DNoteEditor
ακολουθεί.
Το
DStaveActionHandler.java
χρησιµοποιείται
από
το
parent-class
DStave.java και αποτελεί τον ActionHandler της παρτιτούρας. Περιέχει τον
κώδικα που κάνει control την εφαρµογή, δηλαδή χειρίζεται τα mouse-clicks, υλοποιεί το
drag & drop και περιέχει κώδικα για τα κουµπιά και τις επιλογές της εφαρµογής.
Επίσης περιέχει κώδικα που εµφανίζει το Popup menu που φαίνεται στο Σχήµα 5-8.
Σχήµα 5-8: Popup menu του score editor.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
52
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
5.4 Αρχεία: Dot1.java, Main.form, ScoreEditor.form
Το αρχείο Dot1.java περιέχει κώδικα που καλεί το View.notate(), µια µέθοδο της JMusic
βιβλιοθήκης που παρουσιάζει στο χρήστη µια φράση του JMusic notation και το
ολοκληρωµένο γραφικό περιβάλλον που παρέχει η κλάσση View το οποίο απεικονίζεται
στο Σχήµα 5-9.
package diamouses.ui.scoreEditor;
import jm.music.data.*;
import jm.JMC;
import jm.util.*;
public class Dot1 implements JMC {
public static void main(String[] args) {
Note n;
n = new Note(C4, QUARTER_NOTE);
Phrase phr = new Phrase();
phr.addNote(n);
//View.sketch(phr);
View.notate(phr);
//View.histogram(new Score(new Part(phr)));
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
53
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 5-9: Γραφικό περιβάλλον κλάσης View.
Τα δύο αρχεία τύπου .form περιέχουν User Interface δεδοµένα, όπως αυτά σχεδιάστηκαν
από το γραφικό περιβάλλον του εργαλείου Netbeans.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
54
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
5.5 Αρχείο: ScoreEditor.java
To αρχείο ScoreEditor αν και περιέχει 600 γραµµές κώδικα µπορεί εύκολα να κατανοηθεί.
Περιέχει τον κώδικα που «χτίζει» το γραφικό περιβάλλον, εµφανίζει την επιλογή των
µουσικών οργάνων όταν ο χρήστης επιλέγει ‘Select Instrument’ (βλέπε Σχήµα 5-10).
Σχήµα 5-10: Παράθυρο επιλογής µουσικού οργάνου.
Επίσης περιέχει control κώδικα για όλα τα κουµπιά που εµφανίζονται στο πάνω µέρος της
εφαρµογής (βλέπε Σχήµα 5-11).
Σχήµα 5-11: Απεικόνιση κουµπιών του score editor.
Τέλος, περιέχει κώδικα που τοποθετεί 40 τυχαίες νότες στην παρτιτούρα όπως φαίνεται
στο Σχήµα 5-12.
Σχήµα 5-12: Κώδικας εισαγωγής τυχαίων νοτών στην παρτιτούρα.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
55
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6. Υλοποίηση
Στο κεφάλαιο αυτό αναλύονται τα κοµµάτια του κώδικα που υλοποιήθηκαν στα πλαίσια
της πτυχιακής εργασίας, καθώς και οι τροποποιήσεις που έγιναν στον αρχικό κώδικα.
Επίσης, παρουσιάζονται εργαλεία ανοιχτού κώδικα που χρησιµοποιήθηκαν όπως το
Apache Ant, για τη διαδικασία packaging την εφαρµογής, και το Joomla, για την
δηµιουργία της ιστοσελίδας και την ενσωµάτωση της εφαρµογής σε αυτή.
6.1 Μετρονόμος
Για την υλοποίηση του µετρονόµου θα χρησιµοποιηθεί κώδικας από το project JFrets [11].
Τα απαραίτητα αρχεία για την εµφάνιση του παραθύρου του Μετρονόµου είναι τα
Metronome και PlayNote.
Αφού εντοπίστηκε ο κώδικας των δύο αυτών αρχείων και αντιγράφηκε στο project της
πτυχιακής εργασίας, δηµιουργήθηκε ένα package ώστε να είναι τακτοποιηµένα τα αρχεία
της εφαρµογής. Το νέο πακέτο ονοµάστηκε diamouses.ui.Metronome και θα
περιέχει όλα τα αρχεία τα σχετικά µε το Μετρονόµο.
Επίσης υλοποιήθηκε ένα νέο αρχείο στο ίδιο πακέτο µε το όνοµα TestMetronome το
οποίο αρχικοποιεί το µετρονόµο για να γίνουν δοκιµές. Έτσι το τελικό αποτέλεσµα –
package structure καθώς και ο κώδικας του TestMetronome.java παρουσιάζονται
στο Σχήµα 6-1.
Σχήµα 6-1: Package structure µετρονόµου.
package diamouses.ui.Metronome;
import javax.swing.JFrame;
public class TestMetronome {
public static void main (String [] args) {
Metronome met = new Metronome(new JFrame(), null, true);
met.setVisible(true);
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
56
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Στην παρακάτω εικόνα ο χρήστης επιλέγει το κουµπί Start και κατόπιν µπορεί να κάνει τις
απαραίτητες ρυθµίσεις όσον αφορά στο τέµπο του µετρονόµου και στην ταχύτητά του
(Beats Per Minute) όπως φαίνεται στο Σχήµα 6-2.
Σχήµα 6-2: Παράθυρο µετρονόµου.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
57
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.2 Βελτίωση αρχείου: ScoreEditor.java
Η κύρια δουλειά του αρχείου ScoreEditor.java είναι να εµφανίζει menu µε κουµπιά που
απεικονίζεται στο Σχήµα 6-3, για επιλογή νότας ή παύσης καθώς και µουσικού οργάνου.
Επίσης διαθέτει controls για επιλογή παρτιτούρας, για διαγραφή της τελευταίας νότας στην
παρτιτούρα και για καθαρισµό όλης της παρτιτούρας.
Σχήµα 6-3: Μενού µε κουµπιά του score editor.
Η επιλογή νότας και παύσης δεν λειτουργούσε σωστά. Ήταν υλοποιηµένες σαν
JToggleButtons αλλά ο χρήστης µπορούσε να κάνει πολλαπλές επιλογές και η δεύτερη
νότα στο duration ήταν µόνιµα επιλεγµένη.
Η διαγραφή της τελευταίας νότας κράσαρε την εφαρµογή, όταν η παρτιτούρα ήταν άδεια
όπως φαίνεται στο Σχήµα 6-4.
Σχήµα 6-4: Exception διαγραφής τελευταίας νότας σε άδεια παρτιτούρα.
Το αρχείο ScoreEditor.java περιείχε παραπάνω από 600 γραµµές κώδικα µε δεκάδες
µεταβλητές και µεθόδους, οι οποίες δεν ήταν ονοµατισµένες έτσι ώστε να αποκαλύπτουν
τη χρήση τους. Η βελτίωση του αρχείου αυτού, τόσο σχεδιαστικά όσο και λειτουργικά
κρίθηκε απαραίτητη.
Βελτίωση 1
Ας δούµε τις δεκάδες µεθόδους jButton_ActionPerformed. Στην ισχύουσα υλοποίηση για
κάθε κουµπί του παραπάνω µενού υπήρχε ο παρακάτω κώδικας:
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
58
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Και κατόπιν η αντίστοιχη µέθοδος:
Αντί να έχουµε δεκάδες µεθόδους, µπορούµε να χρησιµοποιήσουµε έναν άλλο τρόπο
υλοποίησης. Σε κάθε κουµπί προσθέτουµε σαν ActionListener την ίδια την κλάση και
θέτουµε ένα ActionCommand, ένα string βάση του οποίου θα αναγνωρίσουµε στη
συνέχεια ποιο κουµπί πατήθηκε.
Εφόσον για κάθε κουµπί αντικαταστήσαµε την πρώτη από την παραπάνω µέθοδο µε τις
παραπάνω δύο γραµµές και τη δεύτερη µέθοδο µε δική µας υλοποίηση που φαίνεται
παρακάτω, µειώθηκε κατά 150 γραµµές το αρχείο µας και οι απαραίτητες µέθοδοι κατά 8.
Βελτίωση 2
Παρατηρώντας τον κώδικα τώρα που άρχισε να είναι readable, αρκετός κώδικας
επαναλαµβανόταν σε αρκετά σηµεία του αρχείου. Για παράδειγµα στα rests 1/16 , 1/8 κτλ
12 γραµµές κώδικα επαναλαµβάνονται 6 φορές, µια για κάθε rest. Η µόνη διαφορά είναι
µια τιµή τύπου double.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
59
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Ο παραπάνω κώδικας µπορούσε να βελτιωθεί µε τη δηµιουργία µιας µεθόδου που παίρνει
σαν παράµετρο την επίµαχη τιµή και τρέχει τις δώδεκα εντολές.
Με τη δηµιουργία της παραπάνω µεθόδου µειώθηκε ο κώδικας του αρχείου ακόµα
περισσότερο (50 γραµµές λιγότερες).
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
60
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Βελτίωση 3
∆όθηκαν ονόµατα στις µεταβλητές και δηµιουργήθηκαν µέθοδοι για κάθε λειτουργία.
Κατόπιν το actionPerformed, η µέθοδος που είναι υπεύθυνη για κάθε control (κουµπί της
εφαρµογής) έγινε τόσο απλή και ξεκάθαρη.
Βελτίωση 4
Όταν ο χρήστης προσπαθούσε να σβήσει την τελευταία νότα µιας παρτιτούρας ενώ η
παρτιτούρα ήταν άδεια, η εφαρµογή κόλλαγε. Μια µικρή αλλαγή στον κώδικα (που πλέον
τοποθετήθηκε σε µια µέθοδο) ήταν αρκετή για να διορθωθεί το λάθος αυτό.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
61
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Το if (phrase.getSize() > 0) ήταν αρκετό για να διορθωθεί το παραπάνω λάθος.
Βελτίωση 5
∆ηµιουργήθηκε µέθοδος για να δηµιουργεί τα κουµπιά της εφαρµογής. Ξανά κώδικας
επαναλαµβανόταν για κάθε κουµπί του ScoreEditor.
/**
* Method creates a "smart" JToggleButton
* @param imageName The location of the image of this toggle-button
* @param selected_imageName The location of the image of this toggle-button
*
when the toggle button is selected
* @param actionCommand The action-command to set for this components
* @param toolTipText the tooltip of the component
* @param altText Alternative text in case the image is missing
* @return A JToggleButton component
*/
protected JToggleButton makeToggleButton(String imageName, String
selected_imageName, String actionCommand, String toolTipText, String altText) {
// Look for the image.
String imgLocation = "images/menu_images/" + imageName + ".gif";
String imgLocation2 = "images/menu_images/" + selected_imageName + ".gif";
URL imageURL = Main.class.getResource(imgLocation);
URL imageURL2 = Main.class.getResource(imgLocation2);
// Create and initialize the button.
JToggleButton button = new JToggleButton();
button.setActionCommand(actionCommand);
button.setToolTipText(toolTipText);
button.addActionListener(this);
if ( (imageURL != null) & (imageURL2 != null) ){ // image found
button.setIcon(new ImageIcon(imageURL, altText));
button.setSelectedIcon(new ImageIcon(imageURL2, altText));
} else { // no image found
button.setText(altText);
System.err.println("Resource not found: " + imgLocation + "" +
(imageURL==null) + " " + (imageURL2==null));
}
return button;
}
Γενικά το αρχείο ScoreEditor.java είχε παραπάνω από 600 γραµµές κώδικα. Μετά από
σειρά αλλαγών και βελτιώσεων κατέληξε να κάνει ακριβώς την ίδια δουλειά πολύ πιο
αποτελεσµατικά τόσο από πλευράς χρήσης µνήµης όσο και από λειτουργικότητα µε
λιγότερο από 300 γραµµές κώδικα.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
62
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.3 Βελτίωση αρχείου: Main.java
Μια αδυναµία που εντοπίζεται αµέσως στο αρχείο αυτό, είναι ότι το Look & Feel είναι το
default της Java. Γνωρίζοντας ότι η Java παρέχει δυνατότητες να προσοµοιάσει το γραφικό
περιβάλλον πολλών λειτουργικών συστηµάτων µπορούµε να βελτιώσουµε αισθητά το
Look & Feel της εφαρµογής προσθέτοντας την παρακάτω µέθοδο, και καλώντας την στη
main προτού εµφανίσουµε το γραφικό περιβάλλον.
/**
* setDefault() , Sets the default Look and Feel.
* On Microsoft Windows platforms, this specifies the Windows Look & Feel.
* On Mac OS platforms, this
* specifies the Mac OS Look & Feel. On Sun platforms, it specifies the CDE/Motif
* Look & Feel.
*
* With JDK1.4.2 upwards it sets the 'Luna' look and feel in Windows XP and
* 'Bluecurve' in GNOME.
*/
public static void setDefault() {
try {
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
} catch (java.lang.ClassNotFoundException classE) {
// Handle exception
} catch (java.lang.InstantiationException insE) {
//Handle exception
} catch (java.lang.IllegalAccessException illE) {
//Handle exception
} catch (javax.swing.UnsupportedLookAndFeelException unE) {
//Handle exception
}
}
Η παραπάνω µέθοδος «κοιτάει» σε ποιο λειτουργικό σύστηµα τρέχει η εφαρµογή και θέτει
το κατάλληλο Look & Feel.
Σχήµα 6-5: Look & Feel εφαρµογής.
Στο Σχήµα 6-5 παρουσιάζεται στο πάνω µέρος το νέο Look & Feel που µοιάζει
περισσότερο σε αυτό που χρησιµοποιούν τα Windows XP/Vista από το αρχικό το οποίο
φαίνεται από κάτω σαν µέτρο σύγκρισης.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
63
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Στο αρχείο αυτό προστέθηκαν επίσης αρκετές γραµµές κώδικα (περίπου 150), µε σκοπό τη
δηµιουργία µενού επιλογών.
Στο µενού File υπάρχουν επιλογές για ‘Καθαρισµό Παρτιτούρας’ και ‘Παίξιµο
παρτιτούρας’ όπως φαίνεται στο Σχήµα 6-6.
Σχήµα 6-6: Μενού File.
Στο Σχήµα 6-7 απεικονίζεται το µενού Tools όπου υπάρχει η επιλογή για τον
‘Μετρονόµο’.
Σχήµα 6-7: Μενού Tools.
Ενώ στο µενού Help υπάρχει η επιλογή ‘About’(Σχήµα 6-8).
Σχήµα 6-8: Μενού Help.
Όταν ο χρήστης επιλέξει το Help About εµφανίζεται στο χρήστη το µήνυµα που
παρουσιάζεται στο Σχήµα 6-9.
Σχήµα 6-9: Μήνυµα στο ‘About’.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
64
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Τα short-cuts που εµφανίζονται στο About Dialog λειτουργούν κανονικά στην εφαρµογή
καθώς υλοποιήθηκαν στο Main.java
O κώδικας του Main.java αρχικοποιεί την εφαρµογή. Είναι τύπου JFrame και στη main
µέθοδο, την µέθοδο που καλείται όταν τρέχει η κλάση αυτή καλείται ο constructor της
Main, ο οποίος θέτει τίτλο στο JFrame αρχικοποιεί τις µεταβλητές και κατόπιν τοποθετεί
τα τρία κοµµάτια που αποτελούν την εργασία αυτή (το πάνελ επιλογών, το score που είναι
η παρτιτούρα και την εικονική κιθάρα) στην οθόνη του χρήστη.
/**
* Constructor
*/
public Main() {
this.setTitle("Πτυχιακή ΤΕΙ Κρήτης Γρηγορακάκη Αιµιλία");
initComponents();
score = new ScoreEditor();
setJMenuBar(getJMenuBar());
Ευθυµίου Μιχαλίτσα,
Toolkit kit = getToolkit();
Dimension screenSize = kit.getScreenSize();
int screenWidth = screenSize.width;
//-System.out.println("screenwidth" + screenWidth);
GuitarNeck ff = GuitarNeck.getInstance(screenWidth);
getContentPane().add(score, BorderLayout.CENTER);
getContentPane().add(score.getJToolBar(),
BorderLayout.PAGE_START);
getContentPane().add(ff, BorderLayout.SOUTH);
setVisible(true);
setExtendedState(JFrame.MAXIMIZED_HORIZ);
pack();
}
Το πάνελ επιλογών παρουσιάστηκε στο προηγούµενο κεφάλαιο 7.2. Η εικονική κιθάρα και
η παρτιτούρα θα παρουσιαστούν σε επόµενα κεφάλαια. Η άλλη εργασία που κάνει η Main
είναι η προσθήκη του Μενού Επιλογών.
Η µέθοδος που δηµιουργεί το µενού επιλογών ακολουθεί:
/**
* Creates a JMenuBar (File/Tools/Help) with appropriate
* menu items
*/
public JMenuBar getJMenuBar() {
// Local Variables
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// Create the menu bar.
menuBar = new JMenuBar();
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
65
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
// 1. Build the 'File' menu.
menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menuBar.add(menu);
// 'Clear Stave' MenuItem
menuItem = new JMenuItem("Clear Stave", KeyEvent.VK_N);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,Action
Event.CTRL_MASK));
menuItem.setActionCommand("Clear_Stave");
menuItem.addActionListener(this);
menu.add(menuItem);
Κάθε µενού αποτελείται από menu-items. Τα menu-items έχουν µια ονοµασία, «ακούν» σε
ένα KeyEvent και έχουν κάποιο Accelarator. Με τη χρήση των accelerators ο χρήστης
µπορεί να πατήσει ένα συνδυασµό πλήκτρων στο πληκτρολόγιό του π.χ. Ctrl-P για να
κάνει Play το tune της παρτιτούρας.
Το κάθε menu-item κάνει register στον ActionListener o οποίος περιέχει τον απαραίτητο
κώδικα για την υλοποίηση της επιλογής του χρήστη. Για παράδειγµα για την αποθήκευση
της παρτιτούρας ως MIDI αρχείο στο δίσκο απαιτείται ο παρακάτω κώδικας.
if (action_command.equals("Save_Stave")) {
JFileChooser fc = new JFileChooser(new File(filename));
// Show save dialog; this method does not return until the dialog is
closed
fc.showSaveDialog(this);
File selected_file = fc.getSelectedFile();
System.out.println("Going to save score into file : " +
selected_file.toString());
Score s = new Score(new Part(score.stave.getPhrase()));
Write.midi(s, selected_file.toString());
}
Κώδικας από [30] και [31]. Εµφανίζει στο χρήστη το παράθυρο επιλογής αρχείου(βλέπε
Σχήµα 6-10) για αποθήκευση και κατόπιν αποθηκεύει σε αυτό το αρχείο το MIDI που
αντιστοιχεί στην παρτιτούρα.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
66
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-10: Παράθυρο επιλογής αρχείου για αποθήκευση.
Μετά την επιλογή του φακέλου αλλά και του ονόµατος του αρχείου που έχει την κατάληξη
.midi εµφανίζεται στην κονσόλα το µήνυµα:
Going to save score into file : C:\ test2.midi
----------------------- Writing MIDI File -----------------------------Converting to SMF data structure...
Part 0 'Untitled Part' to SMF Track on Ch. 0: Phrase 0:......
MIDI file 'C:\test2.midi' written from score 'Untitled Score' in 0.074
seconds.
------------------------------------------------------------------------
Και ένα valid αρχείο µε κατάληξη .midi δηµιουργείται και µπορούµε να το ακούσουµε µε
οποιαδήποτε media player (Winamp, Windows Media Player, VLC, Real Audio κτλ)
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
67
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.4 Αρχείο: Constants.java
Το αρχείο Constants.java (50 γραµµές) υλοποιήθηκε ως βοηθητικό αρχείο για τη
διευκόλυνση του loading αρχείων εικόνας. Στο Σχήµα 6-11 παρουσιάζονται οι εικόνες που
αποφασίστηκε να χρησιµοποιηθούν στη συνέχεια της εργασίας για να εµφανίζονται στο
µπράτσο της κιθάρας στην αντίστοιχη θέση. ∆ηλαδή όταν ο χρήστης επιλέγει την 3η θέση
της 2ης χορδής της κιθάρας, η αντίστοιχη νότα θα «ζωγραφίζεται» στο αντίστοιχο σηµείο
της κιθάρας. Για προγραµµατιστική διευκόλυνση όλα τα paths των εικόνων, αλλά και ο
κώδικας για να τις φορτώνει τοποθετήθηκε στο αρχείο Constants.java
Σχήµα 6-11: Οι εικόνες του Constants.java.
package diamouses.ui.scoreEditor;
import javax.swing.ImageIcon;
public final class Constants
{
public ImageIcon a;
public ImageIcon asharp;
public ImageIcon b ;
public ImageIcon c;
public ImageIcon csharp;
public ImageIcon d;
public ImageIcon dsharp;
public ImageIcon e;
public ImageIcon f;
public ImageIcon fsharp;
public ImageIcon g;
public ImageIcon gsharp;
public Constants()
{
a = new ImageIcon(getClass().getResource("images/note_images/a.png"));
asharp = new ImageIcon(getClass().getResource("images/note_images/asharp.png"));
b = new ImageIcon(getClass().getResource("images/note_images/b.png"));
c = new ImageIcon(getClass().getResource("images/note_images/c.png"));
csharp = new ImageIcon(getClass().getResource("images/note_images/csharp.png"));
d = new ImageIcon(getClass().getResource("images/note_images/d.png"));
dsharp = new ImageIcon(getClass().getResource("images/note_images/dsharp.png"));
e = new ImageIcon(getClass().getResource("images/note_images/e.png"));
f = new ImageIcon(getClass().getResource("images/note_images/f.png"));
fsharp = new ImageIcon(getClass().getResource("images/note_images/fsharp.png"));
g = new ImageIcon(getClass().getResource("images/note_images/g.png"));
gsharp = new ImageIcon(getClass().getResource("images/note_images/gsharp.png"));
e.setDescription("e");
f.setDescription("f");
fsharp.setDescription("fsharp");
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
68
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
g.setDescription("g");
gsharp.setDescription("gsharp");
a.setDescription("a");
asharp.setDescription("asharp");
b.setDescription("b");
c.setDescription("c");
csharp.setDescription("csharp");
d.setDescription("d");
dsharp.setDescription("dsharp");
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
69
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.5 Αρχείο: GuitarNeck.java
Ένας από τους αρχικούς στόχους της πτυχιακής αυτής εργασίας ήταν η εµφάνιση µέρους
της κιθάρας και συγκεκριµένα του µπράτσου της και η υλοποίηση κατάλληλης διεπαφής
για την αλληλεπίδραση του χρήστη µε την εικονική απεικόνιση της κιθάρας. Επίσης ένας
άλλος στόχος της εφαρµογής της πτυχιακής ήταν η αλληλεπίδραση µεταξύ της
παρτιτούρας και της εικονικής κιθάρας.
Στο Σχήµα 6-12 εµφανίζεται η εικονική κιθάρα όπως έχει υλοποιηθεί από το project JFrets.
Ακριβώς πάνω από την κιθάρα αυτή εµφανίζεται το πρώτο prototype της δικής µας
υλοποίησης µε έναν αριθµό κουµπιών (Java JButtons) των οποίων το πλάτος έχει ορισθεί
ίσο µε το πλάτος του κάθε τάστου της κιθάρας.
Σχήµα 6-12: Εικονική κιθάρα JFrets.
Για επιβεβαίωση των µεγεθών των κουµπιών που υλοποιήθηκαν, κόκκινες κάθετες
γραµµές εµφανίζονται κατόπιν επεξεργασίας της εικόνας µε πρόγραµµα επεξεργασίας
(βλέπε Σχήµα 6-13).
Σχήµα 6-13: Απεικόνιση τωνµεγεθών των κουµπιών που υλοποιήθηκαν.
Επαναλαµβάνοντας το JPanel του πρώτου prototype 5 φορές (5 * 13 κουµπιά) εµφανίζεται
το αποτέλεσµα του Σχήµατος 6-14 που µοιάζει να πλησιάζει την επιθυµητή µορφή.
∆ηλαδή τα κουµπιά αποτελούν τους χώρους που επιθυµούµε να αλληλεπιδρά ο χρήστης.
Στόχος είναι ο χρήστης να βλέπει µόνο το µπράτσο της κιθάρας και κάνοντας mouse-click
πάνω σε κάποιο σηµείο της να γνωρίζει η εφαρµογή ποια ακριβώς νότα πατήθηκε.
Σχήµα 6-14: Πρώτο prototype της εικονικής κιθάρας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
70
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Τα κουµπιά ουσιαστικά θα βρίσκονται «πίσω» από την εικόνα της κιθάρας και ο τελικός
χρήστης θα αγνοεί την ύπαρξη τους. Θα είναι όµως ο µηχανισµός µε τον οποίο θα
καταλαβαίνει η εφαρµογή τα mouse-clicks.
Τα JButtons σαν components της swing library εµφανίζονται στην οθόνη του χρήστη
επικαλύπτοντας το υπάρχον JPanel. Με την παρακάτω εντολή ορίζουµε σε κάθε κουµπί να
µην «γεµίζει» το content-area. ∆ηλαδή να µην κάνει paint την επιφάνεια του κουµπιού που
είναι γύρω από τις εικόνες ή το κείµενο του κουµπιού. Συνήθως αυτό γίνεται σε χρώµα
συµβατό µε αυτό του λειτουργικού συστήµατος που τρέχει η εφαρµογή.
button.setContentAreaFilled(false);
Το οπτικό αποτέλεσµα απεικονίζεται στο Σχήµα 6-15.
Σχήµα 6-15: ∆εύτερο prototype της εικονικής κιθάρας.
Για να µην εµφανίζεται το διακοσµητικό border γύρω από τα κουµπιά η παρακάτω εντολή
είναι απαραίτητη.
b1.setBorderPainted(false);
Το οπτικό αποτέλεσµα φαίνεται στο Σχήµα 6-16.
Σχήµα 6-16: Τρίτο prototype της εικονικής κιθάρας.
Θέλοντας να δοκιµάσουµε να εµφανίσουµε µια εικόνα πίσω από τα κουµπιά της παραπάνω
εικόνας υλοποιήθηκε η παρακάτω µέθοδος που πρέπει να εµφανίσει ένα µπλε οβάλ σχήµα
στο background.
public void paintComponent(Graphics g) {
int width = getWidth();
int height = getHeight();
g.setColor(Color.blue);
g.drawOval(0, 0, width, height);
}
Η µπλε γραµµή σε οβάλ σχήµα δεν εµφανίζεται. Κάνοντας όµως .setOpaque(false) όλα τα
JPanels που περιέχουν τα κουµπιά:
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
71
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
string_1.setOpaque(false);
string_2.setOpaque(false);
string_3.setOpaque(false);
string_4.setOpaque(false);
string_5.setOpaque(false);
Στο Σχήµα 6-17 βλέπουµε ότι το background πλέον εµφανίζεται και όλα τα components
που χρησιµοποιήσαµε είναι TRANSPARENT (διαφανή).
Σχήµα 6-17: Απεικόνιση οβάλ σχήµατος στο prototype της εικονικής κιθάρας.
∆ιαθέτοντας την απαραίτητη τεχνογνωσία, ήρθε η ώρα να κάνουµε την πλήρη υλοποίηση
της εικονικής κιθάρας. Ξεκινώντας από το wood texture που απεικονίζεται στο Σχήµα 618.
Σχήµα 6-18: Wood texture ταστίερας της κιθάρας.
Και µε ορισµένη δουλειά σε πρόγραµµα επεξεργασίας εικόνας καταλήγουµε στο Σχήµα 619 που απεικονίζει ένα ξύλινο µπράτσο κιθάρας µε 6 χορδές και τα ανάλογα τάστα.
Σχήµα 6-19: Εικονική αναπαράσταση µπράτσου κιθάρας.
Η παραπάνω εικόνα θα χρησιµοποιηθεί σαν background για την υλοποίηση της εικονικής
κιθάρας.
∆ηµιουργώντας ξανά τα απαραίτητα κουµπιά της εφαρµογής έχουµε το αποτέλεσµα που
φαίνεται στο Σχήµα 6-20.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
72
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-20: Πάνελ κουµπιών εικονικής κιθάρας.
Εµφανίζουµε το background image µε τον παρακάτω κώδικα πίσω από τα κουµπιά αυτά:
/**
* Method Paint the Guitar Neck on the Background of this JPanel.
*/
public void paintComponent(Graphics g) {
String imgLocation2 = "images/GuitarNeck.png";
URL imageURL = GuitarNeck.class.getResource(imgLocation2);
ImageIcon ii = new ImageIcon(imageURL, "altText");
g.drawImage(ii.getImage(),
0,0,this.getSize().width,this.getSize().height, this);
}
έχουµε το οπτικό αποτέλεσµα που παρουσιάζεται στο Σχήµα 6-21.
Σχήµα 6-21: Πάνελ εικονικής κιθάρας.
Μπροστά από την κάθε θέση της κιθάρας «κρύβεται» ένα διαφανές JButton.
Έχοντας κατά νου τις θέσεις της κιθάρας και τις νότες που αντιστοιχούν (βλέπε Σχήµα 622), και κάνοντας χρήση της κλάσης Constants.java που παρουσιάστηκε νωρίτερα θέτουµε
σαν IconImages το σύµβολο της κατάλληλης νότας στο κατάλληλο σηµείο.
Σχήµα 6-22: Νότες στην ταστιέρα της κιθάρας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
73
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-23: ∆ιεπαφή εικονικής κιθάρας.
Υλοποιώντας τα παραπάνω σαν JToggleButtons αντί για απλά JButtons και θέτοντας την
κατάλληλη εικόνα για τα «πατηµένα» κουµπιά και καµία εικόνα για τα «µη-πατηµένα»
κουµπιά, έχουµε µια πρώτη διεπαφή χρήστη (βλέπε Σχήµα 6-23).
Η υλοποίηση του κώδικα ακολούθησε τις αρχές του αντικειµενοστραφούς
προγραµµατισµού. Αντί να επαναλαµβάνεται κώδικας µε πλήθος συντεταγµένων
υλοποιήθηκαν ορισµένες µέθοδοι (4 µέθοδοι) που η κάθε µια κάνει συγκεκριµένη εργασία.
1. Η µέθοδος getIconsForString(int string) παίρνει σαν παράµετρο την
χορδή της κιθάρας, τιµές από ένα (1) µέχρι και έξι (6) και επιστρέφει πίνακα
αντικειµένων javax.swing.ImageIcon µε τις εικόνες των νοτών.
/**
* Method getIconsForString returns an Array [] of ImageIcons
* with the images of the appropriate Notes for each string of
* the Guitar.
*
* @param string An integer from 1 to 6 representing the First..Sixth string
*
of a Guitar.
* @return an ImageIcon [] array.
*/
private ImageIcon [] getIconsForString( int string ) {
Constants c = new Constants();
switch (string) {
case 1: ImageIcon [] string_1_notes = {c.e, c.f, c.fsharp, c.g,
c.gsharp,c.a,c.asharp,c.b, c.c, c.csharp,c.d, c.dsharp,c.e,c.f,
null, null, null, null,null,null,null,null};
return string_1_notes;
case 2: ImageIcon [] string_2_notes = {c.b, c.c,c.csharp,c.d,
c.dsharp,c.e,c.f, c.fsharp, c.g, c.gsharp,
c.a,c.asharp,c.b, c.c,null,null, null, null,null,null,null,null};
return string_2_notes;
case 3: ImageIcon [] string_3_notes = {c.g, c.gsharp,c.a,c.asharp,c.b,
c.c,c.csharp,c.d, c.dsharp, c.e,c.f,c.fsharp, c.g,
c.gsharp,null,null, null, null,null,null,null,null};
return string_3_notes;
case 4: ImageIcon [] string_4_notes = {c.d, c.dsharp, c.e,c.f,c.fsharp,
c.g, c.gsharp, c.a,c.asharp,c.b, c.c, c.csharp,c.d,
c.dsharp,null,null, null, null,null,null,null,null};
return string_4_notes;
case 5: ImageIcon [] string_5_notes = {c.a,c.asharp,c.b, c.c,c.csharp,c.d,
c.dsharp, c.e,c.f,c.fsharp, c.g, c.gsharp,c.a, c.asharp,null,null,
null, null,null,null,null,null};
return string_5_notes;
case 6: ImageIcon [] string_6_notes = { c.e,c.f,c.fsharp, c.g,
c.gsharp,c.a, c.asharp,c.b, c.c,c.csharp,c.d, c.dsharp,
c.e,c.f,null,null, null, null,null,null,null,null};
return string_6_notes;
default: System.out.println("Errornous string " + string +
" in method GuitarFrame.getIconsForString");
return null;
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
74
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
2. Η µέθοδος paintComponent() που «ζωγραφίζει» το background της εικονικής
κιθάρας:
/**
* Method Paint the Guitar Neck on the Background of this JPanel.
*/
public void paintComponent(Graphics g) {
String imgLocation2 = "images/GuitarNeck.png";
URL imageURL = GuitarNeck.class.getResource(imgLocation2);
ImageIcon ii = new ImageIcon(imageURL, "altText");
g.drawImage(ii.getImage(), 0,0,this.getSize().width,this.getSize().height,
this);
}
3. Η µέθοδος setSizes() που δίνει στα διάφανα κουµπιά το κατάλληλο µέγεθος ώστε
να πιάνουν τα mouse-clicks του χρήστη µε όσο το δυνατόν µεγαλύτερη πιστότητα.
/**
* This method sets the sizes of the JToggleButtons
*/
private void setSizes () {
int width;
for (int i = 0; i <= 21; i++) {
switch (i) {
case 0: width = 83; break;
case 1: width = 89; break;
case 2: width = 82; break;
case 3: width = 77; break;
case 4: width = 75; break;
case 5: width = 66; break;
case 6: width = 64; break;
case 7: width = 59; break;
case 8: width = 55; break;
case 9: width = 54; break;
case 10: width = 49; break;
case 11: width = 46; break;
case 12: width = 43; break;
case 13: width = 40; break;
case 14: width = 38; break;
case 15: width = 35; break;
case 16: width = 32; break;
case 17: width = 30; break;
case 18: width = 28; break;
case 19: width = 26; break;
case 20: width = 22; break;
default: width = 12; break;
}
width+=2;
width = screen_width*width/1280;
string_1_buttons[i] .setPreferredSize(new Dimension(width,
string_2_buttons[i] .setPreferredSize(new Dimension(width,
string_3_buttons[i] .setPreferredSize(new Dimension(width,
string_4_buttons[i] .setPreferredSize(new Dimension(width,
string_5_buttons[i] .setPreferredSize(new Dimension(width,
string_6_buttons[i] .setPreferredSize(new Dimension(width,
}
}
height));
height));
height));
height));
height));
height));
Μάλιστα στην παραπάνω µέθοδο πέρα από το γεγονός ότι τα διάφανα κουµπιά αποκτούν
το κατάλληλο πλάτος σε pixels µε ξεκάθαρο τρόπο έχει υλοποιηθεί δυνατότητα για να
µπορεί η εφαρµογή να τρέχει άψογα σε όλες τις δυνατές αναλύσεις.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
75
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Με άλλα λόγια η εικόνα που χρησιµοποιήθηκε για την εφαρµογή µας έχει διαστάσεις 1517
x 144 εικονο-στοιχεία (pixels) έτσι ώστε η εφαρµογή να είναι άριστη οπτικά ακόµα και σε
αναλύσεις 1600x1200 ή και µεγαλύτερες. Επειδή όµως η ανάπτυξη της εφαρµογής έγινε σε
οθόνη µε ανάλυση 1280x800 και το πλάτος των κουµπιών σε pixels µετρήθηκε στην
ανάλυση αυτή, έπρεπε να προβλεφθεί χρήση σε διαφορετικές αναλύσεις. Έτσι µε έξυπνο
τρόπο υλοποιήθηκε και δοκιµάστηκε η εφαρµογή και σε άλλες αναλύσεις µε επιτυχία.
4. Μέθοδος
private
JPanel
string_buttons, int string).
getStringPanel(JToggleButton
[]
/**
* Method returns a JPanel with JButtons for each note of the Guitar
* @param string First..Sixth string of the guitar
* @return a JPanel with appropriate JButtons
*/
private JPanel getStringPanel(JToggleButton [] string_buttons, int string) {
JPanel main_panel = new JPanel();
main_panel .setLayout(new FlowLayout());
ImageIcon [] string_images = getIconsForString(string);
for (int i = 0; i <= 21; i++) {
string_buttons[i] = new JToggleButton();
string_buttons[i].setContentAreaFilled(false);
string_buttons[i].setBorderPainted(false);
string_buttons[i].setOpaque(false);
string_buttons[i].setIcon(new ImageIcon());
string_buttons[i].setSelectedIcon(string_images[i]);
main_panel.add(string_buttons[i]);
}
return main_panel;
}
H παραπάνω µέθοδος παίρνει σαν παραµέτρους ένα uninitialized πίνακα από Buttons και
τον αριθµό µιας χορδής. Περιέχει κώδικα για να αρχικοποιεί τα κουµπιά και καθορίζει τις
παραµέτρους για να είναι διαφανή (transparent) τα κουµπιά αυτά.
Τοποθετώντας τον κώδικα της εφαρµογής σε µεθόδους έχουµε τη δυνατότητα εύκολα να
µετατρέψουµε τα components από JButtons σε JToggleButtons ή JLabels για να
πειραµατιστούµε και να ανακαλύψουµε την ιδανικότερη υλοποίηση.
Αφού έχουν υλοποιηθεί όλες οι απαραίτητες µέθοδοι παρουσιάζουµε τις µεταβλητές της
κλάσης και τον constructor που αρχικοποιεί το νέο αυτό αντικείµενο-component.
Οι µεταβλητές του αντικειµένου είναι:
/**
* Global variables for the application
*/
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
76
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
private int height = 32;
private int screen_width;
private
private
private
private
private
private
JToggleButton
JToggleButton
JToggleButton
JToggleButton
JToggleButton
JToggleButton
[]
[]
[]
[]
[]
[]
string_1_buttons
string_2_buttons
string_3_buttons
string_4_buttons
string_5_buttons
string_6_buttons
=
=
=
=
=
=
new
new
new
new
new
new
JToggleButton
JToggleButton
JToggleButton
JToggleButton
JToggleButton
JToggleButton
[22];
[22];
[22];
[22];
[22];
[22];
Ο αριθµός των global µεταβλητών είναι µικρός και µε τέτοιο τρόπο ώστε να
παραµετροποιείται εύκολα το αντικείµενο. To height είναι το ύψος των κουµπιών (ή των
χορδών) σε pixels, το screen_width είναι το πλάτος της εφαρµογής σε pixes και οι έξης
πίνακες µε JToggleButtons περιέχουν τα διάφανα κουµπιά για κάθε µια από τις χορδές της
κιθάρας.
Τέλος, ο constructor του αντικειµένου είναι ο εξής:
/**
* Constructor.
* Initializes 6 JPanels, one for each guitar string
*/
public GuitarNeck(int screen_width) {
this.screen_width = screen_width;
// 1. Create six JPanels
JPanel string_1 = getStringPanel(string_1_buttons,1);
JPanel string_2 = getStringPanel(string_2_buttons,2);
JPanel string_3 = getStringPanel(string_3_buttons,3);
JPanel string_4 = getStringPanel(string_4_buttons,4);
JPanel string_5 = getStringPanel(string_5_buttons,5);
JPanel string_6 = getStringPanel(string_6_buttons,6);
// 2. Make them Not-Opaque (Make them TRANSPARENT)
string_1.setOpaque(false);
string_2.setOpaque(false);
string_3.setOpaque(false);
string_4.setOpaque(false);
string_5.setOpaque(false);
string_6.setOpaque(false);
// 3. Add each of the JPanel in a stack from top to bottom
setLayout(new GridLayout(0,1,0,0));
add(string_1);
add(string_2);
add(string_3);
add(string_4);
add(string_5);
add(string_6);
setSizes();
}
Παίρνει σαν παράµετρο το µέγεθος του παραθύρου. Κατόπιν αρχικοποιεί έξι JPanels
κάνοντας χρήση της µεθόδου getStringPanel και στη συνέχεια κάνει transparent (διάφανα)
τα νέα αυτά JPanels. Τέλος χρησιµοποιεί τον GridLayout Layout Manager µε παράµετρους
0,1,0,0 εννοώντας τοποθέτηση όλων των components σε 1 στήλη µε border 0,0.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
77
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Κάνοντας add τα 6 JPanels, τοποθετούνται όλα τα JPanels της εφαρµογής το ένα κάτω από
το άλλο και τέλος καλείται η µέθοδος setSizes() για να βελτιστοποιήσουµε την εµφάνιση
της εφαρµογής σε όλες τις πιθανές αναλύσεις.
Ένα ακόµα σηµείο που χρήζει αναφοράς είναι ο τρόπος µε τον οποίο θα προστεθεί αυτό το
Component µέσα σε ένα JFrame.
JFrame f = new JFrame();
f.setVisible(true);
f.setExtendedState(JFrame.MAXIMIZED_HORIZ);
Toolkit kit = f.getToolkit();
Dimension screenSize = kit.getScreenSize();
int screenWidth = screenSize.width;
System.out.println("screenwidth" + screenWidth);
GuitarNeck ff = new GuitarNeck(screenWidth);
f.getContentPane().add(ff);
f.pack();
Αφού
αρχικοποιήσουµε
ένα
νέο
JFrame
καλούµε
την
εντολή
ώστε να πάρει το µέγιστο δυνατό
πλάτος το νέο παράθυρο. Κατόπιν µε χρήση του εργαλείου Toolkit ανακαλύπτουµε το
πλάτος της εφαρµογής (δηλαδή της ανάλυσης που θα τρέξει στο περιβάλλον του χρήστη)
και αρχικοποιούµε το αντικείµενο GuitarNeck µε την παράµετρο screenWidth.
setExtendedState(JFrame.MAXIMIZED_HORIZ);
Αυτό το σηµείο αξίζει αναφοράς καθώς οι Layout Managers για να θέσουν σωστά τα
µεγέθη (ύψος και πλάτος) σε κάθε component (και στο αντικείµενο αυτό έχουµε να
θέσουµε τα µεγέθη ύψος και πλάτος σε 132 κουµπιά, 6 χορδές επί 22) πρέπει να το κάνουν
τη στιγµή που τα αρχικοποιούµε για πρώτη φορά.
Για αυτό και είναι απαραίτητο να χρησιµοποιηθεί η παραπάνω τεχνική προτού
αρχικοποιήσουµε το αντικείµενο µας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
78
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.6 Αρχείο: DStave.java
Η πτυχιακή αυτή εργασία απαιτούσε οι νότες στο πεντάγραµµο να αποκτούν κόκκινο
χρώµα όταν ο χρήστης τις επέλεγε. Η πρώτη σκέψη ήταν να δηµιουργούσαµε µια σειρά
από εικόνες που αντί για µαύρο χρώµα να είχαν κόκκινο (βλέπε Σχήµα 6-24), να τις
φορτώναµε στη µνήµη και να τις εµφανίζαµε όταν ο χρήστης κάνει click πάνω στην
αντίστοιχη νότα.
Σχήµα 6-24: Μουσικά σύµβολα που έπρεπε να επαναδηµιουργηθούν.
Η παραπάνω σκέψη απορρίφτηκε αµέσως. Οι λόγοι ήταν πολλοί:
1. Η εφαρµογή θα απαιτούσε πολύ παραπάνω αποθηκευτικό χώρο τόσο στη µνήµη
όσο και στον αποθηκευτικό δίσκο.
2. Τι θα συνέβαινε αν κάποιος επέλεγε να τροποποιήσει τις αρχικές εικόνες. Θα
έπρεπε να τροποποιήσει και την κόκκινη εκδοχή τους.
3. Τι θα συνέβαινε αν αντί για κόκκινο χρώµα θέλαµε να εµφανίζαµε τα επιλεγµένα
µουσικά σύµβολα σε ΠΡΑΣΙΝΟ ή σε ΜΠΛΕ χρώµα; Θα έπρεπε να δηµιουργηθούν
νέες σειρές εικόνων, και θα απαιτούνταν περισσότερος κώδικας.
Η λύση που επιλέχθηκε και µετά από αρκετή έρευνα υλοποιήθηκε ήταν η µετατροπή του
RGB color model δυναµικά όταν αυτό ήταν απαραίτητο. Για να γίνει αυτό, και καθώς η
εικόνα που εµφανίζεται στην παρτιτούρα είναι τύπου java.awt.Image έπρεπε να
δηµιουργηθούν πρώτα δύο µέθοδοι. Η πρώτη θα µετέτρεπε το java.awt.Image σε
java.awt.Image.BufferedImage και η άλλη θα έκανε την αντίστροφη διαδικασία.
Ο λόγος είναι ότι η κλάση java.awt.Image είναι µια πολύ απλή υλοποίηση που δεν περιέχει
µεθόδους ούτε για Alpha Pixels (Transparency) ούτε για color models (RGB / ARGB κτλ).
Ας δούµε τη µέθοδο που µετατρέπει µια κλάση BufferedImage σε Image:
// This method returns an Image object from a buffered image
public static Image toImage(BufferedImage bufferedImage) {
return Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource());
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
79
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Ας δούµε και τη µέθοδο που κάνει το αντίστροφο της παραπάνω, δηλαδή από Image σε
BufferedImage:
// This method returns a buffered image with the contents of an image
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage)image;
}
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels; for this method's
// implementation, see e661 Determining If an Image Has Transparent Pixels
// Create a buffered image with a format that's compatible with the screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered image
// int transparency = Transparency.OPAQUE;
//boolean hasAlpha = hasAlpha(image);
//if (hasAlpha)
int transparency = Transparency.BITMASK;
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(
image.getWidth(null), image.getHeight(null), transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
// Create a buffered image using the default color model
//int type = BufferedImage.TYPE_INT_RGB;
//if (hasAlpha)
int type = BufferedImage.TYPE_INT_ARGB;
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null),
type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
H παραπάνω µέθοδος ήταν πολύ πιο απαιτητική. Ο λόγος είναι ότι αντικείµενα τύπου
Image δεν µπορούν να µετατραπούν σε αντικείµενα τύπου BufferedImage. Το πιο δυνατό
ισοδύναµο είναι να δηµιουργηθεί ένα νέο BufferedImage αντικείµενο και να
«ζωγραφίσουµε» προγραµµατιστικά την εικόνα του Image αντικειµένου πάνω σε αυτό, και
αυτό ακριβώς υλοποιήσαµε παραπάνω.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
80
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Εφόσον οι δύο παραπάνω µέθοδοι τοποθετήθηκαν στο αρχείο DStave.java (και είναι
µάλιστα στατικές µέθοδοι) µένει το κοµµάτι που όταν µια νότα επιλέγεται να
µετατρέπονται τα pixel της από µαύρο χρώµα σε κόκκινο (ή κάποιο άλλο).
Στη γραµµή 180 του αρχείου DGrantStave.java εντοπίζεται η εντολή
g.drawImage(currImage, totalBeatWidth, pitchTempPos, this);
Σε συνεργασία µε τις εντολές
// draw notes and rests
for (int i = 0; i < phrase.size(); i++) {
int notePitchNum = (int) phrase.getNote(i).getPitch();
// choose graphic
chooseImage(notePitchNum, phrase.getNote(i).getRhythmValue(), 71, 60, 50);
που προϋπάρχουν και για κάθε νότα της µουσικής φράσης Phrase παίρνουν την αντίστοιχη
εικόνα µε την εντολή chooseImage και την αποθηκεύουν στη µεταβλητή currImage,
καταλαβαίνουµε ότι η εικόνα τύπου java.awt.Image περιέχει την εικόνα της κάθε νότας.
Έτσι πριν τη γραµµή 180 στο αρχείο DGrantStave.java τοποθετούµε το δικό µας κώδικα:
// Aimilia Grigorakaki – Euthimiou Michalitsa -> draw note/rest
if (currImage != null) {
if (i==getSelectedNote()) {
Note selected_note = phrase.getNote(i);//.getPitch();
BufferedImage bi = DStave.toBufferedImage(currImage);
int w = bi.getWidth();
int h = bi.getHeight();
int pixel;
BufferedImage biOut = new BufferedImage(w, h,
bi.TYPE_INT_ARGB_PRE);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
pixel = bi.getRGB(x, y);
if (pixel == (Color.BLACK).getRGB()) {
pixel = (Color.RED).getRGB();
}
biOut.setRGB(x, y, pixel);
}
}
currImage = DStave.toImage(biOut);
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
81
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Ουσιαστικά αυτό που κάνει το παραπάνω κοµµάτι κώδικα είναι να χρησιµοποιεί τις δύο
µεθόδους που δηµιουργήσαµε νωρίτερα. Αν η εικόνα δεν είναι null και είναι επιλεγµένη
από το χρήστη, τότε δηµιουργούµε ένα νέο BufferedImage αντικείµενο «ζωγραφίζοντας»
πάνω του το περιεχόµενο της αρχικής εικόνας όπως έχουµε περιγράψει παραπάνω.
Κατόπιν ανακαλύπτουµε το width και το height της νέας εικόνας και σαρώνοντας τα pixel
της εικόνας αυτής ένα-ένα, συγκρίνουµε το RGB (Red-Green-Blue) µε το RGB του
µαύρου χρώµατος (Color.BLACK) και αντικαθιστούµε τα pixels που είναι µαύρου
χρώµατος µε κόκκινα pixels.
Όταν η διαδικασία ολοκληρωθεί, τοποθετούµε ξανά την εικόνα από την BufferedImage
στη µεταβλητή currImage. Τώρα η εντολή:
g.drawImage(currImage, totalBeatWidth, pitchTempPos, this);
θα εµφανίσει στην οθόνη την κόκκινη εκδοχή της αντίστοιχης εικόνας για την επιλεγµένη
µόνο νότα της παρτιτούρας, όπως φαίνεται στο Σχήµα 6-25.
Σχήµα 6-25: Απεικόνιση επιλεγµένης νότας (αλλαγή χρώµατος).
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
82
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.7 Διάδραση ανάμεσα στην παρτιτούρα και την εικονική κιθάρα
Στο αρχείο DGrandStave στην προηγούµενη ενότητα έχουµε υλοποιήσει όταν κάποια νότα
επιλέγεται στην παρτιτούρα να χρωµατίζεται µε κόκκινο χρώµα. Σε αυτό ακριβώς το
σηµείο του κώδικα γνωρίζουµε ποια νότα έχει επιλεγεί. Προσθέτουµε λοιπόν µια γραµµή
κώδικα :
// Aimilia Grigorakaki – Euthimiou Michalitsa -> draw note/rest
if (currImage != null) {
if (i==getSelectedNote()) {
Note selected_note = phrase.getNote(i);//.getPitch();
GuitarNeck.getInstance().setNote(selected_note.getPitch());
Η τελευταία γραµµή θα εξυπηρετήσει ώστε στην εικονική κιθάρα να εµφανιστεί αµέσως η
αντίστοιχη νότα στο αντίστοιχο τάστο της κιθάρας. Για να γίνει όµως αυτό, πρέπει πρώτα
να εξηγήσουµε τις απαραίτητες αλλαγές στον κώδικα του κεφαλαίου 7.5 GuitarNeck.java.
Η πρώτη αλλαγή είναι η µετατροπή του αρχείου αυτού σε Singleton. Singleton [27] είναι
ένα Design Pattern [28] όπου αναγκάζουµε την εφαρµογή να διατηρεί ΜΟΝΟ ΕΝΑ
instance του αντικειµένου αυτού. Ενώ όλα τα αντικείµενα της Java µπορούν να
αρχικοποιηθούν πολλές φορές π.χ.
JButton button1 = new JButton();
JButton button2 = new JButton();
Τα Singleton αντικείµενα αρχικοποιούνται µόνο µια φορά, την πρώτη φορά που τα
αρχικοποιούµε. Πως το πετυχαίνουµε αυτό? Κάνουµε τον constructor του αντικειµένου
private, δηλαδή ένα αντικείµενο τέτοιου τύπου µπορεί να αρχικοποιηθεί µόνο από τον ίδιο
τον εαυτό του.
∆ηλαδή προγραµµατιστικά δεν µπορούµε να κάνουµε το
JButton button1 = new JButton();
επειδή το ‘new JButton()’ µέρος της παραπάνω εντολής κάνει χρήση του constructor του
αντικειµένου, που πλέον το µετατρέψαµε σε private.
Πώς θα αρχικοποιήσουµε όµως το αντικείµενο? ∆ηµιουργούµε µια µέθοδο µε το όνοµα
getInstance() η οποία αρχικοποιεί το αντικείµενο GuitarNeck. Παρακάτω φαίνεται ο
απαραίτητος κώδικας:
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
83
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
private static GuitarNeck reference;
public static GuitarNeck getInstance() {
if (reference==null) {
reference = new GuitarNeck();
}
return reference;
}
Έχουµε λοιπόν µια µεταβλητή µε το όνοµα reference. Όταν καλούµε τη µέθοδο
getInstance() την πρώτη φορά το reference είναι null οπότε θα αρχικοποιηθεί µέσω του
constructor το αντικείµενο. Αυτό µπορεί να γίνει και ας είναι ο constructor private επειδή ο
παραπάνω κώδικας βρίσκεται µέσα στο αρχείο GuitarNeck.java
To private δηλαδή «κρύβει» κάτι από όλα τα αντικείµενα εκτός από τον εαυτό του. Για να
συνεχίσουµε, την δεύτερη, τρίτη κ.ο.κ. φορά που ο χρήστης καλεί τη µέθοδο getInstance,
το reference δεν είναι πλέον null. Υπάρχει instance του αντικειµένου και το
επιστρέφουµε. To αντικείµενο GuitarNeck µε αυτόν τον τρόπο υπάρχει καµία, ή µια φορά
µόνο στη µνήµη.
Αυτή η µέθοδος ήταν µια από τις πολλές που θα µπορούσαµε να χρησιµοποιήσουµε για να
καταφέρουµε να υλοποιήσουµε µια σύνδεση ανάµεσα στην εικονική κιθάρα και στην
παρτιτούρα. Ένας άλλος τρόπος θα ήταν να χρησιµοποιούσαµε events. Όταν δηλαδή
επιλεγόταν µια νότα θα κάναµε fire ένα νέο event. Το GuitarNeck από την άλλη, θα έκανε
register σαν listener για events και «ακούγοντας» το νέο αυτό event θα αντιδρούσε
κατάλληλα.
Επειδή όµως οι παρτιτούρες είναι πολλές ενώ η εικονική κιθάρα µια και µοναδική η λύση
που επιλέξαµε µε τη µετατροπή του αντικειµένου σε Singleton καλύπτει εύκολα τις
ανάγκες της εφαρµογής.
Ο κώδικας του αντικειµένου GuitarNeck χρειάζεται µια νέα µέθοδο η οποία θα δέχεται σαν
είσοδο το pitch της επιλεγµένης νότας της παρτιτούρας και θα εµφανίζει τις αντίστοιχες
νότες στην εικονική κιθάρα. Η µέθοδος αυτή θα ονοµάζεται setNote και έχει τον παρακάτω
κώδικα:
public void setNote(int pitch)
clearAll();
int fret_1 = (pitch-77);
int fret_2 = (pitch-72);
int fret_3 = (pitch-68);
int fret_4 = (pitch-63);
int fret_5 = (pitch-58);
int fret_6 = (pitch-53);
{
//5
//4
//5
//5
//5
if (fret_1>=0 & fret_1<=21) {
fret_buttons[0][fret_1].setSelected(true);
}
if (fret_2>=0 & fret_2<=21) {
fret_buttons[1][fret_2].setSelected(true);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
84
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
if (fret_3>=0 & fret_3<=21) {
fret_buttons[2][fret_3].setSelected(true);
}
if (fret_4>=0 & fret_4<=21) {
fret_buttons[3][fret_4].setSelected(true);
}
if (fret_5>=0 & fret_5<=21) {
fret_buttons[4][fret_5].setSelected(true);
}
if (fret_6>=0 & fret_6<=21) {
fret_buttons[5][fret_6].setSelected(true);
}
}
Ο παραπάνω κώδικα πρώτα από όλα καλεί τη νέα µέθοδο clearAll();
public void clearAll() {
for (int string=0; string <= 5; string++) {
for (int i=0; i<fret_buttons[0].length; i++) {
fret_buttons[string][i].setSelected(false);
}
}
}
Η οποία αναλαµβάνει να «καθαρίσει» την εικονική κιθάρα από τις ενεργές νότες.
Αφού τρέξει η µέθοδος αυτή η εικονική κιθάρα είναι έτοιµη να απεικονίσει τη νότα της
παρτιτούρας. Όταν ο χρήστης επιλέγει µια νότα στην παρτιτούρα τρέχει η εντολή
GuitarNeck.getInstance().setNote(selected_note.getPitch());
Έχουµε σαν παράµετρο λοιπόν το pitch της νότας και θέλουµε να ανακαλύψουµε τη θέση
της κιθάρας που αντιστοιχεί στη νότα αυτή. Στην κιθάρα όµως οι νότες της παρτιτούρας
αντιστοιχούν σε αρκετά πιθανά σηµεία, για παράδειγµα χρησιµοποιώντας ένα on-line
εργαλείο [29] βλέπουµε ότι στη νότα Ε στην πρώτη γραµµή του πενταγράµµου στο
µουσικό κλειδί ΣΟΛ αντιστοιχεί το δεύτερο τάστο της 4ης χορδής της κιθάρας καθώς και
το 7ο της 5ης χορδής και το 12ο της 6ης χορδής (Σχήµα 6-26).
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
85
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-26: Αντιστοιχία νότας E της 1η γραµµής στην ταστιέρα της κιθάρας.
Το ίδιο θέλουµε να πετύχουµε από την εφαρµογή µας. Έτσι όταν στην παρτιτούρα
επιλέγεται η νότα Ε όπως φαίνεται στο Σχήµα 6-27, θέλουµε να εµφανίζεται η αντίστοιχη
νότα στο µπράτσο της κιθάρας.
Σχήµα 6-27: Αντιστοιχία νότας E της 1ης γραµµής στην εφαρµογή.
Το παραπάνω επιτεύχθηκε µε τη χρήση της γνώσης του pitch της νότας. Όταν µια νότα
έχει για pitch την τιµή 76 τότε αντιστοιχεί στην 1η χορδή της κιθάρας. Με τιµή 77
αντιστοιχεί στο πρώτο τάστο της 1ης χορδής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
86
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Ακολουθώντας τους µαθηµατικούς κανόνες που συνδέουν τις νότες µε τις αντίστοιχες
χορδές και τα τάστα καταλήξαµε στον απλό αλγόριθµο:
int
int
int
int
int
int
fret_1
fret_2
fret_3
fret_4
fret_5
fret_6
=
=
=
=
=
=
(pitch-77);
(pitch-72);
(pitch-68);
(pitch-63);
(pitch-58);
(pitch-53);
//5
//4
//5
//5
//5
H θέση του τάστου (frets) που πρέπει να χρησιµοποιήσει ο καλλιτέχνης µουσικός για να
παίξει µια νότα µπορεί να βρεθεί µε µια απλή αφαίρεση. Η αφαίρεση ανακαλύπτει τη θέση
αυτή. Αν η αφαίρεση επιστρέψει την τιµή 0 τότε µιλάµε για την ανοιχτή χορδή. Αν η τιµή
είναι µικρότερη ή ίση µε το 22 τότε υπάρχει θέση στη χορδή και η νότα εµφανίζεται στη
θέση αυτή.
Υπάρχουν νότες που µπορούν να παίχτουν σε περισσότερες από µια χορδές της κιθάρας.
Στην περίπτωση αυτή µια από τις θέσεις αυτές είναι η σύνηθες ενώ οι άλλες θεωρούνται
«alternatives» ή εναλλακτικές.
Στην εφαρµογή αυτή φαίνονται όλες οι πιθανές θέσεις στην κιθάρα όταν επιλέγονται στην
παρτιτούρα.
Ένα θέµα που δεν έχει αντιµετωπιστεί µέχρι τώρα είναι οι ανοιχτές χορδές, και η
υλοποίηση που επιλέχθηκε θα παρουσιαστεί στο επόµενο κεφάλαιο.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
87
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.8 Ανοιχτές χορδές
Για τις «ανοιχτές» χορδές, όταν δηλαδή η χορδή πρέπει να παίξει χωρίς τη χρήση τάστου
ένας πιο έξυπνος τρόπος υλοποίησης χρειαζόταν.
Η υλοποίηση που επιλέχθηκε είναι η παρακάτω: Με χρήση του PhotoShop
επεξεργαστήκαµε την εικόνα του µπράτσου της κιθάρας και επιλέξαµε συγκεκριµένα RGB
χρωµάτων για κάθε χορδή ξεχωριστά.
Σχήµα 6-28: Το RGB της πρώτης χορδής.
Σχήµα 6-29: Το RGB της δεύτερης χορδής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
88
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-30: Το RGB της τρίτης χορδής.
Σχήµα 6-31: Το RGB της τέταρτης χορδής.
Σχήµα 6-32: Το RGB της πέµπτης χορδής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
89
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-33: Το RGB της έκτης χορδής.
Έτσι η κάθε χορδή είναι ένα συγκεκριµένο RGB:
1η χορδή 241,255,255
2η χορδή 255,255,240
3η χορδή 255,255,230
4η χορδή 255,255,225
5η χορδή 255,255,220
6η χορδή 255,255,210
Χρησιµοποιώντας τις µεθόδους για color replacement που υλοποιήσαµε στο κεφάλαιο 7.6
µπορούµε πλέον να χρωµατίσουµε τις χορδές επειδή απεικονίζονται µε διακριτό RGB στην
εικόνα µε ένα έντονο κόκκινο χρώµα για να καταλάβει ο χρήστης ότι πρέπει να παίξει
απλά τη χορδή.
Σχήµα 6-34: Απεικόνιση 1ης χορδής ανοιχτής.
Σχήµα 6-35: Απεικόνιση 2ης χορδής ανοιχτής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
90
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-36: Απεικόνιση 3ης χορδής ανοιχτής.
Σχήµα 6-37: Απεικόνιση 4ης χορδής ανοιχτής.
Σχήµα 6-38: Απεικόνιση 5ης χορδής ανοιχτής.
Σχήµα 6-39: Απεικόνιση 6ης χορδής ανοιχτής.
Εφόσον η δοκιµή έγινε µε επιτυχία µε πρόχειρο κώδικα ήρθε η στιγµή να υλοποιηθεί µε
δηµιουργία µεθόδων ώστε να µπορούµε εύκολα να εµφανίσουµε όποια χορδή θέλουµε.
Στην αρχή του αντικειµένου τοποθετούµε τα χρώµατα που τοποθετήσαµε στις χορδές.
Color
Color
Color
Color
Color
Color
color_1st
color_2nd
color_3rd
color_4th
color_5th
color_6th
=
=
=
=
=
=
new
new
new
new
new
new
Color(241,255,255);
Color(255,255,240);
Color(255,255,230);
Color(255,255,225);
Color(255,255,220);
Color(255,255,210);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
91
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Κατόπιν δηµιουργούµε µέθοδο η οποία κάνει την απαραίτητη χρωµατική αλλαγή. Παίρνει
σαν παράµετρο τον αριθµό της χορδής (από 1 ως 6), εντοπίζει το χρώµα της χορδής, κάνει
τη χρωµατική αλλαγή και καλεί την repaint εντολή για να ανανεωθεί το γραφικό
περιβάλλον της εφαρµογής.
/**
* Switch the color of the string
* @param string values 1 to 6
*/
private void switchColor(int string) {
Color new_color;
switch (string) {
case 1: new_color = color_1st; break;
case 2: new_color = color_2nd; break;
case 3: new_color = color_3rd; break;
case 4: new_color = color_4th; break;
case 5: new_color = color_5th; break;
case 6: new_color = color_6th; break;
default: new_color = Color.black;
}
BufferedImage bi = DStave.toBufferedImage(ii.getImage());
int w = bi.getWidth();
int h = bi.getHeight();
int pixel;
BufferedImage biOut = new BufferedImage(w, h,
bi.TYPE_INT_ARGB_PRE);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
pixel = bi.getRGB(x, y);
if (pixel == (new_color).getRGB()) {
pixel = (Color.RED).getRGB();
}
biOut.setRGB(x, y, pixel);
}
}
ii = new ImageIcon(DStave.toImage(biOut));
repaint();
}
Στη συνέχεια πρέπει να προσέξουµε τη µέθοδο clearAll. Μέχρι τώρα «καθάριζε» την
εικονική κιθάρα από τις νότες. Τώρα η µέθοδος αυτή θα πρέπει να την «καθαρίζει» και
από τις επιλεγµένες-κοκκινισµένες χορδές. Έτσι η µέθοδος µετατρέπεται:
public void clearAll() {
for (int string=0; string <= 5; string++) {
for (int i=0; i<fret_buttons[0].length; i++) {
fret_buttons[string][i].setSelected(false);
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
92
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
String imgLocation2 = "images/GuitarNeck.png";
URL imageURL = GuitarNeck.class.getResource(imgLocation2);
ii = new ImageIcon(imageURL, "altText");
repaint();
}
Σε αυτό το σηµείο ολοκληρώνεται η φάση της υλοποίησης. Μάλιστα χρειάστηκαν µόλις
300 γραµµές κώδικα για την υλοποίηση τόσο της εικονικής κιθάρας όσο και της διεπαφής
της µε την παρτιτούρα. Παρακάτω παρουσιάζονται παραδείγµατα χρήσης της εφαρµογής,
όπως αυτή υλοποιήθηκε.
Σχήµα 6-40: Αντιστοιχία νότας Ε 4ου διαστήµατος στην εφαρµογή.
Στο Σχήµα 6-40 φαίνεται η αντιστοιχία του προγράµµατος που αναπτύξαµε µε τη θεωρία.
Η νότα Ε µπορεί να παιχτεί σαν «ανοιχτή πρώτη χορδή» ή στην 5η θέση της δεύτερης
χορδής ή στην 9η θέση της 3ης χορδής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
93
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-41: Αντιστοιχία νότας D στην εφαρµογή.
Στο Σχήµα 6-41 απεικονίζεται η αντιστοιχία της νότας D όπου η σωστή θέση της στην
κιθάρα είναι η ανοιχτή 3η χορδή ή η 5η θέση της 5ης χορδής ή η 10η θέση της 6ης χορδής.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
94
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-42: Αντιστοιχία νότας C - sharp στην εφαρµογή.
Επίσης εµφανίζονται σωστά και οι νότες µε σηµεία αλλοίωσης όπως π.χ. η δίεση (#) που
ανεβάζει το φθόγγο ένα ηµιτόνιο. Στο σχήµα 6-42 εµφανίζονται οι θέσεις που αντιστοιχούν
στην C-Sharp.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
95
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.9 Δημιουργία Ant Script
Για να µπορεί η εφαρµογή να πακεταριστεί όµορφα θα πρέπει όλα τα .class αρχεία µετά το
compilation να µπουν σε ένα αρχείο .JAR Για να γίνει αυτό πρέπει πρώτα από όλα να
δηµιουργηθεί ένα MANIFEST αρχείο [25]. Κατόπιν µελέτης το τελικό manifest.txt
ακολουθεί.
Manifest-Version: 2.0
Main-Class: diamouses.ui.scoreEditor.Main
Class-Path: jmusic.jar
Created-By: 1.5 (Sun Microsystems Inc.)
Name:
Specification-Title: @Name@
Specification-Version: @version@
Specification-Vendor: @vendor@
Implementation-Vendor: Aimilia
Implementation-Version: @version@
Implementation-Title: ScoreEditor
Το παραπάνω αρχείο περιγράφει πού θα βρεθεί η κύρια κλάση της εφαρµογής (δηλαδή στο
diamouses.ui.scoreEditor.Main) και ποιες βοηθητικές βιβλιοθήκες χρησιµοποιούνται
και απαιτούνται για να τρέξει η εφαρµογή (στην εφαρµογή της πτυχιακής αυτής εργασίας,
απαραίτητη είναι η ύπαρξη και χρήση της βιβλιοθήκης jmusic.jar).
Εφόσον δηµιουργηθεί το MANIFEST αρχείο, ένα ακόµα θέµα είναι ότι η εφαρµογή
ακολουθείται από ορισµένες εικόνες που πρέπει και αυτές να τοποθετηθούν στο .JAR Και
ενώ η εφαρµογή φόρτωνε αρχικά τις εικόνες κανονικά, όταν τοποθετούνταν µέσα σε .JAR
αρχείο δεν µπορούσε να τις εντοπίσει. Η λύση δόθηκε µε τη χρήση του
getClass().getClassLoader().getResource():
Όταν δηλαδή η εφαρµογή αποτελείται από .class αρχεία τότε µπορούµε να
χρησιµοποιήσουµε το filesystem ευθέως π.χ. URL url = “images/image.gif”. Όταν όµως
πακεταριστούν τα δεδοµένα µέσα σε ένα JAR αρχείο, που στην πράξη δεν είναι τίποτα
παραπάνω από ένα συµπιεσµένο αρχείο τύπου RAR, πρέπει να καλέσουµε την
getResource µέθοδο για να αποκτήσουµε πρόσβαση στα αρχεία που περικλείονται στο
αρχείο JAR.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
96
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Εφόσον οι παραπάνω προϋποθέσεις εκπληρώθηκαν (δηλαδή η δηµιουργία του
MANIFEST αρχείου, και οι απαραίτητες µετατροπές στον κώδικα της εφαρµογής) µε την
χρήση µιας σειράς µακροσκελών εντολών µπορούµε να κάνουµε compile τα αρχεία της
εργασίας και να τα τοποθετήσουµε µαζί µε τα υπόλοιπα αρχεία (εικόνες κτλ) σε ένα .JAR.
Για να αυτοµατοποιηθεί όµως η παραπάνω διαδικασία κατασκευής του αρχείου .JAR
αποφασίστηκε να χρησιµοποιηθεί ένα ant script file [26]. Ονοµάζεται build.xml και
βρίσκεται στο root κατάλογο του project.
Το ANT αποτελεί ένα open source project του Apache Foundation και είναι ένα εργαλείο
που βοηθάει στην αυτοµατοποίηση της διαδικασίας BUILD και packaging εφαρµογών
java.
Για να χρησιµοποιήσει κανείς το ANT αφού το εγκαταστήσει και το τοποθετήσει στο
PATH του λειτουργικού συστήµατος πρέπει να δηµιουργήσει ένα αρχείο XML, το
build.xml.
Το XML αυτό αρχείο αποτελείται από tasks, κάθε ένα από τα οποία κάνει µια
συγκεκριµένη εργασία. ∆ηµιουργήθηκε λοιπόν ένα build.xml αρχείο µε τα tasks που
παρουσιάζονται στον Πίνακα 6-1.
TASK NAME
Περιγραφή - Επεξήγηση
variables
Αρχικοποιεί
µεταβλητές
που
θα
χρησιµοποιηθούν
στη
συνέχεια της διαδικασίας του build, όπως βοηθητικές
βιβλιοθήκες, τοποθεσία φακέλων και εικόνων.
init
∆ηµιουργεί το φάκελο build/classes όπου
τα .class (τα compiled αρχεία), το φάκελο
θα τοποθετηθούν τα .JAR αρχεία και
φωτογραφίες
(images)
από
το
source
destination directory
compile
Κάνει compile τα αρχεία .java της εφαρµογής
jar
Πακετάρει τα αρχεία .class το Manifest.txt
εικόνες σε ένα αρχείο ScoreEditor.jar
clean
Σβήνει τους φακέλους /build/classes και /build/jars
«καθαρίζοντας» το περιβάλλον για δηµιουργία νέας έκδοσης
της εφαρµογής
run
θα τοποθετηθούν
build/jars όπου
αντιγράφει τις
directory
στο
και
τις
Εκτελεί την εφαρµογή
Πίνακας 6-1: Λίστα των tasks που υλοποιούνται στο αρχείο build.xml.
Τέλος πρέπει να ειπωθεί ότι ορισµένα tasks εξαρτούνται (depend) από άλλα tasks. ∆ηλαδή
για να τρέξει το jar-task το οποίο εξαρτάται από το init-task και το compile-task, τρέχουν
πρώτα τα απαραίτητα task και κατόπιν το jar-task.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
97
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
<?xml version="1.0"?>
<!-- ============================================================== -->
<!-- A Buildfile
-->
<!-- ============================================================== -->
<project name="ScoreEditor" default="jar" basedir=".">
<target name="variables">
<tstamp/>
<property name="Name"
value="ScoreEditor"/>
<property name="src.dir" value="${basedir}${file.separator}src"/>
<property name="lib.dir"
value="${basedir}${file.separator}libs"/>
<property name="build.dir"
value="${basedir}${file.separator}build"/>
<property name="build.classes"value="${build.dir}${file.separator}classes"/>
<property name="build.jar.dir" value="${build.dir}${file.separator}jars"/>
<property name="build.jar"
value="${build.jar.dir}${file.separator}${Name}.jar"/>
<property name="build.classpath"
value=".:${lib.dir}${file.separator}jmusic.jar"/>
<property name="images.src"
value="${src.dir}${file.separator}diamouses${file.separator}ui${file.sepa
rator}scoreEditor${file.separator}images"/>
<property name="images.dest"
value="${build.classes}${file.separator}diamouses${file.separator}ui${fil
e.separator}scoreEditor${file.separator}images"/>
<property name="packages"
value="*"/>
</target>
<!-- ============================================================== -->
<!-- Create required directories
-->
<!-- ============================================================== -->
<target name="init" depends="variables">
<!-- Prepare necessary directories -->
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes}"/>
<mkdir dir="${build.jar.dir}"/>
<mkdir dir="${images.dest}"/>
<!-- Copy all the images to the build directory -->
<copy todir="${images.dest}">
<fileset dir="${images.src}" casesensitive="yes">
<include name="**/*.*"/>
</fileset>
</copy>
</target>
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
98
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
<!-- ============================================================== -->
<!-- Compiles the source code
-->
<!-- ============================================================== -->
<target name="compile" depends="init" description="Compiles source
code">
<javac encoding="UTF-8"
srcdir="${src.dir}"
destdir="${build.classes}"
classpath="${build.classpath}"
optimize="on"
/>
</target>
<!-- ===============================================================-->
<!-- Creates a jar archive
-->
<!-- ============================================================== -->
<target name="jar" depends="init,compile" description="Generates
ScoreEditor.jar" >
<!-- Put everything from ${build.dir} into the ScoreEditor.jar file -->
<jar
manifest="${src.dir}/myManifest.txt"
jarfile="${build.jar.dir}${file.separator}${Name}.jar"
basedir="${build.classes}"
includes="**"
/>
<copy todir="${build.jar.dir}">
<fileset dir="${src.dir}" casesensitive="yes">
<include name="**/*.html"/>
</fileset>
</copy>
<copy todir="${build.jar.dir}">
<fileset dir="${lib.dir}" casesensitive="yes">
<include name="**/*.jar"/>
</fileset>
</copy>
</target>
<!-- ============================================================== -->
<!-- Cleans up all
-->
<!-- ============================================================== -->
<target name="clean" depends="init" description="Removes previous
build (classes and jar files)">
<delete dir="${build.classes}"/>
<delete dir="${build.jar.dir}"/>
</target>
<!-- ============================================================== -->
<!-- Run Score Editor
-->
<!-- ============================================================== -->
<target name="run" depends="init,compile,jar" description="Initiates
ScoreEditor.java">
<echo message = "Running ScoreEditor"/>
<java
jar="${build.jar.dir}${file.separator}${Name}.jar"
fork="true"
>
</java>
</target>
</project>
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
99
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Φαίνεται λοιπόν η jar εντολή που παίρνει σαν παράµετρο το myManifest.txt βρίσκει τα
.class αρχεία και τις εικόνες στο φάκελο που ενηµερώσαµε νωρίτερα και τα πακετάρει όλα
στο φάκελο build/jars στο αρχείο ScoreEditor.jar. Στον φάκελο αυτό τοποθετεί και το
jmusic.jar µιας και είναι απαραίτητο για την εφαρµογή της πτυχιακής αυτής εργασίας.
Με ‘ant –p’ βλέπουµε τα tasks που υποστηρίζονται από το script (βλέπε Σχήµα 6-43).
Σχήµα 6-43: Λίστα µε tasks που υποστηρίζει το script.
Με ‘ant clean’ διαγράφεται το προηγούµενο compilation της εφαρµογής (βλέπε Σχήµα
6-44).
Σχήµα 6-44: Απεικόνιση εκτέλεσης εντολής ‘ant clean’.
Και τέλος µε ‘ant jar’ γίνεται compile η εφαρµογή, αντιγράφονται οι εικόνες, και
τοποθετούνται όλα τα απαραίτητα αρχεία µαζί µε το myManifest.txt σε αρχείο µε όνοµα
ScoreEditor.jar όπως φαίνεται στο Σχήµα 6-45.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
100
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-45: Απεικόνιση εκτέλεσης εντολής ‘ant jar’.
Εφόσον τρέξει το task του ANT η εφαρµογή βρίσκεται πακεταρισµένη στον φάκελο
build/jars και µπορεί να τρέξει µε την εντολή ‘java -jar ScoreEditor.jar’ ή µε double-click
από το λειτουργικό σύστηµα.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
101
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.10 Μετατροπή εφαρμογής σε Applet
Για να τρέξει η εφαρµογή µέσα από µια ιστοσελίδα πρέπει να µετατραπεί σε Java Applet.
Εφόσον έχουµε ήδη εξηγήσει τη µέθοδο τοποθέτησης των interpreted αρχείων µε την
κατάληξη .class και των εικόνων σε αρχείο .JAR (κάτι που κρίνεται απαραίτητο ώστε η
εφαρµογή να µπορεί να τρέξει σαν Applet) προχωράµε στη συγγραφή του απαραίτητου
κώδικα HTML που δίνει τις κατάλληλες οδηγίες στον φυλλοµετρητή όπως µέγεθος του
Applet καθώς και την starting class:
<HTML>
<HEAD>
<TITLE>Εκµάθηση κιθάρας</TITLE>
<META content="MSHTML 5.50.4616.200" name=GENERATOR>
<link rel="stylesheet" href="css/styles.css" type="text/css">
</HEAD>
<BODY>
<applet code="diamouses.ui.scoreEditor.Main.class"
codebase="."
archive="ScoreEditor.jar"
width="1160" height="600">
Your browser is completely ignoring the &lt;APPLET&gt; tag!
</applet>
</center>
</BODY></HTML>
∆οκιµάζοντας από τοπικό υπολογιστή να ανοίξουµε το παραπάνω αρχείο το οποίο το
τοποθετούµε στον φάκελο µε τα δύο JAR αρχεία, το ένα της εφαρµογής µας και το άλλο
της βιβλιοθήκης JMusic, το Applet αρνείται να φορτώσει και εµφανίζεται ένα µήνυµα:
java.security.AccessControlException: access denied (java.lang.RuntimePermission)
Κοιτάζοντας πιο προσεκτικά εντοπίζουµε στην έβδοµη (7) γραµµή του exception ότι το
µήνυµα λάθους οφείλεται στη χρήση του JFrame.setDefaultCloseOperation. Βρίσκοντας το
σηµείο του κώδικα στο οποίο οφείλεται το λάθος καταλαβαίνουµε την αιτία:
Στα Applets η Java δεν επιτρέπει το κλείσιµο της Java Virtual Machine. O λόγος είναι ότι
επίδοξοι hackers θα χρησιµοποιούσαν αυτή τη δυνατότητα για να κάνουν DOS attacks
(Denial Of Service επιθέσεις σε περιηγητές του Ιστού).
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
102
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Το άνοιγµα και το κλείσιµο της Java Virtual Machine είναι µια σχετικά χρονοβόρα
διαδικασία η οποία καταναλώνει resources (τόσο µνήµη όσο και επεξεργαστή). Ένας
κακόβουλος χρήστης θα µπορούσε να γράψει απλά Applets που θα ανοιγόκλειναν την Java
Virtual Machine εκατοντάδες φορές το δευτερόλεπτο.
Αυτή η διαδικασία θα «κράσαρε» ακόµα και τα πιο σύγχρονα υπολογιστικά µηχανήµατα
των χρηστών, που επισκεπτόµενοι τη σελίδα αυτή δεν θα µπορούσαν να αποφύγουν την
παγίδα του κακόβουλου χρήστη. Για το σκοπό αυτό απαγορεύτηκε το κλείσιµο της JVM.
Στο Σχήµα 6-46 φαίνεται το µήνυµα λάθους.
Σχήµα 6-46: Μήνυµα λάθους της Java Console.
Εναλλακτικά µπορούµε να αντικαταστήσουµε τη γραµµή
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
µε τη γραµµή
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
Κατόπιν ξαναδηµιουργούµε το νέο JAR αρχείο που περιέχει τον ανανεωµένο κώδικα.
Αυτή τη φορά η εφαρµογή µας τρέχει σαν Application και στη θέση του Applet βρίσκουµε
µήνυµα λάθους που µας λέει:
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
103
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
java.lang.ClassCastException: diamouses.ui.scoreEditor.Main
java.applet.Applet (βλέπε Σχήµα 6-47) .
cannot
be
cast
to
Σχήµα 6-47: Exception: diamouses.ui.scoreEditor.Main cannot be cast to java.applet.Applet.
Η εφαρµογή χρειάζεται και άλλες αλλαγές για τη µετατροπή της σε Applet. Μέχρι τώρα η
Main έκανε extend το JFrame. Αυτό αναγκάζει την εφαρµογή να τρέξει σε νέο παράθυρο.
public class Main extends javax.swing.JFrame
έτσι η Main θα χρειαστεί πλέον να κάνει extend το JApplet. Ο λόγος είναι ότι επιθυµούµε
η εφαρµογή να τρέχει τόσο σαν Application όσο και σαν Applet την ίδια στιγµή. O τρόπος
που µπορεί να επιτευχθεί αυτό είναι να τοποθετήσουµε τον initialization κώδικα σε µέθοδο
µε την ονοµασία init και να καταργήσουµε τη χρήση του JFrame. Βέβαια αυτό απαιτεί
αλλαγές σε πολλά σηµεία του κώδικα. Αφού όµως κάναµε τις κατάλληλες τροποποιήσεις
τα οφέλη ήταν πολλαπλά.
Ένα ακόµα πρόβληµα που αντιµετωπίσαµε κατά τη µετατροπή του ScoreEditor σε Java
Applet ήταν η παράκαµψη των µηχανισµών ασφαλείας του sandbox της Java Virtual
Machine που απαγορεύει τη χρήση του JFileChooser για εγγραφή και ανάγνωση αρχείων
από τοπικό filesystem του χρήστη στον φυλλοµετρητή του οποίου τρέχει το Java Applet.
Όπως είπαµε η JVM για να προστατέψει τους χρήστες περιέχει έναν πολύ αυστηρό
µηχανισµό ασφαλείας ειδικά στα Applets για να αποτρέψει την κακόβουλη χρήση τους.
Παρέχει όµως µηχανισµούς για τροποποίηση των policy settings παρέχοντας µέσα από
πιστοποιητικά ασφαλείας και κατόπιν συναίνεσης του χρήστη priviledge escalation,
δηλαδή παροχή αυξηµένων δικαιωµάτων σε ένα applet.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
104
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Συγκεκριµένα 3 εργαλεία παρέχονται µαζί µε το JDK, τα:
• Keytool: ∆ηµιουργεί και κάνει manage κλειδιά ασφαλείας
• Jarsigner: Υπογράφει αρχεία JAR µε κάποιο κλειδί ασφαλείας που έχουµε ήδη
δηµιουργήσει.
• Policytool: Γραφικό περιβάλλον για διαχείριση πολιτικής ασφαλείας (policy
management).
Το πρώτο βήµα λοιπόν είναι να χρησιµοποιήσουµε το keytool και να δηµιουργήσουµε ένα
κλειδί ασφαλείας. Το εργαλείο αυτό δηµιουργεί κλειδιά βασισµένα στο πρωτόκολλο
X.509.
Το Χ.509 είναι ένα πρότυπο κρυπτογράφησης το οποίο σχεδιάστηκε για να παρέχει
υποδοµή πιστοποίησης. Η πρώτη έκδοση του X.509 δηµοσιεύθηκε το 1988, καθιστώντας
το την παλαιότερη πρόταση για µια παγκόσµια Υποδοµή ∆ηµόσιου Κλειδιού. Σε
συνδυασµό µε την υποστήριξη του προτύπου από τον ISO και από άλλους οργανισµούς
όπως τη ∆ιεθνή Ένωση Τηλεπικοινωνιών (International Telecommunications Union ITU), το X.509 έχει διεθνώς αναγνωριστεί. Αρκετά χρηµατοπιστωτικά ιδρύµατα
χρησιµοποιούν το X.509 για το πρότυπο ασφαλών συναλλαγών SET (Secure Electronic
Transactions). Με τα παραπάνω φαίνεται ότι αποτελεί ένα σοβαρό πρότυπο ασφαλείας και
για το λόγο αυτό χρησιµοποιείται από την Sun για πιστοποίηση στα Applets.
Για να δηµιουργήσουµε λοιπόν ένα κλειδί ασφαλείας, πληκτρολογούµε την παρακάτω
εντολή:
keytool -genkey -alias scoreeditor -keyalg rsa -validity 750
Ζητάµε δηλαδή τη δηµιουργία κλειδιού µε το alias scoreeditor µε χρήση του αλγορίθµου
RSA και µε διάρκεια ζωής 750 µέρες. Στο Σχήµα 6-48 που ακολουθεί µπορείτε να
παρατηρήσετε τα στοιχεία που συµπληρώνουµε και ακολουθούν το κλειδί ασφαλείας.
Σχήµα 6-48: Στοιχεία που ακολουθούν το κλειδί ασφαλείας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
105
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Εφόσον προετοιµάσαµε το κλειδί, αυτό τοποθετείται στο µηχανισµό που συγκρατεί τα
κλειδιά στον τοπικό υπολογιστή. ∆ηµιουργεί µάλιστα ένα αρχείο µε το όνοµα .keystore
(βλέπε Σχήµα 6-49) στο φάκελο user.home. ∆ηλαδή στο φάκελο:
C:\Documents and Settings\uName στα Windows XP
C:\Users\uName στα Windows Vista
Σχήµα 6-49: Αρχείο .keystore.
Για να τοποθετήσουµε το certificate στο φάκελο στον οποίο πατάµε την εντολή, πρέπει να
χρησιµοποιήσουµε την παράµετρο -keystore ορίζοντας το όνοµα του αρχείου που
επιθυµούµε να χρησιµοποιήσουµε.
Έτσι χρησιµοποιώντας την εντολή
keytool -genkey -alias score_editor -keyalg rsa -validity 750 keystore scoreeditor.cer
Θα δηµιουργηθεί το αρχείο scoreeditor.cer στον τρέχον φάκελο όπως φαίνεται στο Σχήµα
6-50.
Σχήµα 6-50: Αρχείο scoreeditor.cer.
Το επόµενο βήµα είναι να κάνουµε sign το JAR αρχείο µας µε το κλειδί που µόλις
δηµιουργήσαµε. Αφού το κάνουµε και αυτό προσπαθούµε να τρέξουµε το applet και να
σώσουµε ένα MIDI αρχείο στον τοπικό δίσκο του χρήστη. Παρατηρούµε όµως το εξής
µήνυµα λάθους.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
106
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Going to save score into file : C:\Users\Desktop\test.midi
-------------------- Writing MIDI File -----------------------------Converting to SMF data structure...
Part 0 'Untitled Part' to SMF Track on Ch. 0: Phrase 0:..
Exception in thread "AWT-EventQueue-2"
java.security.AccessControlException: access denied
(java.io.FilePermission C:\Users\Desktop\test.midi write)
at java.security.AccessControlContext.checkPermission(Unknown
Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
Ο Security Manager της Java Virtual Machine αρνείται να σώσει το αρχείο test.midi
παρόλο που το Applet µας είναι signed και ο χρήστης δέχεται την παροχή αυξηµένων
δικαιωµάτων. Μετά από αρκετό trial & error καταλάβαµε ότι πέρα από το Score_Editor.jar
πρέπει να κάνουµε sign και τη βοηθητική βιβλιοθήκη jmusic.jar
Έτσι συνολικά οι εντολές που πρέπει να πληκτρολογήσουµε για να πετύχουµε τον αρχικό
στόχο, την παροχή δικαιωµάτων εγγραφής στον τοπικό δίσκο είναι:
1.
2.
3.
4.
keytool -genkey -alias score_editor
keytool -export -alias score_edit -rfc -file score_editor_sig.x509
jarsigner ScoreEditor.jar score_editor
jarsigner jmusic.jar score_editor
Κατόπιν και χρησιµοποιώντας τα electronically signed applets, όταν ο χρήστης
επισκέπτεται τη σελίδα του εµφανίζεται το µήνυµα που παρουσιάζεται στο Σχήµα 6-51,
και πρέπει να επιλέξει ‘Run’, διαφορετικά δεν θα δώσει τα απαραίτητα δικαιώµατα στο
Applet.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
107
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-51: Μήνυµα στο χρήστη που αφορά τα δικαιώµατα του Applet.
Στο κάτω δεξιά µέρος της παραπάνω εικόνας υπάρχει ένα link µε την ονοµασία More
Information (βλέπε Σχήµα 6-52). Ο χρήστης επιλέγοντας το link αυτό µπορεί να δει
πληροφορίες σχετικές µε το πιστοποιητικό ασφαλείας. Μπορεί να δει δηλαδή τα στοιχεία
που συµπληρώσαµε όταν δηµιουργούσαµε το πιστοποιητικό αυτό. Πρώτα βέβαια
εµφανίζεται το παρακάτω µήνυµα που προειδοποιεί τον χρήστη για 2 πράγµατα: α) ότι αν
δεχθεί το πιστοποιητικό θα δώσει αυξηµένα δικαιώµατα σε remote applet και β) ότι το
συγκεκριµένο πιστοποιητικό είναι untrusted.
Θα µπορούσαµε να δηµιουργούσαµε ένα trusted πιστοποιητικό, αλλά αυτό προϋποθέτει
την πληρωµή µιας συνδροµής σε έναν από τους διεθνής αναγνωρισµένους οργανισµούς
που έχουν αναλάβει την παροχή trusted πιστοποιητικών µε ένα σχετικά µικρό κόστος. Στην
περίπτωση αυτή θα στέλναµε το public key στον οργανισµό αυτό (π.χ. VeriSign) και θα
µας το πιστοποιούσε αφού εξακρίβωνε τα πραγµατικά µας στοιχεία. To private key όµως
θα το κρατούσαµε εµείς κάνοντάς µας τους µοναδικούς που θα µπορούσαν να κάνουν sign
applets µε το συγκεκριµένο κλειδί - ηλεκτρονική υπογραφή µας. Κάτι τέτοιο όµως δεν
είναι απαραίτητο και δεν έγινε στα πλαίσια της πτυχιακής αυτής εργασίας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
108
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-52: Παράθυρο ‘More Information’.
Τέλος πατώντας ‘Certificate Details…’ µπορούµε να δούµε τα στοιχεία που συνοδεύουν το
πιστοποιητικό ασφαλείας, όωπς φαίνεται στο Σχήµα 6-53.
Σχήµα 6-53: Στοιχεία που συνοδεύουν το πιστοποιητικό ασφαλείας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
109
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Εν τέλει ο χρήστης µπορεί να αποθηκεύσει αρχεία στον τοπικό υπολογιστή του χρήστη και
να κάνει χρήση του JFileChooser component που φαίνεται στο Σχήµα 6-54.
Σχήµα 6-54: Απεικόνιση Save Dialog για αποθήκευση παρτιτούρας.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
110
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
6.11 Δημιουργία Ιστοσελίδας
Το Joomla [33] είναι ένα πλήρες σύστηµα διαχείρισης περιεχοµένου ανοιχτού κώδικα.
Είναι εφαρµογή η οποία µπορεί να καλύψει τις ανάγκες µιας προσωπικής ιστοσελίδας,
αλλά και ενός ολόκληρου δικτυακού τόπου. Είναι προσαρµόσιµο σε περιβάλλοντα
επιχειρηµατικής κλίµακας όπως τα intranets µεγάλων επιχειρήσεων ή οργανισµών, και οι
δυνατότητες επέκτασής του είναι πρακτικά απεριόριστες.
Το Joomla εγκαθίσταται σε έναν κεντρικό υπολογιστή, τον web server. Ο χρήστης διαχειριστής , έχει πρόσβαση στο περιβάλλον διαχείρισης του Joomla (βλέπε Σχήµα 6-55)
µέσω ενός browser, όπως είναι ο Internet Explorer ή ο Firefox, και µπορεί να προσθέσει
οποιοδήποτε κείµενο ή γραφικό ώστε να δηµιουργήσει την ιστοσελίδα του.
Σχήµα 6-55: Περιβάλλον διαχείρισης Joomla.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
111
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Το Joomla χρησιµοποιεί µια ισχυρή templating engine που µας δίνει την δυνατότητα να
χρησιµοποιήσουµε το template που επιθυµούµε. Έτσι, ψάχνοντας στον παγκόσµιο ιστό
βρήκαµε το template [34] που πληρούσε τις δικές µας προϋποθέσεις από αισθητικής
άποψης, και το εγκαταστήσαµε στο Joomla. Στη συνέχεια εργαστήκαµε στο υπάρχον
template αλλάζοντας από το αρχείο css [35] παραµέτρους που αφορούν την εµφάνιση.
Η τελική µορφή που πήρε το template της σελίδας µας απεικονίζεται στο Σχήµα 6-56.
Σχήµα 6-56: Template ιστοσελίδας.
Αφού ολοκληρώσαµε την επεξεργασία του template και γενικά της εµφάνισης που θα έχει
η ιστοσελίδα µας, προχωρήσαµε στο επόµενο βήµα που είναι η προσθήκη των υποσελίδων
που θα αποτελούν την δοµή της σελίδας. Αρχικά µέσα από το control panel του Joomla
ορίσαµε την εµφάνιση του κεντρικού µενού και έπειτα προσθέσαµε τα menu items που θα
απαρτίζουν το κεντρικό µενού της σελίδας µας, όπως φαίνεται στο Σχήµα 6-57.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
112
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-57: Κεντρικό µενού της σελίδας.
Αφού δηµιουργήσαµε το κεντρικό µενού της σελίδας ξεκινήσαµε να προσθέτουµε
περιεχόµενο σε κάθε υποσελίδα.
Κεντρική Σελίδα
Πηγαίνοντας στο µενού Content => Article Manager του Joomla µπορούµε να
διαχειριστούµε το περιεχόµενο κάθε υποσελίδας. Έτσι, η κεντρική σελίδα διαµορφώθηκε
όπως φαίνεται στο Σχήµα 6-58.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
113
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-58: Κεντρική σελίδα.
Είσοδος Στην Τάξη
Σε αυτή την σελίδα εργαστήκαµε διαφοτερικά διότι έπρεπε να ενσωµατώσουµε το applet
µέσα στο οποίο θα εµφανίζεται η εφαρµογή µας. Αφού γράψαµε τον κώδικα που ήταν
απαραίτητος για την εµφάνιση του applet σε µια html σελίδα προσθέσαµε ένα εισαγωγικό
κείµενο πριν την εφαρµογή, και ορίσαµε στο Joomla το Menu Item «Είσοδος στην τάξη»
ως Wrapper. Με αυτό τον τρόπο το Joomla δηµιουργεί ένα εσωτερικό πλαίσιο (iframe)
όπου µπορούµε να ενσωµατώσουµε µία εξωτερική σελίδα στη σελίδα µας. Έτσι εισάγουµε
το url της σελίδας (http://localhost/mysite/myapplet/application.php) στην οποία
εµφανίζουµε το applet και παίρνουµε το αποτέλεσµα που απεικονίζεται στο Σχήµα 6-59.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
114
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-59: Σελίδα ‘Είσοδος στην τάξη’.
Φόρουµ
Για το φόρουµ εργαστήκαµε ως εξής:
Αρχικά κατεβάσαµε και εγκαταστήσαµε στην ίδια βάση µε το Joomla, το phpBB3
("Olympus") forum [36] που είναι ένα forum ανοιχτού κώδικα. Μετά την εγκατάσταση του
phpBB3 στον υπολογιστή βλέπουµε τον πίνακα ελέγχου του διαχειριστή (ACP) του
φόρουµ (βλέπε Σχήµα 6-60).
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
115
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-60: Πίνακας ελέγχου διαχειριστή φόρουµ.
Έπειτα ψάξαµε στον παγκόσµιο ιστό το στυλ του φόρουµ που ταιριάζει στη σελίδα µας
και αφού το εγκαταστήσαµε το ορίσαµε ως default για το φόρουµ. Η ενσωµάτωση του
φόρουµ στη σελίδα έγινε µε παρόµοιο τρόπο όπως και στην σελίδα «Είσοδος Στην Τάξη».
∆ηλαδή ορίσαµε το Menu Item «Φόρουµ» ως Wrapper και βάλαµε το url του φόρουµ
phpBB3 που στήσαµε. Έτσι η σελίδα «Φόρουµ» διαµορφώθηκε όπως φαίνεται στο Σχήµα
6-61.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
116
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-61: Σελίδα ‘Φόρουµ’.
Τέλος, αποφασίσαµε η σελίδα να υποστηρίζει login χρηστών. Κάνοντας enabled το login
module του Joomla, εµφανίστηκε στην σελίδα η φόρµα εγγραφής που φαίνεται στο Σχήµα
6-62.
Αυτό είχε ως αποτέλεσµα κάθε φορά που ο χρήστης έκανε
login στη σελίδα να αναγκάζεται να κάνει login και στο
φόρουµ. Το πρόβληµα λύθηκε εγκαθιστώντας µια γέφυρα [37]
µεταξύ του Joomla και του phpBB3 forum. Με αυτό τον τρόπο
οι χρήστες κάνουν µια φορά login στη σελίδα και φαίνονται
συνδεδεµένοι και στο φόρουµ.
Σχήµα 6-62: Φόρµα εγγραφής
χρηστών.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
117
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Το phpBB3 forum µας δίνει τη δυνατότητα µέσω του πίνακα ελέγχου να δηµιουργήσουµε
νέες δηµόσιες συζητήσεις, να ορίσουµε τις προσβάσεις που θα έχουν οι οµάδες σε αυτές,
και τους ρόλους των οµάδων µελών. Επίσης µπορούµε να δηµιουργήσουµε νέες οµάδες
µελών και να ορίσουµε επιπλέον δυνατότητες σε αυτές. Συγκεκριµένα δηµιουργήσαµε δύο
νέες οµάδες, τις Καθηγητές και Μαθητές, και τις εξής δηµόσιες συζητήσεις:
-
Καλώς Ήρθατε
Θεωρία Ασκήσεις
Απορίες για τη θεωρία και τις ασκήσεις
Γενικά
Σε κάθε µία από αυτές τις δηµόσιες συζητήσεις ορίσαµε τα δικαιώµατα πρόσβασης
συνοψίζονται στον Πίνακα 6-2.
∆ηµόσια Συζήτηση
Θεωρία Ασκήσεις
Απορίες για τη θεωρία και τις
ασκήσεις
Γενικά
∆ικαιώµατα Πρόσβασης
µόνο οι καθηγητές έχουν τη δυνατότητα να
επισυνάπτουν αρχεία και µόνο οι µαθητές
µπορούν να µεταφορτώσουν τα αρχεία αυτά.
Επίσης µόνο οι καθηγητές µπορούν να
δηµιουργήσουν νέα θέµατα σε αυτή τη
δηµόσια συζήτηση
οι µαθητές µπορούν να συζητήσουν τις
απορίες που έχουν σχετικά µε τη θεωρία και
τις ασκήσεις που έχουν επισυνάψει οι
καθηγητές για αυτούς. Επίσης οι µαθητές
µπορούν να επισυνάψουν αρχεία ώστε να
διευκολύνουν τους καθηγητές και να λυθούν
ευκολότερα οι απορίες τους
µπορούν όλα τα µέλη να συζητήσουν γενικά
για ότι αφορά την κιθάρα. Οι επισκέπτες του
φόρουµ µπορούν µόνο να διαβάσουν τα
θέµατα που έχουν δηµοσιευτεί σε αυτή τη
δηµόσια συζήτηση. ∆εν έχουν όµως δικαίωµα
συµµετοχής στη συζήτηση µε την δηµιουργία
νέου θέµατος
Πίνακας 6-2: ∆ικαιώµατα πρόσβασης στις ∆ηµόσιες Συζητήσεις.
Βοήθεια
Στη «Βοήθεια» εργαστήκαµε όπως και στην «Κεντρική Σελίδα» και έτσι η σελίδα
διοµορφώθηκε όπως φαίνεται στο Σχήµα 6-63.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
118
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Σχήµα 6-63: Σελίδα ‘Βοήθεια’.
Επίπεδο πρόσβασης στις σελίδες
Το επίπεδο πρόσβασης των χρηστών στις σελίδες παρουσιάζεται στον Πίνακα 6-3.
Σελίδα
Κεντρική Σελίδα
Είσοδος στην Τάξη
Φόρουµ
Βοήθεια
Επίπεδο Πρόσβασης Χρηστών
∆ηµόσιο / Public
Μέλη / Registered
∆ηµόσιο / Public
Μέλη / Registered
Πίνακας 6-3: Επίπεδο πρόσβασης χρηστών στις σελίδες.
Όπως προκύπτει από τον πίνακα όλοι οι επισκέπτες της σελίδας έχουν πρόσβαση στην
κεντρική σελίδα και στο φόρουµ, ενώ οι εγγεγραµένοι χρήστες έχουν επιπλέον πρόσβαση
στην τάξη και στην βοήθεια.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
119
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
7. Σύνοψη και Συμπεράσματα
Με την εκπόνηση της πτυχιακής αυτής εργασίας, αποκτήσαµε γνώσεις σχετικά µε τον
αντικειµενοστραφή προγραµµατισµό χρησιµοποιώντας την Java. Ανακαλύψαµε τις
τεράστιες δυνατότητες που παρέχει ο αντικειµενοστραφής προγραµµατισµός, υλοποιώντας
απλές µεθόδους και κλάσεις, και δηµιουργώντας αντικείµενα.
Επίσης, µε την χρήση του εργαλείου Joomla διαπιστώσαµε την αξία ενός συστήµατος
διαχείρισης περιεχοµένου ιστοσελίδων. Χρησιµοποιώντας modules και components του
Joomla δηµιουργήσαµε την ιστοσελίδα που πληρούσε τις δικές µας απαιτήσεις και
προδιαγραφές, µε απλές διαδικασίες.
Η πτυχιακή αυτή εργασία µας εφοδίασε µε γνώσεις τόσο στον αντικειµενοστραφή
προγραµµατισµό, όσο και στον προγραµµατισµό ιστοσελίδων,
τις οποίες θα
αξιοποιήσουµε στην µελλοντική εργασία µας.
Οι δυνατότητες επέκτασης και βελτίωσης της πτυχιακής εργασίας είναι πολλές. Μπορεί να
αποτελέσει τη βάση ώστε να προστεθούν και άλλες εικονικές αναπαραστάσεις κιθάρας
(π.χ. ηλεκτρική κιθάρα). Έχουµε υλοποιήσει έτσι την εφαρµογή ώστε να µπορεί να
παραµετροποιηθεί εύκολα το αντικείµενο GuitarNeck και να καθιστά απλή µια τέτοια
βελτίωση. Επίσης, θα µπορούσαν να προστεθούν και άλλα µουσικά όργανα ώστε ο
χρήστης όταν επιλέγει ένα µουσικό όργανο να βλέπει και την αντίστοιχη απεικόνισή του.
Ακόµα, θα µπορούσε να βελτιωθεί το κουµπί play score, ώστε όταν ο χρήστης το πατάει,
για κάθε νότα που θα ακούγεται να εµφανίζεται η εκάστοτε θέση της στην εικονική
αναπαράσταση του µουσικού οργάνου.
Γενικά οι επεκτάσεις και οι βελτιώσεις της πτυχιακής εργασίας περιορίζονται µόνο από
την φαντασία του εκάστοτε προγραµµατιστή!
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
120
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
8. Βιβλιογραφία
[1] UML ∆ιαγράµµατα,
http://el.wikipedia.org/wiki/Γλώσσες_µοντελοποίησης_λογισµικού
[2] Βιβλιοθήκη ABC4J,
http://code.google.com/p/abc4j/
[3] ABC notation,
http://en.wikipedia.org/wiki/Abc_notation
[4] Using abc notation abc4j,
http://code.google.com/p/abc4j/wiki/JScore_Using_abc_notation
[5] Αρχεία MIDI,
http://el.wikipedia.org/wiki/MIDI
[6] ImproVisor,
http://www.cs.hmc.edu/~keller/jazz/improvisor/
[7] JFugue,
http://www.jfugue.org/
[8] Java MIDI Kit,
http://www.mcnabb.com/software/fantasia/index.html
[9] jMusic,
http://jmusic.ci.qut.edu.au/
[10] jFrets,
https://jfrets.dev.java.net/
[11] ABC BNF,
http://www.norbeck.nu/abc/abcbnf.htm
[12] The Complete Guide to JFugue,
http://www.jfugue.org/book.html
[13] Λίστα µε βιβλιοθήκες και πακέτα λογισµικού στη µουσική τεχνολογία,
http://www.softsynth.com/links/java_music.html
[14] Java Sound API,
http://java.sun.com/products/java-media/sound/
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
121
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
[15] Apple QuickTime,
http://www.apple.com/quicktime/
[16] MidiShare,
http://midishare.sourceforge.net/
[17] CodeSounding,
http://www.codesounding.org/
[18] Red Wine Music,
http://www.redwinemusic.com/
[19] JM-Etude,
http://jmetude.dihardja.de/
[20] CVS,
http://en.wikipedia.org/wiki/Concurrent_Versions_System
[21] Subversion,
http://subversion.tigris.org/
[22] NetBeans,
http://www.netbeans.org/
[23] Rational Rose,
http://www-01.ibm.com/software/rational/
[24] Κληρονοµικότητα,
http://www.cs.teilar.gr/gkakaron/java/Day2/8.html
[25] JAR File Specifications,
http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html
[26] Ant tool,
http://ant.apache.org/
[27] Singleton,
http://en.wikipedia.org/wiki/Singleton_pattern
[28] Design Patterns,
http://en.wikipedia.org/wiki/Design_pattern_(computer_science)
[29]Guitar note positioning,
http://www.ocmusic.com/trebleclef.htm
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
122
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
[30] Saving MIDI files in JMusic,
http://jmusic.ci.qut.edu.au/jmtutorial/jmDOSTute.html
[31] FileChoosers in Java,
http://java.sun.com/docs/books/tutorial/uiswing/components/filechooser.html
[32] Θεωρία µουσικής,
http://homepages.pathfinder.gr/papakrasas/diafora.htm
[33] Joomla,
http://joomla.org
[34] Template,
http://www.themza.com/joomla1.5/computer-society-template.html
[35] Cascading Style Sheets,
http://www.w3schools.com/css
[36] PhpBB3,
http://www.phpbb.com
[37] Γέφυρα Joomla – phpBB3,
http://www.rocketwerx.com/forum/viewtopic.php?f=22&t=368
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
123
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Παράρτημα 1
package diamouses.ui.scoreEditor;
import javax.swing.ImageIcon;
public final class
{
Constants
public ImageIcon a;
public ImageIcon asharp;
public ImageIcon b ;
public ImageIcon c;
public ImageIcon csharp;
public ImageIcon d;
public ImageIcon dsharp;
public ImageIcon e;
public ImageIcon f;
public ImageIcon fsharp;
public ImageIcon g;
public ImageIcon gsharp;
public Constants()
{
a = new ImageIcon(getClass().getResource("images/note_images/a.png"));
asharp = new
ImageIcon(getClass().getResource("images/note_images/asharp.png"));
b = new ImageIcon(getClass().getResource("images/note_images/b.png"));
c = new ImageIcon(getClass().getResource("images/note_images/c.png"));
csharp = new
ImageIcon(getClass().getResource("images/note_images/csharp.png"));
d = new ImageIcon(getClass().getResource("images/note_images/d.png"));
dsharp = new
ImageIcon(getClass().getResource("images/note_images/dsharp.png"));
e = new ImageIcon(getClass().getResource("images/note_images/e.png"));
f = new ImageIcon(getClass().getResource("images/note_images/f.png"));
fsharp = new
ImageIcon(getClass().getResource("images/note_images/fsharp.png"));
g = new ImageIcon(getClass().getResource("images/note_images/g.png"));
gsharp = new
ImageIcon(getClass().getResource("images/note_images/gsharp.png"));
e.setDescription("e");
f.setDescription("f");
fsharp.setDescription("fsharp");
g.setDescription("g");
gsharp.setDescription("gsharp");
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
124
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
a.setDescription("a");
asharp.setDescription("asharp");
b.setDescription("b");
c.setDescription("c");
csharp.setDescription("csharp");
d.setDescription("d");
dsharp.setDescription("dsharp");
}
}
=========================================================================
=========================================================================
package diamouses.ui.scoreEditor;
import
import
import
import
import
import
import
java.awt.Color;
java.awt.Dimension;
java.awt.Graphics;
java.awt.GridLayout;
java.awt.Toolkit;
java.awt.image.BufferedImage;
java.net.URL;
import
import
import
import
javax.swing.ImageIcon;
javax.swing.JFrame;
javax.swing.JPanel;
javax.swing.JToggleButton;
import diamouses.ui.scoreEditor.staves.DStave;
public class
GuitarNeck
extends JPanel {
/**
* Global variables for the application
*/
private int height = 28;
private int screen_width;
private JToggleButton [][] fret_buttons = new JToggleButton
[6][22];
private JPanel [] string_panels;
private JPanel fret_panel;
ImageIcon ii;
Color color_1st = new Color(241,255,255);
Color color_2nd = new Color(255,255,240);
Color color_3rd = new Color(255,255,230);
Color color_4th = new Color(255,255,225);
Color color_5th = new Color(255,255,220);
Color color_6th = new Color(255,255,210);
private static GuitarNeck reference;
/**
* Constructor.
* Initializes 6 JPanels, one for each guitar string
*/
private GuitarNeck(int screen_width) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
125
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
this.screen_width = screen_width;
// 0. Load background image
String imgLocation2 = "images/GuitarNeck.png";
URL imageURL = GuitarNeck.class.getResource(imgLocation2);
ii = new ImageIcon(imageURL, "altText");
// 1. Create six JPanels
fret_panel = getStringPanel();
// 2. Make them Not-Opaque (Make them TRANSPARENT)
fret_panel.setOpaque(false);
add(fret_panel);
setSizes();
}
public static GuitarNeck getInstance(int mm) {
if (reference==null) {
reference = new GuitarNeck(mm); // mm = 1160px
}
return reference;
}
public static GuitarNeck getInstance() {
return reference;
}
/**
* Method returns a JPanel with JButtons for each note of the
Guitar
* @param string First..Sixth string of the guitar
* @return a JPanel with appropriate JButtons
*/
private JPanel getStringPanel() {
JPanel main_panel = new JPanel();
ImageIcon [] string_images;
// Add each of the JPanel in a stack from top to bottom
main_panel .setLayout(new GridLayout(0,1,0,0));
string_panels = new JPanel [6];
for (int string = 0; string <= 5; string++) {
string_panels[string] = new JPanel();
string_panels[string].setOpaque(false);
string_images = getIconsForString(string);
for (int i = 0; i <= 21; i++) {
fret_buttons[string][i] = new JToggleButton();
fret_buttons[string][i].setContentAreaFilled(false);
fret_buttons[string][i].setBorderPainted(false);
fret_buttons[string][i].setOpaque(false);
fret_buttons[string][i].setIcon(new ImageIcon());
fret_buttons[string][i].setSelectedIcon(string_images
[i]);
string_panels[string].add(fret_buttons[string][i]);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
126
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
main_panel.add(string_panels[string]);
}
return main_panel;
}
/**
* This method sets the sizes of the JToggleButtons
*/
private void setSizes () {
int width;
for (int i = 0; i <= 21; i++) {
switch (i) {
case 0: width = 83; break;
case 1: width = 89; break;
case 2: width = 82; break;
case 3: width = 77; break;
case 4: width = 75; break;
case 5: width = 66; break;
case 6: width = 64; break;
case 7: width = 59; break;
case 8: width = 55; break;
case 9: width = 54; break;
case 10: width = 49; break;
case 11: width = 46; break;
case 12: width = 43; break;
case 13: width = 40; break;
case 14: width = 38; break;
case 15: width = 35; break;
case 16: width = 32; break;
case 17: width = 30; break;
case 18: width = 28; break;
case 19: width = 26; break;
case 20: width = 22; break;
default: width = 12; break;
}
width+=2;
width = screen_width*width/1280;
//string_1.setPreferredSize(new Dimension(width,height));
fret_buttons[0][i].setPreferredSize(new
height));
fret_buttons[1][i].setPreferredSize(new
height));
fret_buttons[2][i].setPreferredSize(new
height));
fret_buttons[3][i].setPreferredSize(new
height));
fret_buttons[4][i].setPreferredSize(new
height));
fret_buttons[5][i].setPreferredSize(new
height));
}
Dimension(width,
Dimension(width,
Dimension(width,
Dimension(width,
Dimension(width,
Dimension(width,
}
/**
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
127
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
* Method Paint the Guitar Neck on the Background of this JPanel.
*/
public void paintComponent(Graphics g) {
g.drawImage(ii.getImage(),0,0,this.getSize().width,this.getSize()
.height, this);
}
/**
* Switch the color of the string
* @param string values 1 to 6
*/
private void switchColor(int string) {
Color new_color;
switch (string) {
case 1: new_color = color_1st; break;
case 2: new_color = color_2nd; break;
case 3: new_color = color_3rd; break;
case 4: new_color = color_4th; break;
case 5: new_color = color_5th; break;
case 6: new_color = color_6th; break;
default: new_color = Color.black;
}
BufferedImage bi = DStave.toBufferedImage(ii.getImage());
int w = bi.getWidth();
int h = bi.getHeight();
int pixel;
BufferedImage biOut = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB_PRE);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
pixel = bi.getRGB(x, y);
if (pixel == (new_color).getRGB()) {
pixel = (Color.RED).getRGB();
}
biOut.setRGB(x, y, pixel);
}
}
ii = new ImageIcon(DStave.toImage(biOut));
repaint();
}
/**
* Method getIconsForString returns an Array [] of ImageIcons
* with the images of the appropriate Notes for each string of
* the Guitar.
*
* @param string An integer from 1 to 6 representing the
First..Sixth string
*
of a Guitar.
* @return an ImageIcon [] array.
*/
private ImageIcon [] getIconsForString( int string ) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
128
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Constants c = new Constants();
string+=1;
switch (string) {
//c.e,
case 1: ImageIcon [] string_1_notes = { c.f, c.fsharp, c.g,
c.gsharp,c.a,c.asharp,c.b, c.c,c.csharp,c.d,c.dsharp,c.e,c.f,
null, null, null, null,null,null,null,null,null};
return string_1_notes;
// c.b
case 2: ImageIcon [] string_2_notes = {c.c,c.csharp,c.d,
c.dsharp,c.e,c.f, c.fsharp, c.g, c.gsharp,c.a,c.asharp,c.b,
c.c,null,null, null, null,null,null,null,null,null};
return string_2_notes;
// c.g
case 3: ImageIcon [] string_3_notes =
{c.gsharp,c.a,c.asharp,c.b, c.c,c.csharp,c.d, c.dsharp,
c.e,c.f,c.fsharp, c.g, c.gsharp,null,null,null, null,
null,null,null,null,null};
return string_3_notes;
// c.d
case 4: ImageIcon [] string_4_notes = {c.dsharp,
c.e,c.f,c.fsharp, c.g, c.gsharp,c.a,c.asharp,c.b, c.c,
c.csharp,c.d, c.dsharp,null,null,null, null,
null,null,null,null,null};
return string_4_notes;
// c.a
case 5: ImageIcon [] string_5_notes = {c.asharp,c.b,
c.c,c.csharp,c.d,c.dsharp,c.e,c.f,c.fsharp, c.g,c.gsharp,c.a,
c.asharp,null,null,null, null, null,null,null,null,null};
return string_5_notes;
// c.e
case 6: ImageIcon [] string_6_notes = {c.f,c.fsharp, c.g,
c.gsharp,c.a,c.asharp,c.b,c.c,c.csharp,c.d,c.dsharp,c.e,c.f,
null,null, null, null,null,null,null,null,null};
return string_6_notes;
default: System.out.println("Errornous string " + string + "
in method GuitarFrame.getIconsForString");
return null;
}
}
/**
* Sets the note with a specific pitch on the virtual guitar
*
* @param pitch the pitch value.
*/
public void setNote(int pitch)
clearAll();
int fret_1 = (pitch-77);
int fret_2 = (pitch-72);
int fret_3 = (pitch-68);
int fret_4 = (pitch-63);
int fret_5 = (pitch-58);
int fret_6 = (pitch-53);
{
//5
//4
//5
//5
//5
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
129
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
if (fret_1>=0 & fret_1<=21) {
fret_buttons[0][fret_1].setSelected(true);
}
if (fret_2>=0 & fret_2<=21) {
fret_buttons[1][fret_2].setSelected(true);
}
if (fret_3>=0 & fret_3<=21) {
fret_buttons[2][fret_3].setSelected(true);
}
if (fret_4>=0 & fret_4<=21) {
fret_buttons[3][fret_4].setSelected(true);
}
if (fret_5>=0 & fret_5<=21) {
fret_buttons[4][fret_5].setSelected(true);
}
if (fret_6>=0 & fret_6<=21) {
fret_buttons[5][fret_6].setSelected(true);
}
if (fret_1==-1)
switchColor(1);
if (fret_2==-1)
switchColor(2);
if (fret_3==-1)
switchColor(3);
if (fret_4==-1)
switchColor(4);
if (fret_5==-1)
switchColor(5);
if (fret_6==-1)
switchColor(6);
}
public void clearAll() {
for (int string=0; string <= 5; string++) {
for (int i=0; i<fret_buttons[0].length; i++) {
fret_buttons[string][i].setSelected(false);
}
}
String imgLocation2 = "images/GuitarNeck.png";
URL imageURL = GuitarNeck.class.getResource(imgLocation2);
ii = new ImageIcon(imageURL, "altText");
repaint();
}
/**
*For testing
*/
/*public static void main(String[] args) {
JFrame f = new JFrame();
f.setVisible(true);
f.setExtendedState(JFrame.MAXIMIZED_HORIZ);
Toolkit kit = f.getToolkit();
Dimension screenSize = kit.getScreenSize();
int screenWidth = screenSize.width;
System.out.println("screenwidth" + screenWidth);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
130
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
GuitarNeck ff = GuitarNeck.getInstance(screenWidth);
f.getContentPane().add(ff);
f.pack();
}*/
}
=========================================================================
=========================================================================
package diamouses.ui.scoreEditor;
java.awt.BorderLayout;
java.awt.Dimension;
java.awt.Toolkit;
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
java.awt.event.KeyEvent;
java.io.File;
import
import
import
import
import
import
import
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import jm.music.data.Phrase;
import jm.music.data.Score;
import jm.util.Write;
import diamouses.ui.Metronome.Metronome;
/**
*
*/
public class
Main extends JApplet implements
ActionListener {
// Global Variables
private static ScoreEditor score;
/**
* Constructor
*/
public Main() {
//setJMenuBar(getJMenuBar());
//-System.out.println("screenwidth" + screenWidth);
}
public void init (){
score = new ScoreEditor();
//JFrame new_frame = new JFrame("Score Editor");
//setDefaultCloseOperation(javax.swing.WindowConstants.DISPOS
E_ON_CLOSE);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
131
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
setJMenuBar(getJMenuBar());
Toolkit kit = getToolkit();
Dimension screenSize = kit.getScreenSize();
int screenWidth = screenSize.width;
GuitarNeck ff = GuitarNeck.getInstance(screenWidth);
getContentPane().add(score, BorderLayout.CENTER);
getContentPane().add(score.getJToolBar(),
BorderLayout.PAGE_START);
getContentPane().add(ff, BorderLayout.SOUTH);
setVisible(true);
//setExtendedState(JFrame.MAXIMIZED_HORIZ);
//pack();
}
/**
* Creates a JMenuBar (File/Tools/Help) with appropriate
* menu items
*/
public JMenuBar getJMenuBar() {
// Local Variables
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// Create the menu bar.
menuBar = new JMenuBar();
// 1. Build the 'File' menu.
menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menuBar.add(menu);
// 'New Stave' MenuItem
menuItem = new JMenuItem("Clear Stave", KeyEvent.VK_N);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
ActionEvent.CTRL_MASK));
menuItem.setActionCommand("Clear_Stave");
menuItem.addActionListener(this);
menu.add(menuItem);
// 'Save Stave' MenuItem
menuItem = new JMenuItem("Save Stave"); //, new
ImageIcon("images/middle.gif"));
menuItem.setMnemonic(KeyEvent.VK_S);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
ActionEvent.CTRL_MASK));
menuItem.setActionCommand("Save_Stave");
menuItem.addActionListener(this);
menu.add(menuItem);
// Separator
menu.addSeparator();
// 'Play Stave' MenuItem
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
132
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
menuItem = new JMenuItem("Play Stave"); //, new
ImageIcon("images/middle.gif"));
menuItem.setMnemonic(KeyEvent.VK_P);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
ActionEvent.CTRL_MASK));
menuItem.setActionCommand("Play_Stave");
menuItem.addActionListener(this);
menu.add(menuItem);
// Separator
menu.addSeparator();
/* 'Exit' MenuItem
menuItem = new JMenuItem("Exit"); //, new
ImageIcon("images/middle.gif"));
menuItem.setMnemonic(KeyEvent.VK_X);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
ActionEvent.CTRL_MASK));
menuItem.setActionCommand("Exit");
menuItem.addActionListener(this);
menu.add(menuItem);
*/
// 2. Build 'Tools' menu
menu = new JMenu("Tools");
menu.setMnemonic(KeyEvent.VK_T);
menuBar.add(menu);
// 'Metronome' MenuItem
menuItem = new JMenuItem("Metronome", KeyEvent.VK_M);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M,
ActionEvent.CTRL_MASK));
menuItem.setActionCommand("Metronome");
menuItem.addActionListener(this);
menu.add(menuItem);
// 3. Build 'Help' menu
menu = new JMenu("Help");
menu.setMnemonic(KeyEvent.VK_H);
menuBar.add(menu);
// 'About' MenuItem
menuItem = new JMenuItem("About", KeyEvent.VK_A);
menuItem.setActionCommand("About");
menuItem.addActionListener(this);
menu.add(menuItem);
return menuBar;
}
/**
* Starting place of the application
* @param args
*/
public static void main(String args[]) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
133
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
JFrame f = new JFrame("Πτυχιακή ΤΕΙ Κρήτης - Ευθυµίου
Μιχαλίτσα, Γρηγορακάκη Αιµιλία");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet ap = new Main();
ap.init();
ap.start();
f.add("Center", ap);
f.pack();
f.setVisible(true);
/*java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
setDefault();
new Main().setVisible(true);
}
});
}*/
}
/**
* setDefault() , Sets the default Look and Feel. On Microsoft
Windows
* platforms, this specifies the Windows Look & Feel. On Mac OS
platforms,
* this specifies the Mac OS Look & Feel. On Sun platforms, it
specifies the
* CDE/Motif Look & Feel.
*
* With JDK1.4.2 upwards it sets the 'Luna' look and feel in Windows
XP and
* 'Bluecurve' in GNOME.
*/
public static void setDefault() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
;
} catch (java.lang.ClassNotFoundException classE) {
// Handle exception
} catch (java.lang.InstantiationException insE) {
// Handle exception
} catch (java.lang.IllegalAccessException illE) {
// Handle exception
} catch (javax.swing.UnsupportedLookAndFeelException unE) {
// Handle exception
}
}
public void actionPerformed(ActionEvent event) {
String action_command = event.getActionCommand();
if (action_command.equals("Metronome")) {
Metronome met = new Metronome(new JFrame(), null,
true);
met.setVisible(true);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
134
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
else if (action_command.equals("Clear_Stave")) {
score.stave.setPhrase(new Phrase());
}
else if (action_command.equals("Save_Stave")) {
String filename = File.separator+".midi";
JFileChooser fc = new JFileChooser(new
File(filename));
fc.setFileFilter(new MIDIFileFilter());
// Show save dialog; this method does not return until
the dialog is closed
fc.showSaveDialog(this);
File selected_file = fc.getSelectedFile();
String file_path = selected_file.toString();
if (!file_path.endsWith(".midi")) {
file_path += ".midi";
}
System.out.println("Goint to save score into file : " +
file_path);
Score s = new Score(score.getPart());
Write.midi(s, file_path);
}
else if (action_command.equals("Play_Stave")) {
score.playTune();
}
else if (action_command.equals("About")) {
JOptionPane.showMessageDialog(new JFrame(),
"Αυτή η εφαρµογή αναπτύχθηκε από τις
Γρηγορακάκη Αιµιλία και Ευθυµίου
Μιχαλίτσα,\n"+
"για την εκµάθηση κιθάρας\n"+
"Ctrl-N --> Νέα παρτιτούρα\n"+
"Ctrl-P --> Play tune\n" +
"Ctrl-M --> Show Metronome\n"+
//"Ctrl-X --> Exit",
"About the score-editor",
JOptionPane.INFORMATION_MESSAGE);
}
/*else if (action_command.equals("Exit")) {
this.dispose();
System.exit(0);
}*/
}
public static void setEnabledRemove(boolean b) {
score.setEnabledRemove(b);
// TODO Auto-generated method stub
}
class MIDIFileFilter extends FileFilter {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
135
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
public String getDescription() {
return "MIDI files (*.midi)";
}
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".midi");
}
}
}
=========================================================================
=========================================================================
package diamouses.ui.scoreEditor;
import
import
import
import
import
import
import
import
diamouses.ui.scoreEditor.staves.*;
java.awt.*;
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
java.net.URL;
java.util.Vector;
javax.swing.*;
javax.swing.border.*;
import
import
import
import
jm.music.data.Note;
jm.music.data.Part;
jm.music.data.Phrase;
jm.util.Play;
ScoreEditor extends JPanel implements
public class
ActionListener {
/** Private Variables **/
private JComboBox stave_selection_combobox;
protected DStave stave;
private JPanel scorePanel;
private JScrollPane scroll;
private String selectedInstrument = "Guitar (Clean)
private JButton remove_last_note_button,play_button ;
/**
* Constructor Creates new form ScoreEditor
**/
public ScoreEditor() {
027";
Phrase ph = new Phrase();
/*Vector<Note> notes = new Vector<Note>();
for (int i = 0; i < 40; i++) {
double min = 41;
double max = 78;
double pitch = (max - min) * Math.random() + min;
Note note1 = new Note((int) pitch, 2 * Math.random());
notes.add(note1);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
136
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
ph.addNoteList(notes, true);
DGrandStave dg_stave = new DGrandStave(ph);
*/
DGrandStave dg_stave = new DGrandStave();
stave = dg_stave;
stave.setTitle(selectedInstrument);
stave.setDisplayTitle(true);
scorePanel = new JPanel();
scorePanel.setBackground(Color.getHSBColor((float) 0.14,
(float) 0.09,(float) 1.0)); // .17, .1, 1
scorePanel.add(stave, BorderLayout.CENTER);
scroll = new JScrollPane(stave);
scroll.setViewportView(scorePanel);
setLayout(new BorderLayout());
add(scroll, BorderLayout.CENTER);
stave_selection_combobox = new JComboBox();
stave_selection_combobox.setModel(new
DefaultComboBoxModel(new String[] {"Grand Stave", "Treble
Stave", "Bass Stave" }));
stave_selection_combobox.setActionCommand("Select_Stave");
stave_selection_combobox.addActionListener(this);
stave_selection_combobox.setSelectedItem(1);
selectStave();
}
/**
* Method creates a "smart" JToggleButton
* @param imageName The location of the image of this toggle-button
* @param selected_imageName The location of the image of this
toggle-button
* when the toggle button is selected
* @param actionCommand The action-command to set for this
components
* @param toolTipText the tooltip of the component
* @param altText Alternative text in case the image is missing
* @return A JToggleButton component
*/
protected JToggleButton makeToggleButton(String imageName, String
selected_imageName,String actionCommand, String toolTipText, String
altText) {
// Look for the image.
String imgLocation = "images/menu_images/" + imageName +
".gif";
String imgLocation2 = "images/menu_images/" +
selected_imageName + ".gif";
URL imageURL = Main.class.getResource(imgLocation);
URL imageURL2 = Main.class.getResource(imgLocation2);
// Create and initialize the button.
JToggleButton button = new JToggleButton();
button.setActionCommand(actionCommand);
button.setToolTipText(toolTipText);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
137
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
button.addActionListener(this);
if ( (imageURL != null) & (imageURL2 != null) ){ // image
found
button.setIcon(new ImageIcon(imageURL, altText));
button.setSelectedIcon(new ImageIcon(imageURL2,
altText));
} else { // no image found
button.setText(altText);
System.err.println("Resource not found: " + imgLocation
+ "" + (imageURL==null) + " " + (imageURL2==null));
}
return button;
}
/**
* Method creates a "smart" JButton
* @param imageName The location of the image of this button
* @param actionCommand The action-command to set for this
components
* @param toolTipText the tooltip of the component
* @param altText Alternative text in case the image is missing
* @return A JButton component
*/
protected JButton makeButton(String imageName, String
actionCommand, String toolTipText, String altText) {
// Look for the image.
String imgLocation = "images/menu_images/" + imageName +
".gif";
URL imageURL = Main.class.getResource(imgLocation);
// Create and initialize the button.
JButton button = new JButton();
button.setActionCommand(actionCommand);
button.setToolTipText(toolTipText);
button.setText(toolTipText);
button.addActionListener(this);
(imageURL != null) { // image found
button.setIcon(new ImageIcon(imageURL, altText));
} else { // no image found
button.setText(altText);
System.err.println("Resource not found 2: " +
imgLocation);
}
return button;
if
}
/**
* Method creates and returns the top part of the Score-Editor with
the buttons
* @return the JPanel created with control buttons
*/
public JPanel getJToolBar() {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
138
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
// 1. Create the control panel
JButton new_stave, metronome_button;
new_stave = makeButton("clearscore", "Clear_Stave", "Clear
Stave","altText");
play_button = makeButton("play", "Play", "Play", "altText");
remove_last_note_button = makeButton("removelastnote",
"Remove_Last_Note","Remove Note", "altText");
remove_last_note_button.setEnabled(false);
play_button.setEnabled(false);
JPanel control_panel = new JPanel();
control_panel.setBorder(BorderFactory.createTitledBorder(null
, "Control Buttons", TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION, new Font("Tahoma", 0, 10)));
control_panel.add(new_stave);
control_panel.add(play_button);
control_panel.add(remove_last_note_button);
// 2. Create the NOTE selection panel
JPanel note_panel = new JPanel();
note_panel.setBorder(BorderFactory.createTitledBorder(null,
"Select Note", TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION, new Font("Tahoma", 0, 10)));
JToggleButton note16th_button, note_8th_button,
note_4th_button,note_Half_button, note_Full_button;
note16th_button =
makeToggleButton("semiquaverUp","semiquaverUp_selected",
"Note_16th","Semi quaver Up", "altText");
note_8th_button =
makeToggleButton("quaverUp","quaverUp_selected", "Note_8th",
"Quaver Up", "altText");
note_4th_button = makeToggleButton("crotchetUp",
"crotchetUp_selected", "Note_4th","Crotchet Up", "altText");
note_Half_button = makeToggleButton("minimUp",
"minimUp_selected", "Note_Half","Minim Up", "altText");
note_Full_button = makeToggleButton("semibreve",
"semibreve_selected","Whole","Semi Breve", "altText");
note_panel.add(note16th_button);
note_panel.add(note_8th_button);
note_panel.add(note_4th_button);
note_panel.add(note_Half_button);
note_panel.add(note_Full_button);
// 3. Create the REST selection panel
JPanel rest_panel = new JPanel();
rest_panel.setBorder(BorderFactory.createTitledBorder(null,
"Add Rest", TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION, new Font("Tahoma", 0, 10)));
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
139
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
JToggleButton semi_quaver_rest_button, quaver_rest_button,
crotchet_rest_button,minim_rest_button,
semibreve_rest_button;
semi_quaver_rest_button =
makeToggleButton("semiquaverRest","semiquaverRest",
"Rest_16th","Semi quarter Rest", "altText");
quaver_rest_button = makeToggleButton("quaverRest",
"quaverRest","Rest_8th","Quarter Rest", "altText");
crotchet_rest_button = makeToggleButton("crotchetRest",
"crotchetRest","Rest_4th","Crotchet Rest", "altText");
minim_rest_button = makeToggleButton("minimRest",
"minimRest","Rest_Half", "Minim Rest","altText");
semibreve_rest_button = makeToggleButton("semibreveRest",
"semibreveRest", "Rest_Whole","Semi breve Rest", "altText");
rest_panel.add(semi_quaver_rest_button);
rest_panel.add(quaver_rest_button);
rest_panel.add(crotchet_rest_button);
rest_panel.add(minim_rest_button);
rest_panel.add(semibreve_rest_button);
// 4. Only one Note or one Rest can be selected at a time,
// So add all toggle buttons in a button group
ButtonGroup group = new ButtonGroup();
group.add(note16th_button);
group.add(note_8th_button);
group.add(note_4th_button);
group.add(note_Half_button);
group.add(note_Full_button);
group.add(semi_quaver_rest_button);
group.add(quaver_rest_button);
group.add(crotchet_rest_button);
group.add(minim_rest_button);
group.add(semibreve_rest_button);
// 5. Add Instrument selection panel
JPanel instrument_selection = new JPanel();
instrument_selection.setBorder(BorderFactory.createTitledBord
er(null, "Options", TitledBorder.DEFAULT_JUSTIFICATION,
TitledBorder.DEFAULT_POSITION, new Font("Tahoma", 0, 10)));
JButton select_instrumnet_button =
makeButton("selectinstrument", "Show_Instrument_Dialog",
"Select Instrument", "altText");
instrument_selection.add(stave_selection_combobox);
instrument_selection.add(select_instrumnet_button);
JPanel main_panel = new JPanel();
main_panel.setLayout(new
BoxLayout(main_panel,BoxLayout.X_AXIS));
main_panel.add(control_panel);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
140
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
main_panel.add(note_panel);
main_panel.add(rest_panel);
main_panel.add(instrument_selection);
return main_panel;
}
/**
* Method to listen and react to actions
*/
public void actionPerformed(ActionEvent e) {
// Get the action-command associated with the event
String action_command = e.getActionCommand();
if (action_command.equals("Note_16th"))
stave.setNoteDuration(0.25);
else if (action_command.equals("Note_8th"))
stave.setNoteDuration(0.5);
else if (action_command.equals("Note_4th"))
stave.setNoteDuration(1.0);
else if (action_command.equals("Note_Half"))
stave.setNoteDuration(2.0);
else if (action_command.equals("Note_Whole"))
stave.setNoteDuration(4.0);
else if (action_command.equals("Rest_16th"))
setRest(0.25);
else if (action_command.equals("Rest_8th"))
setRest(0.5);
else if (action_command.equals("Rest_4th"))
setRest(1.0);
else if (action_command.equals("Rest_Half"))
setRest(2.0);
else if (action_command.equals("Rest_Whole"))
setRest(4.0);
else if (action_command.equals("Select_Instrument"))
selectStave();
else if (action_command.equals("Clear_Stave")) {
remove_last_note_button.setEnabled(false);
play_button .setEnabled(false);
stave.setPhrase(new Phrase());
}
else if (action_command.equals("Remove_Last_Note"))
removeLastNote();
else if (action_command.equals("Show_Instrument_Dialog"))
showInstrumentDialog();
else if (action_command.equals("Play"))
playTune();
}
public Part getPart() {
Phrase phr = stave.getPhrase();
Part part = new Part(phr);
String s = selectedInstrument;
s = s.substring(21, 24);
s.trim();
part.setInstrument(Integer.valueOf(s));
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
141
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
return part;
}
/**
* Method that plays the tune in the stave
*/
protected void playTune() {
Play.midi(getPart(), false);
}
/**
* Method that shows an Instrument Selection Dialog
*/
private void showInstrumentDialog() {
Object result = (Object) JOptionPane.showInputDialog(this,
"","Select instrument", JOptionPane.PLAIN_MESSAGE, null,
initializeInstrumentList(), selectedInstrument);
String s = null;
if (result instanceof String)
s = (String) result;
if (s != null) {
selectedInstrument = s;
stave.setTitle(s);
stave.repaint();
}
}
/**
* Method that removes last note in the stave
*/
private void removeLastNote() {
Phrase phrase = stave.getPhrase();
if (phrase.getSize()>0) {
phrase.removeLastNote();
stave.setPhrase(phrase);
if (phrase.getSize()==0) {
remove_last_note_button.setEnabled(false);
play_button.setEnabled(false);
}
}
}
/**
* Method that selects the stave
*/
private void selectStave() {
Phrase phr = stave.getPhrase();
String item = (String)
stave_selection_combobox.getSelectedItem();
scorePanel.remove(stave);
if (item.equalsIgnoreCase("Grand Stave")) {
stave = new DGrandStave(phr);
scorePanel.add(stave, BorderLayout.CENTER);
} else if (item.equalsIgnoreCase("Treble Stave")) {
stave = new DTrebleStave(phr);
scorePanel.add(stave, BorderLayout.CENTER);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
142
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
} else if (item.equalsIgnoreCase("Bass Stave")) {
stave = new DTrebleStave(phr);
scorePanel.add(stave, BorderLayout.CENTER);
}
stave.setTitle(selectedInstrument);
stave.setDisplayTitle(true);
scorePanel.repaint();
}
/**
* This method adds a new Rest if no Note is selected,
* or changes the selected note to a rest.
*
* @param rest_value Rest value is the value of the rest, in the
range:
* 4.0 (whole-rest) 2.0 (half-rest) 1.0 (quarter-rest)
* 0.5 (eight-rest) 0.25 (sixteenth-rest)
*/
private void setRest(double rest_value) {
Phrase phr = stave.getPhrase();
Note n;
if (stave.getSelectedNote() == -1) {
n = new Note(-2147483648, rest_value);
phr.add(n);
} else {
n = phr.getNote(stave.getSelectedNote());
n.setPitch(-2147483648);
n.setRhythmValue(rest_value);
}
remove_last_note_button.setEnabled(true);
stave.repaint();
}
/**
* Method returns an array of valid Guitar instruments
*/
private String [] initializeInstrumentList() {
String [] instrumentList = {
"Guitar (Clean)
027",
"Guitar (Distorted)
030",
"Guitar Harmonics
031",
"Guitar (Jazz)
026",
"Guitar (Muted)
028",
"Guitar (Nylon)
024",
"Guitar (Overdrive)
029",
"Guitar (Steel)
025" };
return instrumentList;
}
public void setEnabledRemove(boolean b) {
remove_last_note_button.setEnabled(b);
play_button.setEnabled(b);
}
}
=========================================================================
=========================================================================
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
143
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
package diamouses.ui.scoreEditor.staves;
import java.awt.*;
import java.awt.image.BufferedImage;
import diamouses.ui.scoreEditor.GuitarNeck;
import jm.JMC;
import jm.music.data.*;
public class
DBassStave extends DStave implements JMC {
public DBassStave() {
super();
staveDelta = staveSpaceHeight*11/2;
}
public DBassStave(Phrase phrase) {
super(phrase);
staveDelta = staveSpaceHeight*11/2;
}
public void paintComponent(Graphics graphics) {
// set up for double buffering
if (image == null) {
image = this.createImage(this.getSize().width,
this.getSize().height);
g = image.getGraphics();
}
g.setFont(font);
// keep track of the rhythmic values for bar lines
double beatCounter = 0.0;
// reset the chromatic vector
previouslyChromatic.removeAllElements();
// reste note position locations
notePositions.removeAllElements();
int keyAccidentals = 0;
// add a title if set to be visible
if (getDisplayTitle()) {
g.drawString(title, rightMargin, bPos - 10);
// insert key signature if required
}
int keyOffset = 0;
// is the key signature using sharps or flats?
if (keySignature > 0 && keySignature < 8) { // sharp
for (int ks = 0; ks < keySignature; ks++) {
// claulate position
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
144
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
int keyAccidentalPosition = notePosOffset[sharps[ks] %
12] + bPos - 4 + ((5 - sharps[ks] / 12) * 24) + ((6 sharps[ks] / 12) * 4);
// draw sharp
g.drawImage(sharp, rightMargin + clefWidth + keyOffset,
keyAccidentalPosition + staveSpaceHeight , this);
// indent position
keyOffset += 10;
//add note to accidental vector
int theModValue = sharps[ks] % 12;
for (int pc = 0; pc < 128; pc++) {
if ((pc % 12) == theModValue) {
previouslyChromatic.addElement(new Integer(pc));
keyAccidentals++;
}
}
keySigWidth = keyOffset;
}
} else {
if (keySignature < 0 && keySignature > -8) { // flat
for (int ks = 0; ks < Math.abs(keySignature); ks++) {
// claulate position
int keyAccidentalPosition = notePosOffset[flats[ks] %
12] + bPos - 4 + ((5 - flats[ks] / 12) * 24) + ((6 flats[ks] / 12) * 4);
// draw flat
g.drawImage(flat, rightMargin + clefWidth +
keyOffset, keyAccidentalPosition + staveSpaceHeight,
this);
// indent position
keyOffset += 10;
//add note to accidental vector
int theModValue = sharps[ks] % 12;
for (int pc = 0; pc < 128; pc++) {
if ((pc % 12) == theModValue) {
previouslyChromatic.addElement(new Integer(pc));
keyAccidentals++;
}
}
keySigWidth = keyOffset;
}
} else {
if (keySignature < 0 && keySignature > -8) { // flat
for (int ks = 0; ks < Math.abs(keySignature); ks++) {
// claulate position
int keyAccidentalPosition = notePosOffset[flats[ks] %
12] + bPos - 4 + ((5 - flats[ks] / 12) * 24) + ((6 flats[ks] / 12) * 4);
// draw flat
g.drawImage(flat, rightMargin + clefWidth +
keyOffset, keyAccidentalPosition + staveSpaceHeight,
this);
// indent position
keyOffset += 10;
//add note to accidental vector
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
145
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
int theModValue = flats[ks] % 12;
for (int pc = 0; pc < 128; pc++) {
if ((pc % 12) == theModValue) {
previouslyChromatic.addElement(new
Integer(pc));
keyAccidentals++;
}
}
}
}
}
keySigWidth = keyOffset + 3;
// insert time signature if required
if (metre != 0.0) {
Image[] numbers = {one, two, three, four, five, six, seven,
eight, nine};
// top number
g.drawImage(numbers[(int) metre - 1], rightMargin + clefWidth
+ keySigWidth, bPos + 13, this);
//bottom number
g.drawImage(four, rightMargin + clefWidth + keySigWidth, bPos
+ 29, this);
timeSigWidth = 30;
} else timeSigWidth = 5;
// set indent position for first note
totalBeatWidth = rightMargin + clefWidth + keySigWidth +
timeSigWidth;
// draw notes and rests
for (int i = 0; i < phrase.size(); i++) {
int notePitchNum = (int) phrase.getNote(i).getPitch();
// choose graphic
chooseImage(notePitchNum, phrase.getNote(i).getRhythmValue(),
50, 0, 50);
// reset pitch for rests
// position?
int pitchTempPos;
if (notePitchNum == REST ||
phrase.getNote(i).getRhythmValue() == 0.0) { // rest or
delete
pitchTempPos = notePosOffset[71 % 12] + bPos - 4 + ((5 - 71 /
12) * 24) + ((6 - 71 / 12) * 4);
} else {
pitchTempPos = notePosOffset[notePitchNum % 12] + bPos 4 + ((5 - notePitchNum / 12) * 24) + ((6 - notePitchNum
/ 12) * 4 – staveSpaceHeight * 6);
}
// accidental?
if (((notePitchNum % 12) == 1 || (notePitchNum % 12) == 3 ||
(notePitchNum % 12) == 6 || (notePitchNum % 12) == 8 ||
(notePitchNum % 12) == 10) && notePitchNum != REST &&
phrase.getNote(i).getRhythmValue() != 0.0) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
146
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
if (keySignature > -1) {
g.drawImage(sharp, totalBeatWidth - 9, pitchTempPos,
this);
previouslyChromatic.addElement(new
Integer(notePitchNum - 1)); // enter the note made
sharp i.e, F for an F#
} else { // flat
pitchTempPos -= 4; // to show the note a semitone
higher for flats
g.drawImage(flat, totalBeatWidth - 9, pitchTempPos,
this);
previouslyChromatic.addElement(new
Integer(notePitchNum + 1));
notePitchNum++; // assume it is a semitone higher for
legerlines etc...
}
} else { // check for a natural
// check vector
int size = previouslyChromatic.size();
for (int j = 0; j < size; j++) {
Integer temp = (Integer)
previouslyChromatic.elementAt(j);
if (temp.intValue() == notePitchNum && notePitchNum
!= REST && phrase.getNote(i).getRhythmValue() != 0.0)
{
// add natural
g.drawImage(natural, totalBeatWidth - 7,
pitchTempPos, this);
// remove element if not in key signature
if (j > keyAccidentals - 1) {
previouslyChromatic.removeElementAt(j);
}
j = size;
}
}
}
// draw note/rest
if (currImage != null) {
if (i==getSelectedNote()) {
Note selected_note =
phrase.getNote(i);//.getPitch();
GuitarNeck.getInstance().setNote(selected_note.getPitch());
//-System.out.println(selected_note.toString());
BufferedImage bi =
DStave.toBufferedImage(currImage);
int w = bi.getWidth();
int h = bi.getHeight();
int pixel;
BufferedImage biOut = new BufferedImage(w, h,
bi.TYPE_INT_ARGB_PRE);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
pixel = bi.getRGB(x, y);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
147
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
if (pixel == Color.BLACK).getRGB()) {
pixel = (Color.RED).getRGB();
}
biOut.setRGB(x, y, pixel);
}
}
currImage = DStave.toImage(biOut);
}
}
g.drawImage(currImage, totalBeatWidth, pitchTempPos, this);
// store position in a vector
notePositions.addElement(new Integer(totalBeatWidth));
notePositions.addElement(new Integer(pitchTempPos +
staveDelta)); // stave delta required for bass clef offset
from treble
//System.out.println("Position "+i+" "+totalBeatWidth + "
"+ pitchTempPos);
if (dottedNote) {
boolean dotFlag = true;
for (int l = 0; l < lineNotes.length; l++) {
if (lineNotes[l] + 12 == notePitchNum || lineNotes[l]
+ 36 == notePitchNum || lineNotes[l] + 60 ==
notePitchNum || lineNotes[l] + 84 == notePitchNum ||
lineNotes[l] + 108 == notePitchNum || notePitchNum ==
REST) {
g.drawImage(dot, totalBeatWidth + 1, pitchTempPos
- 4, this);
dotFlag = false;
l = lineNotes.length;
}
}
if (dotFlag) {
g.drawImage(dot, totalBeatWidth + 1, pitchTempPos,
this);
}
}
// leger lines down
if (notePitchNum <= 40 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 52, totalBeatWidth +
12, bPos + 52);
}
if (notePitchNum <= 37 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 60, totalBeatWidth +
12, bPos + 60);
}
if (notePitchNum <= 34 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 68, totalBeatWidth +
12, bPos + 68);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
148
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
if (notePitchNum <= 30 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 76, totalBeatWidth +
12, bPos + 76);
}
if (notePitchNum <= 26 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 84, totalBeatWidth +
12, bPos + 84);
}
// leger lines up
if (notePitchNum >= 60 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 4, totalBeatWidth + 12,
bPos + 4);
}
if (notePitchNum >= 64 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 4, totalBeatWidth + 12,
bPos - 4);
}
if (notePitchNum >= 67 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 12, totalBeatWidth +
12, bPos - 12);
}
if (notePitchNum >= 71 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 20, totalBeatWidth +
12, bPos - 20);
}
if (notePitchNum >= 74 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 28, totalBeatWidth +
12, bPos - 28);
// increment everything
totalBeatWidth += currBeatWidth;
dottedNote = false;
// quantised to semiquvers!
// (int)((phrase.getNote(i).getRhythmValue()/0.25) * 0.25);
beatCounter += (int) (phrase.getNote(i).getRhythmValue() /
0.25) * 0.25;
// add bar line if required
if (metre != 0.0) {
if ((beatCounter % metre) == 0.0) {
g.drawLine(totalBeatWidth, bPos + 12, totalBeatWidth,
bPos + 44);
// add bar numbers?
if (barNumbers) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
149
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
g.drawString("" + (int) (beatCounter / metre + 1
+ phrase.getStartTime()), totalBeatWidth - 4,
bPos);
}
totalBeatWidth += 12;
}
}
}
// draw stave
for (int i = 0; i < 5; i++) {
g.drawLine(rightMargin, (bPos + imageHeightOffset - (2 *
staveSpaceHeight)) + (i * staveSpaceHeight), totalBeatWidth,
(bPos + imageHeightOffset - (2 * staveSpaceHeight));
}
// draw next note stave area
// draw stave
g.setColor(Color.lightGray);
for (int i = 0; i < 5; i++) {
g.drawLine(totalBeatWidth,
(bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight),totalBeatWidth + 50,(bPos +
imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight));
}
g.setColor(Color.black);
// add Clef
g.drawImage(bassClef, rightMargin + 7, bPos, this);
/* Draw completed buffer to g */
graphics.drawImage(image, 0, 0, null);
// clear image
// clear
g.setColor(this.getBackground());
g.fillRect(0, 0, getSize().width, getSize().height);
g.setColor(this.getForeground());
//repaint();
//g.dispose();
}
}
=========================================================================
=========================================================================
package diamouses.ui.scoreEditor.staves;
import java.awt.*;
import java.awt.image.BufferedImage;
import diamouses.ui.scoreEditor.GuitarNeck;
import jm.JMC;
import jm.music.data.*;
public class
DGrandStave extends DStave implements JMC {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
150
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
public DGrandStave() {
super();
bPos = 110;
panelHeight = 310;
this.setSize((int) (beatWidth * spacingValue), panelHeight);
}
public DGrandStave(Phrase phrase) {
super(phrase);
bPos = 110;
panelHeight = 310;
this.setSize((int) (beatWidth * spacingValue), panelHeight);
}
public void paintComponent(Graphics graphics) {
// set up for double buffering
if (image == null) {
image = this.createImage(this.getSize().width,
this.getSize().height);
g = image.getGraphics();
}
g.setFont(font);
// keep track of the rhythmic values for bar lines
double beatCounter = 0.0;
// reset the chromatic vector
previouslyChromatic.removeAllElements();
// reste note position locations
notePositions.removeAllElements();
int keyAccidentals = 0;
// add a title if set to be visible
if (getDisplayTitle()) {
g.drawString(title, rightMargin, 60); //bPos - 10);
// insert key signature if required
}
int keyOffset = 0;
// is the key signature using sharps or flats?
if (keySignature > 0 && keySignature < 8) { // sharp
for (int ks = 0; ks < keySignature; ks++) {
// claulate position
int keyAccidentalPosition = notePosOffset[sharps[ks] %
12] + bPos - 4 + ((5 - sharps[ks] / 12) * 24) + ((6 sharps[ks] / 12) * 4);
// draw sharp on treble
g.drawImage(sharp, rightMargin + clefWidth + keyOffset,
keyAccidentalPosition, this);
// draw sharp on bass
g.drawImage(sharp, rightMargin + clefWidth + keyOffset,
keyAccidentalPosition + staveSpaceHeight * 7, this);
// indent position
keyOffset += 10;
//add note to accidental vector
int theModValue = sharps[ks] % 12;
for (int pc = 0; pc < 128; pc++) {
if ((pc % 12) == theModValue) {
previouslyChromatic.addElement(new Integer(pc));
keyAccidentals++;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
151
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
}
keySigWidth = keyOffset;
}
} else {
if (keySignature < 0 && keySignature > -8) { // flat
for (int ks = 0; ks < Math.abs(keySignature); ks++) {
// claulate position
int keyAccidentalPosition = notePosOffset[flats[ks] %
12] + bPos - 4 + ((5 - flats[ks] / 12) * 24) + ((6 flats[ks] / 12) * 4);
// draw flat
g.drawImage(flat, rightMargin + clefWidth +
keyOffset, keyAccidentalPosition, this);
// draw flat on bass stave
g.drawImage(flat, rightMargin + clefWidth +
keyOffset, keyAccidentalPosition + staveSpaceHeight *
7, this);
// indent position
keyOffset += 10;
//add note to accidental vector
int theModValue = flats[ks] % 12;
for (int pc = 0; pc < 128; pc++) {
if ((pc % 12) == theModValue) {
previouslyChromatic.addElement(new
Integer(pc));
keyAccidentals++;
}
}
}
}
}
keySigWidth = keyOffset + 3;
// insert time signature if required
if (metre != 0.0) {
Image[] numbers = {one, two, three, four, five, six, seven,
eight, nine};
// top number
g.drawImage(numbers[(int) metre - 1], rightMargin + clefWidth
+ keySigWidth, bPos + 13, this);
g.drawImage(numbers[(int) metre - 1], rightMargin + clefWidth
+ keySigWidth, bPos + 13 + staveSpaceHeight * 6, this);
//bottom number
g.drawImage(four, rightMargin + clefWidth + keySigWidth, bPos
+ 29, this);
g.drawImage(four, rightMargin + clefWidth + keySigWidth, bPos
+ 29 + staveSpaceHeight * 6, this);
timeSigWidth = 30;
} else {
timeSigWidth = 5;
// set indent position for first note
}
totalBeatWidth = rightMargin + clefWidth + keySigWidth +
timeSigWidth;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
152
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
// draw notes and rests
for (int i = 0; i < phrase.size(); i++) {
int notePitchNum = (int) phrase.getNote(i).getPitch();
// choose graphic
chooseImage(notePitchNum, phrase.getNote(i).getRhythmValue(),
71, 60, 50);
// reset pitch for rests
// position?
int pitchTempPos;
if (notePitchNum == REST ||
phrase.getNote(i).getRhythmValue() == 0.0) { // rest or
delete
pitchTempPos = notePosOffset[71 % 12] + bPos - 4 + ((5 - 71 /
12) * 24) + ((6 - 71 / 12) * 4);
} else {
pitchTempPos = notePosOffset[notePitchNum % 12] + bPos 4 + ((5 - notePitchNum / 12) * 24) + ((6 - notePitchNum
/ 12) * 4);
}
// accidental?
if (((notePitchNum % 12) == 1 || (notePitchNum % 12) == 3 ||
(notePitchNum % 12) == 6 || (notePitchNum % 12) == 8 ||
(notePitchNum % 12) == 10) && notePitchNum != REST &&
phrase.getNote(i).getRhythmValue() != 0.0) {
if (keySignature > -1) {
g.drawImage(sharp, totalBeatWidth - 9, pitchTempPos,
this);
previouslyChromatic.addElement(new
Integer(notePitchNum - 1)); // enter the note made
sharp i.e, F for an F#
} else { // flat
pitchTempPos -= 4; // to show the note a semitone
higher for flats
g.drawImage(flat, totalBeatWidth - 9, pitchTempPos,
this);
previouslyChromatic.addElement(new
Integer(notePitchNum + 1));
notePitchNum++; // assume it is a semitone higher for
legerlines etc...
}
} else { // check for a natural
// check vector
int size = previouslyChromatic.size();
for (int j = 0; j < size; j++) {
Integer temp = (Integer)
previouslyChromatic.elementAt(j);
if (temp.intValue() == notePitchNum && notePitchNum
!= REST && phrase.getNote(i).getRhythmValue() != 0.0)
{
// add natural
g.drawImage(natural, totalBeatWidth - 7,
pitchTempPos, this);
// remove element if not in key signature
if (j > keyAccidentals - 1) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
153
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
previouslyChromatic.removeElementAt(j);
}
j = size;
}
}
}
/* draw the selection line
if ((i >= getSelectedNote()) && (i <= getSelectedNote() +
getSelectedArea())) {
g.setColor(new Color(255, 0, 0));
g.drawLine(totalBeatWidth, 10, totalBeatWidth +
currImage.getWidth(this), 10);
g.drawLine(totalBeatWidth, 10, totalBeatWidth, 12);
g.drawLine(totalBeatWidth + currImage.getWidth(this), 10,
totalBeatWidth + currImage.getWidth(this), 12);
g.setColor(new Color(0, 0, 0));
}
*/
// draw note/rest
if (currImage != null) {
if (i==getSelectedNote()) {
Note selected_note =
phrase.getNote(i);//.getPitch();
GuitarNeck.getInstance().setNote(selected_note.getPitch());
//-System.out.println(selected_note.toString());
BufferedImage bi =
DStave.toBufferedImage(currImage);
int w = bi.getWidth();
int h = bi.getHeight();
int pixel;
BufferedImage biOut = new BufferedImage(w, h,
bi.TYPE_INT_ARGB_PRE);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
pixel = bi.getRGB(x, y);
if (pixel == (Color.BLACK).getRGB())
{
pixel = (Color.RED).getRGB();
}
biOut.setRGB(x, y, pixel);
}
}
currImage = DStave.toImage(biOut);
}
}
g.drawImage(currImage, totalBeatWidth, pitchTempPos, this);
// store position in a vector
notePositions.addElement(new Integer(totalBeatWidth));
notePositions.addElement(new Integer(pitchTempPos));
if (dottedNote) {
boolean dotFlag = true;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
154
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
for (int l = 0; l < lineNotes.length; l++) {
if (lineNotes[l] + 12 == notePitchNum || lineNotes[l]
+ 36 == notePitchNum || lineNotes[l] + 60 ==
notePitchNum || lineNotes[l] + 84 == notePitchNum ||
lineNotes[l] + 108 == notePitchNum || notePitchNum ==
REST) {
g.drawImage(dot, totalBeatWidth + 1, pitchTempPos
- 4, this);
dotFlag = false;
l = lineNotes.length;
}
}
if (dotFlag) {
g.drawImage(dot, totalBeatWidth + 1, pitchTempPos,
this);
}
}
// leger lines middle C
if (notePitchNum == 60 || notePitchNum == 61 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 52, totalBeatWidth +
12, bPos + 52);
}
// leger lines down
if (notePitchNum <= 40 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 100, totalBeatWidth
12, bPos + 100);
}
if (notePitchNum <= 37 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 108, totalBeatWidth
12, bPos + 108);
}
// leger lines down low
if (notePitchNum <= 16 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 156, totalBeatWidth
12, bPos + 156);
}
if (notePitchNum <= 13 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 164, totalBeatWidth
12, bPos + 164);
}
if (notePitchNum <= 10 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 172, totalBeatWidth
12, bPos + 172);
}
if (notePitchNum <= 6 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 180, totalBeatWidth
12, bPos + 180);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
+
+
+
+
+
+
155
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
if (notePitchNum <= 3 && notePitchNum > -1 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 188, totalBeatWidth +
12, bPos + 188);
}
// leger lines up
if (notePitchNum >= 81 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos + 4, totalBeatWidth + 12,
bPos + 4);
}
if (notePitchNum >= 84 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 4, totalBeatWidth + 12,
bPos - 4);
}
// leger lines up high
if (notePitchNum >= 105 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 52, totalBeatWidth +
12, bPos - 52);
}
if (notePitchNum >= 108 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 60, totalBeatWidth +
12, bPos - 60);
}
if (notePitchNum >= 112 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 68, totalBeatWidth +
12, bPos - 68);
}
if (notePitchNum >= 115 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 76, totalBeatWidth +
12, bPos - 76);
}
if (notePitchNum >= 119 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 84, totalBeatWidth +
12, bPos - 84);
}
if (notePitchNum >= 122 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 92, totalBeatWidth +
12, bPos - 92);
}
if (notePitchNum >= 125 && notePitchNum < 128 &&
phrase.getNote(i).getRhythmValue() != 0.0) {
g.drawLine(totalBeatWidth - 3, bPos - 100, totalBeatWidth +
12, bPos - 100);
}
// increment everything
totalBeatWidth += currBeatWidth;
dottedNote = false;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
156
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
// quantised to semiquvers!
beatCounter += (int) (phrase.getNote(i).getRhythmValue() /
0.25) * 0.25;
// add bar line if required
if (metre != 0.0) {
if ((beatCounter % metre) == 0.0) {
g.drawLine(totalBeatWidth, bPos + 12 staveSpaceHeight * 7, totalBeatWidth, bPos + 44 +
staveSpaceHeight * 13);
// add bar numbers?
if (barNumbers) {
g.drawString("" + (int) (beatCounter / metre + 1
+ phrase.getStartTime()), totalBeatWidth - 4,
bPos - 50);
}
totalBeatWidth += 12;
}
}
}
// draw treble stave
for (int i = 0; i < 5; i++) {
g.drawLine(rightMargin, (bPos + imageHeightOffset - (2 *
staveSpaceHeight)) + (i * staveSpaceHeight), totalBeatWidth,
(bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight));
}
// draw bass stave
for (int i = 6; i < 11; i++) {
g.drawLine(rightMargin, (bPos + imageHeightOffset - (2 *
staveSpaceHeight)) + (i * staveSpaceHeight), totalBeatWidth,
(bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight));
}
g.setColor(Color.darkGray);
// draw upper treble stave
for (int i = -7; i < -2; i++) {
g.drawLine(rightMargin, (bPos + imageHeightOffset - (2 *
staveSpaceHeight)) + (i * staveSpaceHeight), totalBeatWidth,
(bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight));
}
// draw lower bass stave
for (int i = 13; i < 18; i++) {
g.drawLine(rightMargin, (bPos + imageHeightOffset - (2 *
staveSpaceHeight)) + (i * staveSpaceHeight), totalBeatWidth,
(bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight));
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
157
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
// draw next note stave area
// draw stave
g.setColor(Color.lightGray);
for (int i = 0; i < 5; i++) {
g.drawLine(totalBeatWidth,
(bPos + imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight),totalBeatWidth + 50,(bPos +
imageHeightOffset - (2 * staveSpaceHeight)) + (i *
staveSpaceHeight));
}
for (int i = 6; i < 11; i++) {
g.drawLine(totalBeatWidth,(bPos + imageHeightOffset - (2 *
staveSpaceHeight)) + (i * staveSpaceHeight),
totalBeatWidth + 50,(bPos + imageHeightOffset - (2 *
staveSpaceHeight)) + (i * staveSpaceHeight));
}
g.setColor(Color.black);
// add Clefs
g.drawImage(trebleClef, rightMargin + 7, bPos - 4, this);
g.drawImage(bassClef, rightMargin + 7, bPos + staveSpaceHeight *
6, this);
/* Draw completed buffer to g */
graphics.drawImage(image, 0, 0, null);
// clear image
// clear
g.setColor(this.getBackground());
g.fillRect(0, 0, getSize().width, getSize().height);
g.setColor(this.getForeground());
//repaint();
//g.dispose();
}
}
=========================================================================
=========================================================================
package diamouses.ui.scoreEditor.staves;
import
import
import
import
java.awt.event.*;
java.awt.image.BufferedImage;
java.awt.*;
java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import
import
import
import
jm.JMC;
jm.gui.cpn.Images;
jm.gui.cpn.ToolkitImages;
jm.music.data.*;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
158
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
/**
* An AWT Component for displaying a Common Practice Notation stave.
*
* @author Andrew Brown, Adam Kirby
* @version 8th July 2001
*/
public abstract class
KeyListener {
DStave extends
JPanel implements JMC,
private int selectedNote = -1;
private int selectedArea = 0;
protected boolean requiresMoreThanOneImage = false;
protected double excessRhythmValue = 0.0;
protected boolean isUp = true;
protected boolean isNote = false;
// for double buffering
public Image image;
protected Graphics g;
// attributes
protected Image trebleClef, bassClef, crotchetUp, crotchetDown,
quaverDown, quaverUp,semiquaverDown, semiquaverUp, minimDown,
minimUp, semibreve, dot,semiquaverRest, quaverRest, crotchetRest,
minimRest, semibreveRest,sharp, flat, natural, one, two, three,
four, five, six, seven, eight, nine, delete, tieOver, tieUnder;
public int staveSpaceHeight = 8, rightMargin = 20, beatWidth = 43,
staveWidth = beatWidth*15,imageHeightOffset = 28, clefWidth = 38,
timeSigWidth = 5, keySigWidth = 5;
public int bPos = 28;
protected Phrase phrase;
protected Image currImage;
protected int currBeatWidth, totalBeatWidth;
protected boolean dottedNote = false;
protected int[] notePosOffset = {24,24,20,20,16,12,12,8,8,4,4,0}; //
chromatic scale
protected double metre = 4.0;
protected int keySignature = 0; // postive numbers = sharps, negative
numbers = flats
protected int[] sharps = {77, 72, 79, 74, 69, 76, 71};
protected int[] flats = {71, 76, 69, 74, 67, 72, 65};
protected Vector previouslyChromatic = new Vector();
protected int[] lineNotes = {0, 1, 4, 7, 8, 11, 14, 15, 17, 18, 21,
22};
public Vector notePositions = new Vector();
protected int maxPitch = 127, minPitch = 0;
protected String title;
protected boolean barNumbers = false, editable = true, qtOn = false;
protected int panelHeight = 110, staveDelta = 0;
protected boolean displayTitle = false;
protected Font font = new Font("Helvetica", Font.PLAIN, 10);
protected int spacingValue = 70;
private double noteDuration=1.0;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
159
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
// constructor
/**
* Constructs a new stave to display a blank Phrase using the default
stave
* images.
*/
public DStave() {
this(new Phrase(), new ToolkitImages());
}
/**
* Constructs a new stave to display the specified
<code>phrase</code> using
* the default stave images.
*
* @param phrase
Phrase to be displayed in stave
*/
public DStave(Phrase phrase) {
this(phrase, new ToolkitImages());
}
public int getSelectedNote(){
return selectedNote;
}
public void setSelectedNote(int note){
System.out.println("Selected note = " + note);
this.selectedNote=note;
}
public int getSelectedArea(){
return selectedArea;
}
public void setSelectedArea(int area){
this.selectedArea=area;
}
/**
* Constructs a new stave to display a blank Phrase using the
specified
* stave <code>images</code>.
*
* @param images
Images representing notes, rest and other stave
elements to use within the compenent
*/
public DStave(Images images) {
this(new Phrase(), images);
}
/**
* Constructs a new stave to display the specified
<code>phrase</code> using
* the specified stave <code>images</code>.
*
* @param phrase
Phrase to be displayed in stave
* @param images
Images representing notes, rest and other stave
elements to use within the compenent
*/
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
160
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
public DStave(Phrase phr, Images images) {
super();
title = phr.getTitle();
this.phrase = addRequiredRests(phr);
// change 'paper' colour
this.setBackground(Color.getHSBColor((float)0.14,(float)0.09,(flo
at)1.0)); // .17, .1, 1
// set the appropriate size (at least 8 bars of 4/4) for the stave
this.setSize((int)(beatWidth*spacingValue), panelHeight);
if (this.getSize().width < (int)(phrase.getEndTime()* beatWidth * 1.5) )
this.setSize( (int)(phrase.getEndTime()* beatWidth * 1.5), panelHeight);
// compensate for overly large images - pain!!
//if (this.getSize().width > 5000) {
// this.setSize(5000, panelHeight);
// System.out.println("Not all the phrase can be shown due to
overly large image requirements - sorry");
//}
//System.out.println("Max size is "+this.getMaximumSize().width
+" "+ this.getMaximumSize().height);
// register the listerners
DStaveActionHandler handleActions = new
DStaveActionHandler(this);
this.addMouseListener(handleActions);
this.addMouseMotionListener(handleActions);
// this.addKeyListener(handleActions);
trebleClef = images.getTrebleClef();
bassClef = images.getBassClef();
crotchetDown = images.getCrotchetDown();
crotchetUp = images.getCrotchetUp();
quaverDown = images.getQuaverDown();
quaverUp = images.getQuaverUp();
semiquaverDown = images.getSemiquaverDown();
semiquaverUp = images.getSemiquaverUp();
minimDown = images.getMinimDown();
minimUp = images.getMinimUp();
semibreve = images.getSemibreve();
dot = images.getDot();
semiquaverRest = images.getSemiquaverRest();
quaverRest = images.getQuaverRest();
crotchetRest = images.getCrotchetRest();
minimRest = images.getMinimRest();
semibreveRest = images.getSemibreveRest();
sharp = images.getSharp();
flat = images.getFlat();
natural = images.getNatural();
one = images.getOne();
two = images.getTwo();
three = images.getThree();
four = images.getFour();
five = images.getFive();
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
161
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
six = images.getSix();
seven = images.getSeven();
eight = images.getEight();
nine = images.getNine();
delete = images.getDelete();
tieOver = images.getTieOver();
tieUnder = images.getTieUnder();
}
/*
* Puts rests at the start of an phrase that does not
* start at time 0.0.
*/
public Phrase addRequiredRests(Phrase phrase) {
// add rests if required at the start
if (phrase.getStartTime() > 0.0) {
Phrase tempPhrase = new Phrase(0.0);
double remTime = phrase.getStartTime();
while(remTime >= 4.0) {
tempPhrase.addNote(REST, 4.0);
remTime -= 4.0;
}
while(remTime >= 1.0) {
tempPhrase.addNote(REST, 1.0);
remTime -= 1.0;
}
tempPhrase.addNote(REST, remTime);
jm.music.tools.Mod.append(tempPhrase, phrase);
phrase = tempPhrase;
}
return phrase;
}
/**
* Sets the current Phrase for this Stave instance
* @param Phrase
*/
public void setPhrase(Phrase phr) {
this.phrase = addRequiredRests(phr);
previouslyChromatic.removeAllElements();
//setTitle(phr.getTitle());
repaint();
}
/**
* Returns the current Phrase of this Stave instance
*/
public Phrase getPhrase() {
return this.phrase;
}
/**
* Sets the name for this Stave instance
* @param String Specify the title of the score
*/
public void setTitle(String title) {
this.title = title;
if(this.phrase != null) this.phrase.setTitle(title);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
162
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
/**
* Returns the name for this Stave instance
* @return String The title of the score
*/
public String getTitle() {
return title;
}
/**
* Emptys the name of this Stave instance
*/
public void removeTitle() {
this.title = null;
}
/**
* Show the title or not.
* @param value True or false
*/
public void setDisplayTitle(boolean value) {
this.displayTitle = value;
this.repaint();
}
/**
* Is the title displayed or not.
* @param value True or false
*/
public boolean getDisplayTitle() {
return this.displayTitle;
}
/**
* Return the recommended height for this stave.
*/
public int getPanelHeight() {
return panelHeight;
}
/**
* Sets the current metre for this Stave instance
* This effects the displayed time signature. 4.0 = 4/4 etc.
* @param double
*/
public void setMetre(double timeSig) {
/*
System.out.print("Time Sig =");
System.out.println(timeSig);
System.out.print("Numerator =");
System.out.println(phrase.getNumerator());
System.out.print("Denominator =");
System.out.println(phrase.getDenominator());
*/
this.metre = timeSig;
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
163
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
/**
* returns the current metre for this Stave instance as a double
*/
public double getMetre() {
return this.metre;
}
/**
* returns the current major key for this Stave instance as a integer
* 0 is C, 1 is C#/Db major, 2 is D major, etc
*/
public int getMajorKey() {
int[] keys = {11, 6, 1, 8, 3, 10, 5, 0, 7, 2, 9, 4, 11, 6, 1};
return keys[keySignature + 7];
}
/**
* Sets the current key signature for this Stave instance
* This effects the displayed key signature. 1 = F# etc.
* 0 is no key signature, + numbers for sharps, - numbers for flats
* @param int
*/
public void setKeySignature(int key) {
this.keySignature = key;
}
/**
* returns the current key signature for this Stave instance as a
double
*/
public int getKeySignature() {
return this.keySignature;
}
/**
* Decide to show bar numbers or not
* @param boolean
*/
public void setBarNumbers(boolean show) {
this.barNumbers = show;
}
/**
* Decide to allow stave to be editable or not
* @param boolean
*/
public void setEditable(boolean state) {
this.editable = state;
}
/**
* returns the current minimum MIDI pitch number
*/
public int getMinPitch() {
return this.minPitch;
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
164
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
/**
* Decide the minimum MIDI pitch number for this stave
* @param int
*/
public void setMinPitch(int min) {
this.minPitch = min;
}
/**
* returns the current maximum MIDI pitch number
*/
public int getMaxPitch() {
return this.maxPitch;
}
/**
* Decide the maxinum MIDI pitch number for this stave
* @param int
*/
public void setMaxPitch(int max) {
this.maxPitch = max;
}
/**
* Returns the current next note position in pixels
*/
public int getTotalBeatWidth() {
return this.totalBeatWidth;
}
/**
* Sets the current width of the stave in pixels
* @param int
*/
public void setTotalBeatWidth(int width) {
this.totalBeatWidth = width;
}
/**
* Returns the current state of barNumber showing
*/
public boolean getBarNumbers() {
return barNumbers;
}
/**
* Called by outer containers
*/
public Dimension getPreferredSize() {
return new Dimension( this.getSize().width, this.getSize().height);
}
/**
* Returns the current state of QuickTime Playback
*/
public boolean getQtOn() {
return qtOn;
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
165
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
/**
* Sets the current state of QuickTime
* @param boolean
*/
public void setQtOn(boolean state) {
this.qtOn = state;
}
/**
* Called by stave action on mouseUp
* Can be overridden by extending classes
* to add functionality
*/
public void updateChange() {}
// override update for double buffering
public void update(Graphics g) {
paintComponent(g);
};
public void paintComponent(Graphics graphics) {
// overridden by each class which extends Stave
}
/**
* Remove the last note from the phrase
*/
public void deleteLastNote() {
if(phrase.size() > 0) {
phrase.removeNote(phrase.size() -1);
repaint();
updateChange();
}
}
protected void chooseImage(int pitch,
double rhythmValue,
int upPitch1,
int downPitch,
int upPitch2) {
if (pitch == Note.REST) {
isNote = false;
if (rhythmValue <= 0.0) {
currImage = delete;
currBeatWidth = (int) (beatWidth * 0.5);
} else if (rhythmValue <= 0.2501) {
currImage = semiquaverRest;
currBeatWidth = (int) (beatWidth * 0.5);
} else if (rhythmValue <= 0.501) {
currImage = quaverRest;
currBeatWidth = (int) (beatWidth * (2.0 / 3.0));
} else if (rhythmValue <= 0.7501) {
currImage = quaverRest;
currBeatWidth = (int) (beatWidth * (2.0 / 3.0));
dottedNote = true;
} else if (rhythmValue <= 1.001) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
166
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
}
}
}
}
}
}
}
}
currImage = crotchetRest;
currBeatWidth = beatWidth;
else if (rhythmValue <= 1.2501) {
currImage = crotchetRest;
currBeatWidth = beatWidth;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 1.0;
else if (rhythmValue <= 1.501) {
currImage = crotchetRest;
currBeatWidth = (int) (beatWidth * 1.5);
dottedNote = true;
else if (rhythmValue <= 1.7501) {
currImage = crotchetRest;
currBeatWidth = (int) (beatWidth * 1.5);
dottedNote = true;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 1.5;
else if (rhythmValue <= 2.001) {
currImage = minimRest;
currBeatWidth = (int) (beatWidth * 1.7);
else if (rhythmValue <= 2.7501) {
currImage = minimRest;
currBeatWidth = (int) (beatWidth * 1.7);
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 2.0;
else if (rhythmValue <= 3.001) {
currImage = minimRest;
currBeatWidth = (int) (beatWidth * 1.9);
dottedNote = true;
else if (rhythmValue <= 3.7501) {
currImage = minimRest;
currBeatWidth = (int) (beatWidth * 1.9);
dottedNote = true;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 3.0;
else if (rhythmValue <= 4.001) {
currImage = semibreveRest;
currBeatWidth = (int) (beatWidth * 0.5);
else {
currImage = semibreveRest;
currBeatWidth = (int) (beatWidth * 0.5);
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 4.0;
}
} else { // a note rather than a rest
isNote = true;
if ((pitch < upPitch1 && pitch >= downPitch)
|| pitch < upPitch2 ) { // stems down
isUp = true;
if (rhythmValue <= 0.001) {
currImage = delete;
currBeatWidth = (int) (beatWidth * 0.5);
} else if (rhythmValue <= 0.2501) {
currImage = semiquaverUp;
currBeatWidth = (int) (beatWidth * 0.5);
} else if (rhythmValue <= 0.501) {
currImage = quaverUp;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
167
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
currBeatWidth = (int) (beatWidth * (2.0 / 3.0));
} else if (rhythmValue <= 0.7501) {
currImage = quaverUp;
currBeatWidth = (int) (beatWidth * 0.67);
dottedNote = true;
} else if (rhythmValue <= 1.001) {
currImage = crotchetUp;
currBeatWidth = beatWidth;
} else if (rhythmValue <= 1.2501) {
currImage = crotchetUp;
currBeatWidth = beatWidth;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 1.0;
} else if (rhythmValue <= 1.501) {
currImage = crotchetUp;
currBeatWidth = (int) (beatWidth * 1.5);
dottedNote = true;
} else if (rhythmValue <= 1.7501) {
currImage = crotchetUp;
currBeatWidth = (int) (beatWidth * 1.5);
dottedNote = true;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 1.5;
} else if (rhythmValue <= 2.001) {
currImage = minimUp;
currBeatWidth = (int) (beatWidth * 1.7);
} else if (rhythmValue <= 2.7501) {
currImage = minimUp;
currBeatWidth = (int) (beatWidth * 1.7);
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 2.0;
} else if (rhythmValue <= 3.001) {
currImage = minimUp;
currBeatWidth = (int) (beatWidth * 1.9);
dottedNote = true;
} else if (rhythmValue <= 3.7501) {
currImage = minimUp;
currBeatWidth = (int) (beatWidth * 1.9);
dottedNote = true;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 3.0;
} else if (rhythmValue <= 4.001) {
currImage = semibreve;
currBeatWidth = (int) (beatWidth * 2.25);
} else {
currImage = semibreve;
currBeatWidth = (int) (beatWidth * 2.25);
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 4.0;
}
} else { // stem down
isUp = false;
if (rhythmValue <= 0.001) {
currImage = delete;
currBeatWidth = (int) (beatWidth * 0.5);
} else if (rhythmValue <= 0.2501) {
currImage = semiquaverDown;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
168
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
currBeatWidth = (int) (beatWidth * 0.5);
} else if (rhythmValue <= 0.501) {
currImage = quaverDown;
currBeatWidth = (int) (beatWidth * (2.0 / 3.0));
} else if (rhythmValue <= 0.7501) {
currImage = quaverDown;
currBeatWidth = (int) (beatWidth * (2.0 / 3.0));
dottedNote = true;
} else if (rhythmValue <= 1.001) {
currImage = crotchetDown;
currBeatWidth = beatWidth;
} else if (rhythmValue <= 1.2501) {
currImage = crotchetDown;
currBeatWidth = beatWidth;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 1.0;
} else if (rhythmValue <= 1.501) {
currImage = crotchetDown;
currBeatWidth = (int) (beatWidth * 1.5);
dottedNote = true;
} else if (rhythmValue <= 1.7501) {
currImage = crotchetDown;
currBeatWidth = (int) (beatWidth * 1.5);
dottedNote = true;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 1.5;
} else if (rhythmValue <= 2.001) {
currImage = minimDown;
currBeatWidth = (int) (beatWidth * 1.7);
} else if (rhythmValue <= 2.7501) {
currImage = minimDown;
currBeatWidth = (int) (beatWidth * 1.7);
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 2.0;
} else if (rhythmValue <= 3.001) {
currImage = minimDown;
currBeatWidth = (int) (beatWidth * 1.9);
dottedNote = true;
} else if (rhythmValue <= 3.7501) {
currImage = minimDown;
currBeatWidth = (int) (beatWidth * 1.9);
dottedNote = true;
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 3.0;
} else if (rhythmValue <= 4.001) {
currImage = semibreve;
currBeatWidth = (int) (beatWidth * 2.25);
} else {
currImage = semibreve;
currBeatWidth = (int) (beatWidth * 2.25);
requiresMoreThanOneImage = true;
excessRhythmValue = rhythmValue - 4.0;
}
}
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
169
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
System.out.println(e.getKeyChar());
}
public double getNoteDuration(){
return this.noteDuration;
}
public void setNoteDuration(double noteDuration){
this.noteDuration=noteDuration;
}
// This method returns a buffered image with the contents of an image
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage)image;
}
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels; for this
method's
// implementation, see e661 Determining If an Image Has
Transparent Pixels
// Create a buffered image with a format that's compatible with
the screen
BufferedImage bimage = null;
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered
image
// int transparency = Transparency.OPAQUE;
//boolean hasAlpha = hasAlpha(image);
//if (hasAlpha) {
int transparency = Transparency.BITMASK;
//}
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(
image.getWidth(null), image.getHeight(null),
transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
// Create a buffered image using the default color model
//int type = BufferedImage.TYPE_INT_RGB;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
170
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
//if (hasAlpha) {
int type = BufferedImage.TYPE_INT_ARGB;
//}
bimage = new BufferedImage(image.getWidth(null),
image.getHeight(null), type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
// This method returns an Image object from a buffered image
public static Image toImage(BufferedImage bufferedImage) {
return
Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource());
}
}
=========================================================================
=========================================================================
package diamouses.ui.scoreEditor.staves;
import
import
import
import
import
import
import
import
import
import
import
java.awt.Cursor;
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
java.awt.event.InputEvent;
java.awt.event.KeyEvent;
java.awt.event.KeyListener;
java.awt.event.MouseEvent;
java.awt.event.MouseListener;
java.awt.event.MouseMotionListener;
javax.swing.JMenuItem;
javax.swing.JPopupMenu;
import
import
import
import
diamouses.ui.scoreEditor.Main;
jm.JMC;
jm.music.data.Note;
jm.music.data.Phrase;
DStaveActionHandler
public class
implements JMC,
MouseListener, MouseMotionListener, ActionListener, KeyListener {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
171
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
private DStave theApp;
private int selectedNote = -1;
private boolean topTimeSelected = false, keySelected = false;
private int clickedPosY, clickedPosX, storedPitch = 72;
private double[] rhythmValues = {104.0, 103.0, 102.0, 101.5, 101.0,
100.75,100.5, 100.25, 0.0, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0,
4.0};
private boolean button1Down = false;
private JPopupMenu
noteContextMenu;
private JMenuItem
editNote,
repeatNote,
makeRest,
deleteNote,
// constructor
DStaveActionHandler(DStave stave) {
theApp = stave;
noteContextMenu = new JPopupMenu();
repeatNote = new JMenuItem("Repeat Note");
repeatNote.addActionListener(this);
noteContextMenu.add(repeatNote );
makeRest = new JMenuItem("Change to Rest");
makeRest.addActionListener(this);
noteContextMenu.add(makeRest);
deleteNote = new JMenuItem("Delete Note");
deleteNote.addActionListener(this);
noteContextMenu.add(deleteNote );
theApp.add(noteContextMenu);
}
boolean inNoteArea( MouseEvent e ) {
Integer lastX;
if (theApp.notePositions.size() < 2) {
lastX = new Integer(theApp.getTotalBeatWidth() );
} else {
lastX =
(Integer)theApp.notePositions.elementAt(theApp.notePositions.
size() -2);
}
return (e.getX() <= lastX.intValue() + 15) &&
(e.getX() < theApp.getTotalBeatWidth() + 50);
}
private void searchForSelectedNote(MouseEvent e) {
Integer tempX;
Integer tempY;
for(int i=0;i< theApp.notePositions.size(); i += 2) {
tempX = (Integer)theApp.notePositions.elementAt(i);
tempY = (Integer)theApp.notePositions.elementAt(i+1);
if((e.getX() > tempX.intValue()) &&
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
172
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
(e.getX() < tempX.intValue() + 15) &&
( e.getY() + theApp.staveDelta >
tempY.intValue() + 22) &&
(e.getY() + theApp.staveDelta <
tempY.intValue()+35)){
selectedNote = i/2;
clickedPosY = e.getY() + theApp.staveDelta;
clickedPosX = e.getX();
// get out of loop ASAP
i = theApp.notePositions.size();
System.out.println("LALA");
}
}
}
// Mouse Listener stubs
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse Clicked");
if ((((e.getModifiers() == InputEvent.BUTTON3_MASK))) &&
inNoteArea(e)) {
searchForSelectedNote(e);
if ((selectedNote >= 0) && (selectedNote <
theApp.getPhrase().size())) {
noteContextMenu.show(theApp, e.getX(), e.getY());
}
}else if ((((e.getModifiers() == InputEvent.BUTTON1_MASK))) &&
inNoteArea(e)) {
searchForSelectedNote(e);
if ((selectedNote >= 0) && (selectedNote <
theApp.getPhrase().size())) {
if(selectedNote==theApp.getSelectedNote()){
theApp.setSelectedNote(-1);
theApp.setSelectedArea(0);
}else{
theApp.setSelectedNote(selectedNote);
theApp.setSelectedArea(0);
}
}else{
theApp.setSelectedNote(-1);
theApp.setSelectedArea(0);
}
}
// alg0
System.out.println(theApp.phrase.getSize());
Main.setEnabledRemove(theApp.phrase.getSize() >= 1);
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
//mouseMotionListener stubs
public void mouseMoved(MouseEvent e) {}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
173
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger() || ((e.getModifiers() &
InputEvent.BUTTON2_MASK) != 0) || (!theApp.editable))
return;
button1Down = true;
// add a new note if necessary
// no notes yet?
if(!inNoteArea(e)) {
// new note close to mouse click pitch
int newPitch = 85 - (e.getY() + theApp.staveDelta theApp.bPos)/2;
// make sure it is not an accidental
int[] blackNotes = {1,3,6,8,10};
boolean white = true;
for(int k=0;k<blackNotes.length;k++) {
if(newPitch%12 == blackNotes[k])
newPitch--;
}
Note n = new Note(newPitch,theApp.getNoteDuration());
Phrase phr = theApp.getPhrase();
phr.addNote(n);
theApp.repaint();
// set cursor
theApp.setCursor(new Cursor(Cursor.HAND_CURSOR));
// get ready to drag it
selectedNote = phr.size()-1;
//theApp.playCurrentNote(selectedNote);
clickedPosY = e.getY() + theApp.staveDelta;
clickedPosX = e.getX();
} else {
searchForSelectedNote(e);
theApp.setCursor(new Cursor(Cursor.MOVE_CURSOR));
// check for a click on a note - head?
}
if (selectedNote < 0) { // no note clicked on or yet made
// check which note to insert
for(int j=0;j< theApp.notePositions.size() - 2; j += 2) {
Integer tempX =
(Integer)theApp.notePositions.elementAt(j);
Integer nextTempX =
(Integer)theApp.notePositions.elementAt(j+2);
if(e.getX() > tempX.intValue() + 15 && e.getX() <
nextTempX.intValue()) {
// change cursor
theApp.setCursor(new Cursor(Cursor.HAND_CURSOR));
// add new note close to mouse clicked pitch
int newPitch = 85 - (e.getY() + theApp.staveDelta theApp.bPos)/2;
// make sure it is not an accidental
int[] blackNotes = {1,3,6,8,10};
boolean white = true;
for(int k=0;k<blackNotes.length;k++) {
if(newPitch%12 == blackNotes[k]) newPitch--;
}
Note n = new Note(newPitch
,theApp.getNoteDuration());
Phrase phr = theApp.getPhrase();
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
174
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
phr.getNoteList().insertElementAt(n, j/2 + 1);
theApp.repaint();
// play and update variables for dragging it
selectedNote = j/2 + 1;
clickedPosY = e.getY() + theApp.staveDelta;
clickedPosX = e.getX();
// get out of the loop
j = theApp.notePositions.size();
}
}
}
// check if the time signature is clicked
int theSpace = theApp.rightMargin + theApp.clefWidth +
theApp.keySigWidth;
if(e.getX() > theSpace && e.getX() < theSpace + 10) {
theApp.setCursor(new Cursor(Cursor.MOVE_CURSOR));
topTimeSelected = true;
clickedPosY = e.getY() + theApp.staveDelta;
clickedPosX = e.getX();
}
// check if the key signature is clicked
int theClefSpace = theApp.rightMargin + theApp.clefWidth;
int minKeySpace = 10;
if (theApp.keySigWidth > minKeySpace) minKeySpace =
theApp.keySigWidth;
if(e.getX() > theClefSpace - 10 && e.getX() < theClefSpace +
minKeySpace) {
theApp.setCursor(new Cursor(Cursor.MOVE_CURSOR));
keySelected = true;
clickedPosY = e.getY() + theApp.staveDelta;
clickedPosX = e.getX();
}
// alg0
System.out.println(theApp.phrase.getSize());
Main.setEnabledRemove(theApp.phrase.getSize() >= 1);
}
public void mouseDragged(MouseEvent e) {
if ((!button1Down) || (!theApp.editable))
return;
//theApp.dragNote(e.getX(), e.getY());
if (selectedNote >= 0) {
Phrase phr = theApp.getPhrase();
Note n = phr.getNote(selectedNote);
// move note down
if(e.getY() + theApp.staveDelta > clickedPosY + 2 &&
theApp.getPhrase().getNote(selectedNote).getPitch() != REST)
{
n.setPitch(n.getPitch() - 1);
if (n.getPitch() < theApp.getMinPitch())
n.setPitch(theApp.getMinPitch());
// update the current mouse location
clickedPosY += 2;
// update the visual display
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
175
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
theApp.repaint();
// keep pitch to reinstate it after displaying a rest
storedPitch = n.getPitch();
}
// move note up
if(e.getY() + theApp.staveDelta < clickedPosY - 2 &&
theApp.getPhrase().getNote(selectedNote).getPitch() != REST)
{
n.setPitch(n.getPitch() + 1);
if (n.getPitch() > theApp.getMaxPitch())
n.setPitch(theApp.getMaxPitch());
//theApp.playCurrentNote(selectedNote);
clickedPosY -= 2;
theApp.repaint();
storedPitch = n.getPitch();
}
// move note right - increase RV
if(e.getX() > clickedPosX + 6) {
double tempRV = n.getRhythmValue();
int tempPitch = n.getPitch();
// use +100 numbers for rests
if (tempPitch == REST) tempRV = tempRV + 100;
int currRVindex = rhythmValues.length;
// find current rhythm value and update RV
for(int i=0; i<rhythmValues.length - 1;i++) {
if(tempRV == rhythmValues[i])
n.setRhythmValue(rhythmValues[i + 1]);
}
clickedPosX = e.getX();
// update pitch
if (n.getRhythmValue() > 100.0) {
n.setPitch(REST);
n.setRhythmValue(n.getRhythmValue() - 100);
// update duration value
n.setDuration(n.getRhythmValue()*0.9);
} else {
if (tempPitch == REST) n.setPitch(storedPitch);
}
theApp.repaint();
}
// move note left - decrease RV
if(e.getX() < clickedPosX - 6) {
double tempRV = n.getRhythmValue();
int tempPitch = n.getPitch();
// use +100 numbers for rests
if (tempPitch == REST) tempRV = tempRV + 100;
// find current rhythm value position in the array
int currRVindex = 0;
for(int i=0; i<rhythmValues.length;i++) {
if(tempRV == rhythmValues[i]) currRVindex = i;
}
// update rv
if (currRVindex > 0) {
n.setRhythmValue(rhythmValues[currRVindex - 1]);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
176
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
clickedPosX = e.getX();
// update pitch
if (n.getRhythmValue() > 100.0) {
n.setPitch(REST);
n.setRhythmValue(n.getRhythmValue()-100);
// update duration value
n.setDuration(n.getRhythmValue()*0.9);
} else {
if (tempPitch == REST) n.setPitch(storedPitch);
}
theApp.repaint();
}
}
}
// check for time signature change
if (topTimeSelected) {
//increase?
if(e.getY() + theApp.staveDelta< clickedPosY - 4 ) {
theApp.setMetre(theApp.getMetre() + 1.0);
if (theApp.getMetre() > 9.0) theApp.setMetre(9.0);
if (theApp.getMetre() < 1.0) theApp.setMetre(1.0);
theApp.getPhrase().setNumerator((new
Double(Math.round(theApp.getMetre()))).intValue());
clickedPosY -= 4;
theApp.repaint();
theApp.updateChange();
}
//decrease
if(e.getY() + theApp.staveDelta > clickedPosY + 4) {
theApp.setMetre(theApp.getMetre() - 1.0);
if (theApp.getMetre() < 1.0) theApp.setMetre(1.0);
if (theApp.getMetre() > 9.0) theApp.setMetre(9.0);
theApp.getPhrase().setNumerator((new
Double(Math.round(theApp.getMetre()))).intValue());
clickedPosY += 4;
theApp.repaint();
theApp.updateChange();
}
}
// check for key signature change
if (keySelected) {
//increase?
if(e.getY() + theApp.staveDelta < clickedPosY - 4) {
theApp.setKeySignature(theApp.getKeySignature() + 1);
if (theApp.getKeySignature() > 7)
theApp.setKeySignature(7);
clickedPosY -= 4;
theApp.repaint();
theApp.updateChange();
}
//decrease
if(e.getY() + theApp.staveDelta > clickedPosY + 4) {
theApp.setKeySignature(theApp.getKeySignature() - 1);
if (theApp.getKeySignature() < -7)
theApp.setKeySignature(-7);
clickedPosY += 4;
theApp.repaint();
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
177
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
theApp.updateChange();
}
}
}
public void mouseReleased(MouseEvent e) {
button1Down = false;
if(!theApp.editable) return;
// delete note if necessary
for(int i=0; i< theApp.getPhrase().getNoteList().size(); i++) {
if (theApp.getPhrase().getNote(i).getRhythmValue() == 0.0) {
theApp.getPhrase().getNoteList().removeElementAt(i);
}
}
// unflag any note being selected
theApp.repaint();
theApp.updateChange();
selectedNote = -1;
topTimeSelected = false;
keySelected = false;
theApp.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
public void actionPerformed(ActionEvent e) {
Phrase phrase
= theApp.getPhrase();
Note note
= phrase.getNote(selectedNote);
if (e.getSource() == editNote) {
JFrame
editorFrame
= new JFrame( "Edit this Note");
editorFrame.setSize( 400, 400);
editorFrame.setResizable(true);
DNoteEditor noteEditor
= new DNoteEditor(editorFrame);
noteEditor.editNote(note, 20, 20);
} else if (e.getSource() == repeatNote) {
Note newNote = note.copy();
phrase.getNoteList().insertElementAt(
newNote,
selectedNote
);
} else if (e.getSource() == makeRest) {
note.setFrequency(Note.REST);
} else if (e.getSource() == deleteNote) {
phrase.getNoteList().removeElementAt(selectedNote);
}
selectedNote = -1;
theApp.repaint();
}
// key listener stubs
public void keyPressed(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
//
public void keyTyped(KeyEvent e) {
System.out.println(e.getKeyChar());
if(e.getKeyChar() == '\b') theApp.deleteLastNote();
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
178
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
}
=========================================================================
=========================================================================
package diamouses.ui.scoreEditor.staves;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Vector;
import
import
import
import
diamouses.ui.scoreEditor.GuitarNeck;
jm.JMC;
jm.gui.cpn.Images;
jm.music.data.*;
/**
* Represents a treble clef stave.
*
* @author Andrew Brown, Adam Kirby
* @version 1.0.1, 8th July 2001
*/
public class
DTrebleStave extends
DStave implements JMC{
private static final class Accidental {
public static final Accidental NONE = new Accidental("none");
public static final Accidental SHARP = new Accidental("sharp");
public static final Accidental NATURAL = new
Accidental("natural");
public static final Accidental FLAT = new Accidental("flat");
private String name;
// Due to a 1.1 compiler bug this constructor cannot be private
Accidental(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
/**
* Defines a type representing the rules and logic of when
accidentals
* should be dispalyed against notes on the stave.
*
* Note: In jMusic version 1.2 and earlier this inner class was
previously
* called AccidentalDisplayStyle.
*/
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
179
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
public static abstract class Style {
int[] sharpPitches = {77, 72, 79, 74, 69, 76, 71};
int[] flatPitches = {71, 76, 69, 74, 67, 72, 65};
/**
* Defines the standard style of displaying accidentals in a
Common
* Practice Notation stave.
*/
public static final Style TRADITIONAL = new Trad();
/**
* Defines a style unique to jMusic, which displays an accidental
in
* all situations where the status (sharp/flat/natural) of a note
may
* be unclear.
*
* Note: In jMusic version 1.2 and earlier this field was
previously
* called SUPERFLUOUS_SHARPS_AND_FLATS.
*/
public static final Style JMUSIC = new JMusic();
private static final class Trad extends Style {
private boolean[] accidentalRequiredByKeySignature =
new boolean[12];
private static final int[] SHARP_ACCIDENTAL_PAIRS =
{ 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6 };
private static final int[] FLAT_ACCIDENTAL_PAIRS =
{ 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6 };
private int[] degreeToAccidentalPair =
SHARP_ACCIDENTAL_PAIRS;
private boolean[] accidentalInEffect =
new boolean[7];
private int keySignature = 0;
public Trad() {
super("Traditional style");
this.initialise(0);
}
private void setBooleanArrayToFalse(boolean[] array) {
for (int i = 0; i < array.length; i++) {
array[i] = false;
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
180
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
void initialise(final int keySignature) {
this.keySignature = keySignature;
if (keySignature < 0) {
degreeToAccidentalPair = FLAT_ACCIDENTAL_PAIRS;
} else {
degreeToAccidentalPair = SHARP_ACCIDENTAL_PAIRS;
}
this.setBooleanArrayToFalse(
accidentalRequiredByKeySignature);
accidentalRequiredByKeySignature[1] = true;
accidentalRequiredByKeySignature[3] = true;
accidentalRequiredByKeySignature[6] = true;
accidentalRequiredByKeySignature[8] = true;
accidentalRequiredByKeySignature[10] = true;
for (int i = 0; i < Math.abs(keySignature); i++) {
if (keySignature < 0) {
accidentalRequiredByKeySignature[
flatPitches[i] % 12] = true;
accidentalRequiredByKeySignature[
(flatPitches[i] - 1) % 12] = false;
} else {
accidentalRequiredByKeySignature[
sharpPitches[i] % 12] = true;
accidentalRequiredByKeySignature[
(sharpPitches[i] + 1) % 12] = false;
}
}
this.setBooleanArrayToFalse(accidentalInEffect);
}
Accidental selectAccidental(
final int pitch,
final double rhythmValue) {
if (pitch == Note.REST
|| rhythmValue == 0.0) {
return Accidental.NONE;
}
int degree = pitch % 12; // relative to C not tonic
int accidentalPair = degreeToAccidentalPair[degree];
if (accidentalRequiredByKeySignature[degree]
^ accidentalInEffect[accidentalPair]) {
accidentalInEffect[accidentalPair] =
! accidentalInEffect[accidentalPair];
if (degree == 1 || degree == 3 || degree == 6
|| degree == 8 || degree == 10) {
if (keySignature > -1) {
return Accidental.SHARP;
} else {
return Accidental.FLAT;
}
} else {
return Accidental.NATURAL;
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
181
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
return Accidental.NONE;
}
void processBarLine() {
this.setBooleanArrayToFalse(accidentalInEffect);
}
};
private static final class JMusic extends Style {
private Vector chromaticallyAffectedPitches = new Vector();
/**
* Key signature encoded as a signed accidental count. The
* following conditions apply:
* <ul>
*
<li />0 represents no sharps of flats.
*
<li />positive <i>n</i> represents <i>n</i> sharps
*
<li />negative <i>n</i> represents <i>n</n> flats
* </ul>
*/
private int keySignature;
// had difficulty finding a better name because I don't
// really understand what this variable is and does. It
// seems to be closely related to previouslyChromatic. It
// seems to be a count of accidentals, but in all staves of
// the range of pitches in the MIDI spec. So a G Major
// scale would add 1 to the count for the F# in the treble
// stave, plus 1 for each F# in octaves above and below
// that.
// Odd.
private int keyAccidentals;
public JMusic() {
super("JMusic style (with superfluous sharps and "
+ "flats)");
this.initialise(0);
}
void initialise(final int keySignature) {
chromaticallyAffectedPitches = new Vector();
this.keySignature = keySignature;
keyAccidentals = 0;
if (keySignature > 0 && keySignature < 8) {
for (int i = 0; i < keySignature; i++) {
int degree = sharpPitches[i] % 12;
for (int j = (int)Note.MIN_PITCH;
j <= (int)Note.MAX_PITCH;
j++) {
if ((j % 12) == degree) {
chromaticallyAffectedPitches.addElement(
new Integer(j));
keyAccidentals++;
}
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
182
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
} else if (keySignature < 0 && keySignature > -8) {
for (int i = 0; i > keySignature; i--) {
int degree = flatPitches[-i] % 12;
for (int j = (int)Note.MIN_PITCH;
j <= (int)Note.MAX_PITCH;
j++) {
if ((j % 12) == degree) {
chromaticallyAffectedPitches.addElement(
new Integer(j));
keyAccidentals++;
}
}
}
}
}
Accidental selectAccidental(
final int pitch,
final double rhythmValue) {
if (pitch == Note.REST
|| rhythmValue == 0.0) {
return Accidental.NONE;
}
if ((pitch % 12) == 1 || (pitch % 12) == 3
|| (pitch % 12) == 6 || (pitch % 12) == 8
|| (pitch % 12) == 10) {
if (keySignature > -1) {
chromaticallyAffectedPitches.addElement(
new Integer(pitch - 1));
return Accidental.SHARP;
} else {
chromaticallyAffectedPitches.addElement(
new Integer(pitch + 1));
return Accidental.FLAT;
}
} else {
int size = chromaticallyAffectedPitches.size();
int temp;
for(int j = 0; j < size; j++) {
temp = ((Integer)
chromaticallyAffectedPitches.elementAt(
j)).intValue();
if (temp == pitch) {
if (j > keyAccidentals-1) {
chromaticallyAffectedPitches.
removeElementAt(j);
}
return Accidental.NATURAL;
}
}
}
return Accidental.NONE;
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
183
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
void processBarLine() {
// do nothing
}
};
private String name;
// Due to a 1.1 compiler bug this constructor cannot be private
Style(String name) {
this.name = name;
}
public String toString() {
return name + " of displaying accidentals";
}
abstract void initialise(final int keySignature);
abstract Accidental selectAccidental(
final int pitch,
final double rhythmValue);
abstract void processBarLine();
}
private Style style = new Style.JMusic();
/**
* Sets the display style of accidentals for this stave.
*
* @param ads
Style to be used by this stave.
*/
public void setAccidentalDisplayStyle(Style ads) {
if (ads == Style.TRADITIONAL) {
this.style = new Style.Trad();
} else if (ads == Style.JMUSIC) {
this.style = new Style.JMusic();
} else {
throw new RuntimeException("Unknown Accidental Display
Style");
}
}
private int tonic = 0;
protected int[] scale = JMC.MAJOR_SCALE;
public static final int MAX_HEIGHT = 500;
public static final int MAX_WIDTH = 2000;
/**
* Constructs a new treble stave to display a blank Phrase using the
default
* stave images.
*/
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
184
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
public DTrebleStave() {
super();
}
/**
* Constructs a new treble stave
* <code>phrase</code> using the
*
* @param phrase
Phrase to be
*/
public DTrebleStave(final Phrase
super(phrase);
}
to display the specified
default stave images.
displayed in stave
phrase) {
/**
* Constructs a new treble stave to display a blank Phrase using the
* specified stave <code>images</code>.
*
* @param images
Images representing notes, rest and other stave
elements
*
to use within the compenent
*/
public DTrebleStave(final Images images) {
super(images);
}
/**
* Constructs a new treble stave to display the specified
* <code>phrase</code> using the specified stave <code>images</code>.
*
* @param phrase
Phrase to be displayed in stave
* @param images
Images representing notes, rest and other stave
elements
*
to use within the compenent
*/
public DTrebleStave(final Phrase phrase, final Images images) {
super(phrase, images);
}
private double beatCounter;
public void paintComponent(Graphics graphics) {
//
if (phrase == null) {
//
return;
//
}
// set up for double buffering
if(image == null) {
image = this.createImage(MAX_WIDTH, MAX_HEIGHT);
g = image.getGraphics();
}
// set font
g.setFont(font);
// keep track of the rhythmic values for bar lines
beatCounter = 0.0;
// reste note position locations
notePositions.removeAllElements();
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
185
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
// add a title if set to be visible
if(getDisplayTitle()) g.drawString(title, rightMargin, bPos 10);
// insert key signature if required
int keyOffset = 0;
style.initialise(keySignature);
// is the key signature using sharps or flats?
if (keySignature > 0 && keySignature < 8) { // sharp
for(int ks=0;ks<keySignature; ks++) {
// claulate position
int keyAccidentalPosition = notePosOffset[
sharps[ks]%12] + bPos - 4 + (( 5- sharps[ks]/12) * 24) +
(( 6- sharps[ks]/12) * 4);
// draw sharp on treble
g.drawImage(sharp, rightMargin + clefWidth + keyOffset,
keyAccidentalPosition, this);
// indent position
keyOffset += 10;
keySigWidth = keyOffset;
}
} else {
if (keySignature < 0 && keySignature > -8) { // flat
for(int ks=0;ks< Math.abs(keySignature); ks++) {
// claulate position
int keyAccidentalPosition = notePosOffset[
flats[ks]%12] + bPos - 4 + (( 5- flats[ks]/12) * 24)
+ (( 6- flats[ks]/12) * 4);
// draw flat
g.drawImage(flat, rightMargin + clefWidth +
keyOffset, keyAccidentalPosition, this);
// indent position
keyOffset += 10;
}
}
}
keySigWidth = keyOffset + 3;
// insert time signature if required
if ( metre != 0.0) {
Image[] numbers = {one, two, three, four, five, six, seven,
eight, nine};
// top number
g.drawImage(numbers[(int)metre - 1], rightMargin + clefWidth
+ keySigWidth, bPos + 13, this);
//bottom number
g.drawImage(four, rightMargin + clefWidth + keySigWidth ,
bPos + 29, this);
timeSigWidth = 30;
} else timeSigWidth = 5;
// set indent position for first note
totalBeatWidth = rightMargin + clefWidth + keySigWidth +
timeSigWidth;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
186
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
//
//
//
//
//
//
firstChords =
ChordAnalysis.getFirstPassChords(phrase, 1.0, tonic,
scale);
secondChords =
ChordAnalysis.getSecondPassChords(phrase, 1.0, tonic,
scale);
lastChordDisplayed = -1;
// draw notes and rests
for(int i = 0; i < phrase.size();i++) {
int notePitchNum = (int)phrase.getNote(i).getPitch();
// reset pitch for rests
// position?
int pitchTempPos;
if ( notePitchNum == REST ||
phrase.getNote(i).getRhythmValue() == 0.0) { // rest or
delete
pitchTempPos = notePosOffset[71%12] + bPos - 4 + (( 5- 71/12)
* 24) + (( 6- 71/12) * 4);
} else {
pitchTempPos = notePosOffset[notePitchNum%12] + bPos - 4 + ((
5- notePitchNum/12) * 24) + (( 6- notePitchNum/12) * 4);
}
firstAccidentalDisplayed = false;
semitoneShiftUp = false;
isTied = false;
isFirstNoteInTie = true;
extraImagesUsed = false;
savedBeatWidth = totalBeatWidth;
savedBeatWidth2 = 0;
double rhythmValue = phrase.getNote(i).getRhythmValue();
double rvToEndOfBar = metre - (beatCounter % metre);
while (rvToEndOfBar < rhythmValue) {
isTied = true;
drawNote(notePitchNum, rvToEndOfBar,
pitchTempPos, i);
rhythmValue -= rvToEndOfBar;
rvToEndOfBar = metre - (beatCounter % metre);
}
drawNote(notePitchNum, rhythmValue, pitchTempPos, i);
}
// draw treble stave
for(int i = 0; i < 5;i++) {
g.drawLine( rightMargin, (bPos + imageHeightOffset - (2*
staveSpaceHeight)) +(i* staveSpaceHeight), totalBeatWidth,
(bPos + imageHeightOffset - (2* staveSpaceHeight)) +(i*
staveSpaceHeight));
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
187
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
// draw neext note stave area
// draw stave
g.setColor(Color.lightGray);
for(int i = 0; i < 5;i++) {
g.drawLine( totalBeatWidth, (bPos + imageHeightOffset - (2*
staveSpaceHeight)) +(i* staveSpaceHeight),totalBeatWidth +
50, (bPos + imageHeightOffset - (2* staveSpaceHeight)) +(i*
staveSpaceHeight));
}
//for(int i = 6; i < 11;i++) {
//g.drawLine( totalBeatWidth,
// (bPos + imageHeightOffset - (2* staveSpaceHeight)) +(i*
staveSpaceHeight),
//totalBeatWidth + 50,
// (bPos + imageHeightOffset - (2* staveSpaceHeight)) +(i*
staveSpaceHeight));
//
}
g.setColor(Color.black);
// add Clefs
g.drawImage(trebleClef, rightMargin + 7, bPos - 4, this);
//g.drawImage(bassClef, rightMargin + 7, bPos + staveSpaceHeight
* 6, this);
/* Draw completed buffer to g */
graphics.drawImage(image, 0, 0, null);
// clear image
// clear
g.setColor(this.getBackground());
g.fillRect(0,0, MAX_WIDTH, MAX_HEIGHT);
g.setColor(this.getForeground());
//repaint();
//g.dispose();
}
private boolean isFirstNoteInTie = true;
//
private boolean isNote = false;
private boolean firstAccidentalDisplayed = false;
private boolean isTied = false;
//
private boolean isUp = true;
private boolean semitoneShiftUp = false;
private boolean extraImagesUsed;
//
private boolean requiresMoreThanOneImage;
//
private double excessRhythmValue;
private int savedBeatWidth;
private int savedBeatWidth2;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
188
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
private int lastChordDisplayed = -1;
private int lastPosition = 0;
//
private int[] firstChords = new int[0];
//
private int[] secondChords = new int[0];
private String[] chordStrings = {"I", "II", "III", "IV", "V", "VI",
"VII","."};
private void drawNote(int notePitchNum, final double rhythmValue,
int pitchTempPos, int noOfNote) {
requiresMoreThanOneImage = false;
excessRhythmValue = 0.0;
//
if ((beatCounter % 1.0) == 0.0) {
//
int currentBeat = (int) (beatCounter / 1.0);
//
int total = currentBeat - lastChordDisplayed;
//
int remaining = total;
//
while (lastChordDisplayed < currentBeat) {
//
lastChordDisplayed++;
//
//
remaining--;
//
g.drawString(chordStrings[firstChords[lastChordDisplayed]],
//
(int) (totalBeatWidth - ((totalBeatWidth - lastPosition)
//
* (remaining
//
/ (double) total))),
//
20);
//
int index = secondChords[lastChordDisplayed];
//
String string = chordStrings[index];
////
g.drawString(chordStrings[secondChords[lastChordDisplayed]],
//
g.drawString(string,
//
(int) (totalBeatWidth - ((totalBeatWidth - lastPosition)
//
* (remaining
//
/ (double) total))),
//
40);
//
}
//
lastPosition = totalBeatWidth;
//
}
// choose graphic
chooseImage( notePitchNum, rhythmValue, 71, 0, 71);
// draw note/rest
if (currImage != null) {
if (noOfNote==getSelectedNote()) {
Note selected_note =
phrase.getNote(noOfNote);//.getPitch();
GuitarNeck.getInstance().setNote(selected_note.getPitch());
//-System.out.println(selected_note.toString());
BufferedImage bi =
DStave.toBufferedImage(currImage);
int w = bi.getWidth();
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
189
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
int h = bi.getHeight();
int pixel;
BufferedImage biOut = new BufferedImage(w, h,
bi.TYPE_INT_ARGB_PRE);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
pixel = bi.getRGB(x, y);
if (pixel == (Color.BLACK).getRGB())
{
pixel = (Color.RED).getRGB();
}
biOut.setRGB(x, y, pixel);
}
}
currImage = DStave.toImage(biOut);
}
}
g.drawImage(currImage, totalBeatWidth, pitchTempPos, this);
// store position in a vector
drawNote2(notePitchNum, rhythmValue - excessRhythmValue,
pitchTempPos, noOfNote);
if (requiresMoreThanOneImage) {
drawNote(notePitchNum, excessRhythmValue,
pitchTempPos, noOfNote);
extraImagesUsed = true;
}
}
private void drawNote2(int pitch, final double rhythmValue,
int yCoordinate,int noOfNote) {
// draw accidental
if (pitch != Note.REST && rhythmValue != 0.0) {
Accidental accidental =
style.selectAccidental(pitch, rhythmValue);
if (accidental == Accidental.SHARP) {
if (! firstAccidentalDisplayed) {
displayImage(g, sharp, totalBeatWidth - 9,
yCoordinate, noOfNote);
}
// enter the note made sharp i.e, F for an F#
} else if (accidental == Accidental.FLAT) {
yCoordinate -= 4; // to show the note a semitone higher
for flats
if (! firstAccidentalDisplayed) {
displayImage(g, flat, totalBeatWidth - 9,
yCoordinate, noOfNote);
}
pitch++; // assume it is a semitone higher for
legerlines etc...
semitoneShiftUp = true;
} else if (accidental == Accidental.NATURAL) {
if (! firstAccidentalDisplayed) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
190
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
displayImage(g, natural, totalBeatWidth - 7,
yCoordinate, noOfNote);
}
}
}
firstAccidentalDisplayed = true;
// draw note/rest
displayImage(g, currImage, totalBeatWidth, yCoordinate,
noOfNote);
// store position in a vector
notePositions.addElement(new Integer(totalBeatWidth));
notePositions.addElement(new Integer(yCoordinate));
if (dottedNote) {
boolean dotFlag = true;
for(int l = 0; l < lineNotes.length; l++) {
if (lineNotes[l] + 12 == pitch
|| lineNotes[l] + 36 == pitch
|| lineNotes[l] + 60 == pitch
|| lineNotes[l] + 84 == pitch
|| lineNotes[l] + 108 == pitch
|| pitch == REST) {
displayImage(g, dot, totalBeatWidth + 1, yCoordinate
- 4, noOfNote);
dotFlag = false;
l = lineNotes.length;
}
}
if (dotFlag) {
displayImage(g, dot, totalBeatWidth + 1, yCoordinate,
noOfNote);
}
}
// leger lines down
if (pitch <= 61 && pitch > -1 && rhythmValue != 0.0) {g.drawLine(
totalBeatWidth - 3, bPos + 52, totalBeatWidth+ 12, bPos + 52);}
if ( pitch <= 58 && pitch > -1 && rhythmValue != 0.0)
{g.drawLine( totalBeatWidth - 3, bPos + 60, totalBeatWidth+ 12,
bPos + 60);}
if ( pitch <= 54 && pitch > -1 && rhythmValue != 0.0)
{g.drawLine( totalBeatWidth - 3, bPos + 68, totalBeatWidth+ 12,
bPos + 68);}
if ( pitch <= 51 && pitch > -1 && rhythmValue != 0.0)
{g.drawLine( totalBeatWidth - 3, bPos + 76, totalBeatWidth+ 12,
bPos + 76);}
if ( pitch <= 48 && pitch > -1 && rhythmValue != 0.0)
{g.drawLine( totalBeatWidth - 3, bPos + 84, totalBeatWidth+ 12,
bPos + 84);}
// leger lines up
if ( pitch >= 81 && pitch < 128 && rhythmValue != 0.0)
{g.drawLine( totalBeatWidth - 3, bPos + 4, totalBeatWidth+ 12,
bPos + 4);}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
191
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
if ( pitch >= 84 && pitch <
{g.drawLine( totalBeatWidth
bPos - 4);}
if ( pitch >= 88 && pitch <
{g.drawLine( totalBeatWidth
bPos - 12);}
if ( pitch >= 91 && pitch <
{g.drawLine( totalBeatWidth
bPos - 20);}
if ( pitch >= 95 && pitch <
{g.drawLine( totalBeatWidth
bPos - 28);}
128 && rhythmValue != 0.0)
- 3, bPos - 4, totalBeatWidth+ 12,
128 && rhythmValue != 0.0)
- 3, bPos - 12, totalBeatWidth+ 12,
128 && rhythmValue != 0.0)
- 3, bPos - 20, totalBeatWidth+ 12,
128 && rhythmValue != 0.0)
- 3, bPos - 28, totalBeatWidth+ 12,
// increment everything
savedBeatWidth2 = totalBeatWidth;
if ((isTied || extraImagesUsed) && isNote && ! isFirstNoteInTie)
{
int yPosition = yCoordinate + 19 - ((semitoneShiftUp) ? 4 :
0);
if (isUp) {
g.drawImage(tieUnder,
savedBeatWidth - 3 + 9,
yPosition + 17,
savedBeatWidth2 + 19 - 9,
yPosition + 17 + tieUnder.getHeight(this),
0, 0, tieUnder.getWidth(this),
tieUnder.getHeight(this),this);
} else {
g.drawImage(tieOver,
savedBeatWidth - 3 + 9,
yPosition - 20,
savedBeatWidth2 + 19 - 9,
yPosition - 20 + tieOver.getHeight(this),
0, 0, tieOver.getWidth(this),
tieOver.getHeight(this),
this);
}
}
if (isFirstNoteInTie = true) {
isFirstNoteInTie = false;
}
savedBeatWidth = totalBeatWidth;
totalBeatWidth += currBeatWidth;
dottedNote = false;
// quantised to semiquvers!
// (int)((rhythmValue/0.25) * 0.25);
beatCounter += (int)(rhythmValue/0.25) * 0.25;
// draw bar line
if (metre != 0.0) {
if ( (beatCounter % metre) == 0.0) {
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
192
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
g.drawLine( totalBeatWidth , bPos + 12, totalBeatWidth,
bPos + 44);
style.processBarLine();
// add bar numbers?
if (barNumbers) g.drawString( ""+(int)(beatCounter/metre
+1 + phrase.getStartTime()) , totalBeatWidth - 4 ,
bPos);
totalBeatWidth += 12;
}
}
}
private void displayImage(final Graphics g, final Image image, int
xCoord,int yCoord, int noOfNote ) {
g.drawImage(image, xCoord, yCoord, this);
}
}
=========================================================================
=========================================================================
package diamouses.ui.Metronome;
/*
* PlayNote.java
*
* Created on June 12, 2007, 3:05 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
import java.util.TimerTask;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Patch;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;
/** Used by MetronomeDialog to play a midi note.
*
* @author Aaron Bauer
*/
PlayNote
public class
extends TimerTask{
private MidiChannel[] channels;
private int beatCount;
private static int noteCount;
private boolean compoundTime;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
193
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
/** Creates a new instance of PlayNote. Requires beats per measure
integer
* and a compound time boolean
* @param beatsPM - The beats per minute
* @param compound - whether the compound time is used
*/
public PlayNote(int beatsPM, boolean compound) {
PlayNote.noteCount = beatsPM;
this.beatCount = beatsPM - 1;
this.compoundTime = compound;
try
{
//initializes midi
Synthesizer synth = MidiSystem.getSynthesizer();
synth.open();
this.channels = synth.getChannels();
Soundbank bank = synth.getDefaultSoundbank();
synth.loadAllInstruments(bank);
Instrument instrs[] = synth.getLoadedInstruments();
Instrument instr = instrs[115];
Patch instrPatch = instr.getPatch();
this.channels[2].programChange(instrPatch.getBank(),
instrPatch.getProgram());
}
catch (Exception exc){
exc.printStackTrace();
}
}
/** Plays the note depending on beats per measure and whether or not
compound
* time is enabled.
*/
public void run() {
this.beatCount = this.beatCount + 1;
if(this.beatCount == PlayNote.noteCount){
this.channels[2].noteOn(60, 70);
try {
Thread.sleep(1);
}
catch (Exception exc){
exc.printStackTrace();
}
this.channels[2].noteOff(60);
this.beatCount = 0;
}
else if(this.compoundTime && (this.beatCount == 3 ||
this.beatCount == 6 || this.beatCount == 9) ){
this.channels[2].noteOn(45, 70);
try {
Thread.sleep(1);
}
catch (Exception exc){
exc.printStackTrace();
}
this.channels[2].noteOff(45);
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
194
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
else {
this.channels[2].noteOn(50, 70);
try {
Thread.sleep(1);
}
catch (Exception exc){
exc.printStackTrace();
}
this.channels[2].noteOff(50);
}
}
}
=========================================================================
=========================================================================
package diamouses.ui.Metronome;
import javax.swing.JFrame;
public class
TestMetronome {
public static void main (String [] args) {
Metronome met = new Metronome(new JFrame(), null, true);
met.setVisible(true);
}
}
=========================================================================
=========================================================================
package diamouses.ui.Metronome;
import java.awt.*;
import javax.swing.*;
import java.util.Timer;
/** Creates a metronome that works by having a timer play a note at a
* user defined interval in beats per minute.
*
* @author Aaron Bauer
*/
public class
{
Metronome extends
javax.swing.JDialog
PlayNote playNote = null;
// beats per minute
private int bpm = 120;
private Timer noteTimer = new Timer();
// beats per measure
private double beats = 4;
// compound time indicator
private boolean compound = false;
// used to check text field content
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
195
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
private double textTest;
/** Creates new form Metronome
* @param parent - The parent frame
* @param image - The title image
* @param modal - The modality of the screen
*/
public Metronome(java.awt.Frame parent, Image image, boolean modal)
{
super(parent, modal);
this.setIconImage(image);
initComponents();
this.rb44.setSelected(true);
noteTimer = new Timer();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated
Code">//GEN-BEGIN:initComponents
private void initComponents() {
buttonGroup1 = new javax.swing.ButtonGroup();
rb24 = new javax.swing.JRadioButton();
jLabel4 = new javax.swing.JLabel();
rb68 = new javax.swing.JRadioButton();
rb98 = new javax.swing.JRadioButton();
rb128 = new javax.swing.JRadioButton();
rbCustom = new javax.swing.JRadioButton();
jLabel3 = new javax.swing.JLabel();
rb44 = new javax.swing.JRadioButton();
rb54 = new javax.swing.JRadioButton();
rb34 = new javax.swing.JRadioButton();
jTextField2 = new javax.swing.JTextField();
jLabel6 = new javax.swing.JLabel();
jLabel5 = new javax.swing.JLabel();
jLabel1 = new javax.swing.JLabel();
jSlider1 = new javax.swing.JSlider();
btnStart = new javax.swing.JButton();
jLabel2 = new javax.swing.JLabel();
jLabel7 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Score-Editor Metronome");
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
buttonGroup1.add(rb24);
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
196
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
rb24.setText("2/4");
rb24.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0,
0, 0));
rb24.setMargin(new java.awt.Insets(0, 0, 0, 0));
rb24.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rb24ActionPerformed(evt);
}
});
jLabel4.setText("Compound Time");
buttonGroup1.add(rb68);
rb68.setText("6/8");
rb68.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0,
0, 0));
rb68.setMargin(new java.awt.Insets(0, 0, 0, 0));
rb68.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rb68ActionPerformed(evt);
}
});
buttonGroup1.add(rb98);
rb98.setText("9/8");
rb98.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0,
0, 0));
rb98.setMargin(new java.awt.Insets(0, 0, 0, 0));
buttonGroup1.add(rb128);
rb128.setText("12/8");
rb128.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0,
0, 0));
rb128.setMargin(new java.awt.Insets(0, 0, 0, 0));
rb128.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rb128ActionPerformed(evt);
}
});
buttonGroup1.add(rbCustom);
rbCustom.setText("Custom Time");
rbCustom.setBorder(javax.swing.BorderFactory.createEmptyBorder(0,
0, 0, 0));
rbCustom.setMargin(new java.awt.Insets(0, 0, 0, 0));
rbCustom.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rbCustomActionPerformed(evt);
}
});
jLabel3.setText("Simple Time");
buttonGroup1.add(rb44);
rb44.setText("4/4");
rb44.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0,
0, 0));
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
197
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
rb44.setMargin(new java.awt.Insets(0, 0, 0, 0));
rb44.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rb44ActionPerformed(evt);
}
});
buttonGroup1.add(rb54);
rb54.setText("5/4");
rb54.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0,
0, 0));
rb54.setMargin(new java.awt.Insets(0, 0, 0, 0));
rb54.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rb54ActionPerformed(evt);
}
});
buttonGroup1.add(rb34);
rb34.setText("3/4");
rb34.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0,
0, 0));
rb34.setMargin(new java.awt.Insets(0, 0, 0, 0));
rb34.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
rb34ActionPerformed(evt);
}
});
jTextField2.setText("4");
jLabel6.setText("Beats Per Measure");
jLabel5.setText("Allegro");
jLabel1.setFont(new java.awt.Font("Tahoma", 0, 12));
jLabel1.setText("BPM: 120");
jSlider1.setMaximum(208);
jSlider1.setMinimum(40);
jSlider1.setPaintTicks(true);
jSlider1.setSnapToTicks(true);
jSlider1.setValue(120);
jSlider1.addChangeListener(new javax.swing.event.ChangeListener()
{
public void stateChanged(javax.swing.event.ChangeEvent evt) {
jSlider1StateChanged(evt);
}
});
btnStart.setText("Start");
btnStart.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnStartActionPerformed(evt);
}
});
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
198
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
jLabel2.setFont(new java.awt.Font("Tahoma", 1, 18));
jLabel2.setText("Metronome");
javax.swing.GroupLayout layout = new
javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LE
ADING)
.addComponent(rb98)
.addComponent(rb68)
.addComponent(jLabel4)
.addComponent(rb24)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LE
ADING)
.addComponent(rbCustom)
.addComponent(rb54)
.addComponent(rb44)
.addComponent(jLabel3)
.addComponent(rb34))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LE
ADING)
.addGroup(layout.createSequentialGroup()
.addGap(24, 24, 24)
.addComponent(jLabel6))
.addGroup(layout.createSequentialGroup()
.addComponent(jSlider1,
javax.swing.GroupLayout.PREFERRED_SIZE, 247,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnStart))
.addGroup(layout.createSequentialGroup()
.addGap(91, 91, 91)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LE
ADING)
.addComponent(jLabel5,
javax.swing.GroupLayout.PREFERRED_SIZE, 69,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1)))
.addGroup(layout.createSequentialGroup()
.addGap(70, 70, 70)
.addComponent(jLabel2))
.addComponent(jTextField2,
javax.swing.GroupLayout.PREFERRED_SIZE, 20,
javax.swing.GroupLayout.PREFERRED_SIZE)))
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
199
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
.addComponent(rb128))
.addContainerGap(12, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING,
layout.createSequentialGroup()
.addContainerGap(203, Short.MAX_VALUE)
.addComponent(jLabel7)
.addGap(214, 214, 214))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LE
ADING)
.addGroup(layout.createSequentialGroup()
.addGap(28, 28, 28)
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rb44)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rb54)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rb34)
.addGap(6, 6, 6)
.addComponent(rb24)
.addGap(6, 6, 6)
.addComponent(jLabel4)
.addGap(6, 6, 6)
.addComponent(rb68)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rb98))
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TR
AILING)
.addComponent(btnStart)
.addComponent(jSlider1,
javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel1)
.addGap(6, 6, 6)
.addComponent(jLabel5)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rb128)
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
200
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BA
SELINE)
.addComponent(rbCustom)
.addComponent(jTextField2,
javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel6))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 20,
Short.MAX_VALUE)
.addComponent(jLabel7)
.addContainerGap())
);
java.awt.Dimension screenSize =
java.awt.Toolkit.getDefaultToolkit().getScreenSize();
setBounds((screenSize.width-425)/2, (screenSize.height-300)/2,
425, 300);
}// </editor-fold>//GEN-END:initComponents
private void formWindowClosing(java.awt.event.WindowEvent evt) {//GENFIRST:event_formWindowClosing
noteTimer.purge();
noteTimer.cancel();
}//GEN-LAST:event_formWindowClosing
private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt)
{//GEN-FIRST:event_jSlider1StateChanged
JSlider source = (JSlider) evt.getSource();
if(!source.getValueIsAdjusting())
{
bpm = source.getValue();
jLabel1.setText("BPM: " + bpm);
if(bpm <= 59 && bpm >= 40)
{
jLabel5.setText("Largo");
}
if(bpm <= 65 && bpm >= 60)
{
jLabel5.setText("Larghetto");
}
if(bpm <= 75 && bpm >= 66)
{
jLabel5.setText("Adagio");
}
if(bpm <= 107 && bpm >= 76)
{
jLabel5.setText("Andante");
}
if(bpm <= 119 && bpm >= 108)
{
jLabel5.setText("Moderato");
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
201
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
}
if(bpm <= 167 && bpm >= 120)
{
jLabel5.setText("Allegro");
}
if(bpm <= 199 && bpm >= 168)
{
jLabel5.setText("Presto");
}
if(bpm <= 208 && bpm >= 200)
{
jLabel5.setText("Prestissimo");
}
if(btnStart.getText().equals("Stop"))
{
double noteLength = 1 / (((double) this.bpm / 60) / 1000);
playNote.cancel();
playNote = new PlayNote((int) this.beats, this.compound);
noteTimer.schedule(playNote, 0, (long) noteLength);
}
}
}//GEN-LAST:event_jSlider1StateChanged
private void btnStartActionPerformed(java.awt.event.ActionEvent evt)
{//GEN-FIRST:event_btnStartActionPerformed
if(btnStart.getText().equals("Start"))
{
btnStart.setText("Stop");
double noteLength = 1 / (((double) bpm / 60) / 1000);
playNote = new PlayNote((int) this.beats, this.compound);
noteTimer.schedule(playNote, 0, (long) noteLength);
}
else
{
noteTimer.purge();
playNote.cancel();
btnStart.setText("Start");
}
}//GEN-LAST:event_btnStartActionPerformed
private void rb44ActionPerformed(java.awt.event.ActionEvent evt) {//GENFIRST:event_rb44ActionPerformed
resetTempo();
}//GEN-LAST:event_rb44ActionPerformed
private void rb54ActionPerformed(java.awt.event.ActionEvent evt) {//GENFIRST:event_rb54ActionPerformed
resetTempo();
}//GEN-LAST:event_rb54ActionPerformed
private void rb34ActionPerformed(java.awt.event.ActionEvent evt) {//GENFIRST:event_rb34ActionPerformed
resetTempo();
}//GEN-LAST:event_rb34ActionPerformed
private void rb24ActionPerformed(java.awt.event.ActionEvent evt) {//GENFIRST:event_rb24ActionPerformed
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
202
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
resetTempo();
}//GEN-LAST:event_rb24ActionPerformed
private void rb68ActionPerformed(java.awt.event.ActionEvent evt) {//GENFIRST:event_rb68ActionPerformed
resetTempo();
}//GEN-LAST:event_rb68ActionPerformed
private void rb128ActionPerformed(java.awt.event.ActionEvent evt) {//GENFIRST:event_rb128ActionPerformed
resetTempo();
}//GEN-LAST:event_rb128ActionPerformed
private void rbCustomActionPerformed(java.awt.event.ActionEvent evt)
{//GEN-FIRST:event_rbCustomActionPerformed
resetTempo();
}//GEN-LAST:event_rbCustomActionPerformed
private void resetTempo()
{
if(btnStart.getText().equals("Stop"))
{
//
btnStart.setText("Stop");
double noteLength = 1 / (((double) bpm / 60) / 1000);
if(this.rb44.isSelected())
{
beats = 4;
compound = false;
}
if(rbCustom.isSelected())
{
// allows program to handle illogical entry into text
field
try
{
textTest =
Double.valueOf(this.jTextField2.getText());
}
catch(NumberFormatException ex)
{
ex.printStackTrace();
}
if(this.textTest >= 1 && this.textTest < 101)
{
beats = Double.valueOf(this.jTextField2.getText());
compound = false;
jLabel7.setText("");
}
else
{
jLabel7.setText("Try a different custom time.");
}
}
if(this.rb54.isSelected())
{
beats = 5;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
203
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
compound = false;
}
if(rb34.isSelected())
{
beats = 3;
compound = false;
}
if(rb24.isSelected())
{
beats = 2;
compound = false;
}
if(rb68.isSelected())
{
beats = 6;
compound = true;
}
if(rb98.isSelected())
{
beats = 9;
compound = true;
}
if(rb128.isSelected())
{
beats = 12;
compound = true;
}
noteTimer.purge();
if(playNote != null)
{
playNote.cancel();
playNote = null;
}
playNote = new PlayNote((int) this.beats, this.compound);
noteTimer.schedule(playNote, 0, (long) noteLength);
//}
}
else
{
noteTimer.purge();
playNote.cancel();
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnStart;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JLabel jLabel6;
private javax.swing.JLabel jLabel7;
private javax.swing.JSlider jSlider1;
private javax.swing.JTextField jTextField2;
private javax.swing.JRadioButton rb128;
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
204
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
private javax.swing.JRadioButton rb24;
private javax.swing.JRadioButton rb34;
private javax.swing.JRadioButton rb44;
private javax.swing.JRadioButton rb54;
private javax.swing.JRadioButton rb68;
private javax.swing.JRadioButton rb98;
private javax.swing.JRadioButton rbCustom;
// End of variables declaration//GEN-END:variables
}
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
205
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
<?xml version="1.0"?>
<!-- ============================================================== -->
<!-- A Buildfile
-->
<!-- ============================================================== -->
<project name="ScoreEditor" default="jar" basedir=".">
<target name="variables">
<tstamp/>
<property name="Name"
value="ScoreEditor"/>
<property name="src.dir" value="${basedir}${file.separator}src"/>
<property name="lib.dir"
value="${basedir}${file.separator}libs"/>
<property name="build.dir"
value="${basedir}${file.separator}build"/>
<property name="build.classes"value="${build.dir}${file.separator}classes"/>
<property name="build.jar.dir" value="${build.dir}${file.separator}jars"/>
<property name="build.jar"
value="${build.jar.dir}${file.separator}${Name}.jar"/>
<property name="build.classpath"
value=".:${lib.dir}${file.separator}jmusic.jar"/>
<property name="images.src"
value="${src.dir}${file.separator}diamouses${file.separator}ui${file.sepa
rator}scoreEditor${file.separator}images"/>
<property name="images.dest"
value="${build.classes}${file.separator}diamouses${file.separator}ui${fil
e.separator}scoreEditor${file.separator}images"/>
<property name="packages"
value="*"/>
</target>
<!-- ============================================================== -->
<!-- Create required directories
-->
<!-- ============================================================== -->
<target name="init" depends="variables">
<!-- Prepare necessary directories -->
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes}"/>
<mkdir dir="${build.jar.dir}"/>
<mkdir dir="${images.dest}"/>
<!-- Copy all the images to the build directory -->
<copy todir="${images.dest}">
<fileset dir="${images.src}" casesensitive="yes">
<include name="**/*.*"/>
</fileset>
</copy>
</target>
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
206
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
<!-- ============================================================== -->
<!-- Compiles the source code
-->
<!-- ============================================================== -->
<target name="compile" depends="init" description="Compiles source
code">
<javac encoding="UTF-8"
srcdir="${src.dir}"
destdir="${build.classes}"
classpath="${build.classpath}"
optimize="on"
/>
</target>
<!-- ===============================================================-->
<!-- Creates a jar archive
-->
<!-- ============================================================== -->
<target name="jar" depends="init,compile" description="Generates
ScoreEditor.jar" >
<!-- Put everything from ${build.dir} into the ScoreEditor.jar file -->
<jar
manifest="${src.dir}/myManifest.txt"
jarfile="${build.jar.dir}${file.separator}${Name}.jar"
basedir="${build.classes}"
includes="**"
/>
<copy todir="${build.jar.dir}">
<fileset dir="${src.dir}" casesensitive="yes">
<include name="**/*.html"/>
</fileset>
</copy>
<copy todir="${build.jar.dir}">
<fileset dir="${lib.dir}" casesensitive="yes">
<include name="**/*.jar"/>
</fileset>
</copy>
</target>
<!-- ============================================================== -->
<!-- Cleans up all
-->
<!-- ============================================================== -->
<target name="clean" depends="init" description="Removes previous
build (classes and jar files)">
<delete dir="${build.classes}"/>
<delete dir="${build.jar.dir}"/>
</target>
<!-- ============================================================== -->
<!-- Run Score Editor
-->
<!-- ============================================================== -->
<target name="run" depends="init,compile,jar" description="Initiates
ScoreEditor.java">
<echo message = "Running ScoreEditor"/>
<java
jar="${build.jar.dir}${file.separator}${Name}.jar"
fork="true"
>
</java>
</target>
</project>
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
207
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
JavaDoc of GuitarNeck object
Overview Package Class Use Tree Deprecated Index Help
PREV CLASS NEXT CLASS
SUMMARY: NESTED | FIELD | CONSTR | METHOD
FRAMES NO FRAMES All Classes All Classes
DETAIL: FIELD | CONSTR | METHOD
diamouses.ui.scoreEditor
Class GuitarNeck
java.lang.Object
java.awt.Component
java.awt.Container
javax.swing.JComponent
javax.swing.JPanel
diamouses.ui.scoreEditor.GuitarNeck
All Implemented Interfaces:
java.awt.image.ImageObserver, java.awt.MenuContainer, java.io.Serializable,
javax.accessibility.Accessible
public class GuitarNeck
extends javax.swing.JPanel
See Also:
Serialized Form
Nested Class Summary
Nested classes/interfaces inherited from class javax.swing.JPanel
javax.swing.JPanel.AccessibleJPanel
Nested classes/interfaces inherited from class javax.swing.JComponent
javax.swing.JComponent.AccessibleJComponent
Nested classes/interfaces inherited from class java.awt.Container
java.awt.Container.AccessibleAWTContainer
Nested classes/interfaces inherited from class java.awt.Component
java.awt.Component.AccessibleAWTComponent,
java.awt.Component.BaselineResizeBehavior,
java.awt.Component.BltBufferStrategy,
java.awt.Component.FlipBufferStrategy
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
208
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Field Summary
(package private) color_1st
java.awt.Color
(package private) color_2nd
java.awt.Color
(package private) color_3rd
java.awt.Color
(package private) color_4th
java.awt.Color
(package private) color_5th
java.awt.Color
(package private) color_6th
java.awt.Color
private fret_buttons
javax.swing.JToggleButton[][]
private
javax.swing.JPanel fret_panel
private
int height
Global variables for the application
(package private) ii
javax.swing.ImageIcon
private static GuitarNeck reference
private
private
int screen_width
javax.swing.JPanel[] string_panels
Fields inherited from class javax.swing.JComponent
accessibleContext,
listenerList,
TOOL_TIP_TEXT_KEY,
ui,
UNDEFINED_CONDITION,
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
WHEN_FOCUSED,
WHEN_IN_FOCUSED_WINDOW
Fields inherited from class java.awt.Component
BOTTOM_ALIGNMENT,
TOP_ALIGNMENT
CENTER_ALIGNMENT,
LEFT_ALIGNMENT,
RIGHT_ALIGNMENT,
Fields inherited from interface java.awt.image.ImageObserver
ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, WIDTH
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
209
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
Constructor Summary
private GuitarNeck(int screen_width)
Constructor.
Method Summary
void clearAll()
private getIconsForString(int string)
javax.swing.ImageIcon[]
Method getIconsForString returns
an Array [] of
ImageIcons with the images of the appropriate Notes for
each string of the Guitar.
static GuitarNeck getInstance()
static GuitarNeck getInstance(int mm)
private getStringPanel()
javax.swing.JPanel
Method returns
a JPanel with JButtons for each note
of the Guitar
static void main(java.lang.String[] args)
Main -> For testing purposes
void paintComponent(java.awt.Graphics g)
Method Paint the Guitar Neck on the Background of
this JPanel.
void setNote(int pitch)
Sets the note with a specific pitch on the virtual guitar
private
void setSizes()
This method sets the sizes of the JToggleButtons
private
void switchColor(int string)
Switch the color of the string
Methods inherited from class javax.swing.JPanel
getAccessibleContext, getUI, getUIClassID, paramString, setUI, updateUI
Methods inherited from class javax.swing.JComponent
addAncestorListener,
addNotify,
addVetoableChangeListener,
computeVisibleRect,
contains,
createToolTip,
disable,
enable,
firePropertyChange,
firePropertyChange,
firePropertyChange,
fireVetoableChange, getActionForKeyStroke, getActionMap, getAlignmentX,
getAlignmentY,
getAncestorListeners,
getAutoscrolls,
getBaseline,
getBaselineResizeBehavior,
getBorder,
getBounds,
getClientProperty,
getComponentGraphics,
getComponentPopupMenu,
getConditionForKeyStroke,
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
210
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
getDebugGraphicsOptions, getDefaultLocale, getFontMetrics, getGraphics,
getHeight,
getInheritsPopupMenu,
getInputMap,
getInputMap,
getInputVerifier,
getInsets,
getInsets,
getListeners,
getLocation,
getMaximumSize,
getMinimumSize,
getNextFocusableComponent,
getPopupLocation, getPreferredSize, getRegisteredKeyStrokes, getRootPane,
getSize,
getToolTipLocation,
getToolTipText,
getToolTipText,
getTopLevelAncestor, getTransferHandler, getVerifyInputWhenFocusTarget,
getVetoableChangeListeners,
getVisibleRect,
getWidth,
getX,
getY,
grabFocus,
isDoubleBuffered,
isLightweightComponent,
isManagingFocus,
isOpaque, isOptimizedDrawingEnabled, isPaintingForPrint, isPaintingTile,
isRequestFocusEnabled, isValidateRoot, paint, paintBorder, paintChildren,
paintImmediately,
paintImmediately,
print,
printAll,
printBorder,
printChildren,
printComponent,
processComponentKeyEvent,
processKeyBinding,
processKeyEvent,
processMouseEvent,
processMouseMotionEvent,
putClientProperty,
registerKeyboardAction,
registerKeyboardAction,
removeAncestorListener,
removeNotify,
removeVetoableChangeListener,
repaint,
repaint,
requestDefaultFocus,
requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow,
resetKeyboardActions,
reshape,
revalidate,
scrollRectToVisible,
setActionMap,
setAlignmentX,
setAlignmentY,
setAutoscrolls,
setBackground, setBorder, setComponentPopupMenu, setDebugGraphicsOptions,
setDefaultLocale, setDoubleBuffered, setEnabled, setFocusTraversalKeys,
setFont,
setForeground,
setInheritsPopupMenu,
setInputMap,
setInputVerifier,
setMaximumSize,
setMinimumSize,
setNextFocusableComponent,
setOpaque,
setPreferredSize,
setRequestFocusEnabled,
setToolTipText,
setTransferHandler,
setUI,
setVerifyInputWhenFocusTarget,
setVisible,
unregisterKeyboardAction,
update
Methods inherited from class java.awt.Container
add,
add,
add,
add,
add,
addContainerListener,
addImpl,
addPropertyChangeListener,
addPropertyChangeListener,
applyComponentOrientation,
areFocusTraversalKeysSet,
countComponents,
deliverEvent, doLayout, findComponentAt, findComponentAt, getComponent,
getComponentAt,
getComponentAt,
getComponentCount,
getComponents,
getComponentZOrder,
getContainerListeners,
getFocusTraversalKeys,
getFocusTraversalPolicy, getLayout, getMousePosition, insets, invalidate,
isAncestorOf,
isFocusCycleRoot,
isFocusCycleRoot,
isFocusTraversalPolicyProvider, isFocusTraversalPolicySet, layout, list,
list,
locate,
minimumSize,
paintComponents,
preferredSize,
printComponents, processContainerEvent, processEvent, remove, remove,
removeAll,
removeContainerListener,
setComponentZOrder,
setFocusCycleRoot,
setFocusTraversalPolicy,
setFocusTraversalPolicyProvider,
setLayout,
transferFocusBackward,
transferFocusDownCycle, validate, validateTree
Methods inherited from class java.awt.Component
action,
add,
addComponentListener,
addFocusListener,
addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener,
addKeyListener,
addMouseListener,
addMouseMotionListener,
addMouseWheelListener, bounds, checkImage, checkImage, coalesceEvents,
contains,
createImage,
createImage,
createVolatileImage,
createVolatileImage, disableEvents, dispatchEvent, enable, enableEvents,
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
211
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
enableInputMethods,
firePropertyChange,
firePropertyChange,
firePropertyChange,
firePropertyChange,
firePropertyChange,
firePropertyChange,
getBackground,
getBounds,
getColorModel,
getComponentListeners, getComponentOrientation, getCursor, getDropTarget,
getFocusCycleRootAncestor,
getFocusListeners,
getFocusTraversalKeysEnabled,
getFont,
getForeground,
getGraphicsConfiguration,
getHierarchyBoundsListeners,
getHierarchyListeners,
getIgnoreRepaint,
getInputContext,
getInputMethodListeners,
getInputMethodRequests,
getKeyListeners,
getLocale,
getLocation,
getLocationOnScreen,
getMouseListeners,
getMouseMotionListeners,
getMousePosition,
getMouseWheelListeners,
getName,
getParent,
getPeer,
getPropertyChangeListeners,
getPropertyChangeListeners, getSize, getToolkit, getTreeLock, gotFocus,
handleEvent,
hasFocus,
hide,
imageUpdate,
inside,
isBackgroundSet,
isCursorSet,
isDisplayable,
isEnabled,
isFocusable,
isFocusOwner,
isFocusTraversable,
isFontSet,
isForegroundSet,
isLightweight,
isMaximumSizeSet,
isMinimumSizeSet,
isPreferredSizeSet,
isShowing,
isValid,
isVisible,
keyDown,
keyUp,
list,
list,
list,
location,
lostFocus,
mouseDown,
mouseDrag,
mouseEnter,
mouseExit,
mouseMove,
mouseUp,
move,
nextFocus,
paintAll,
postEvent,
prepareImage,
prepareImage,
processComponentEvent,
processFocusEvent,
processHierarchyBoundsEvent,
processHierarchyEvent,
processInputMethodEvent,
processMouseWheelEvent,
remove,
removeComponentListener,
removeFocusListener,
removeHierarchyBoundsListener,
removeHierarchyListener,
removeInputMethodListener,
removeKeyListener,
removeMouseListener,
removeMouseMotionListener,
removeMouseWheelListener,
removePropertyChangeListener,
removePropertyChangeListener,
repaint,
repaint,
repaint,
resize,
resize,
setBounds,
setBounds,
setComponentOrientation,
setCursor,
setDropTarget,
setFocusable,
setFocusTraversalKeysEnabled, setIgnoreRepaint, setLocale, setLocation,
setLocation, setName, setSize, setSize, show, show, size, toString,
transferFocus, transferFocusUpCycle
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait,
wait, wait
Field Detail
height
private int height
Global variables for the application
screen_width
private int screen_width
fret_buttons
private javax.swing.JToggleButton[][] fret_buttons
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
212
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
string_panels
private javax.swing.JPanel[] string_panels
fret_panel
private javax.swing.JPanel fret_panel
ii
javax.swing.ImageIcon ii
color_1st
java.awt.Color color_1st
color_2nd
java.awt.Color color_2nd
color_3rd
java.awt.Color color_3rd
color_4th
java.awt.Color color_4th
color_5th
java.awt.Color color_5th
color_6th
java.awt.Color color_6th
reference
private static GuitarNeck reference
Constructor Detail
GuitarNeck
private GuitarNeck(int screen_width)
Constructor. Initializes 6 JPanels, one for each guitar string
Method Detail
getInstance
public static GuitarNeck getInstance(int mm)
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
213
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
getInstance
public static GuitarNeck getInstance()
getStringPanel
private javax.swing.JPanel getStringPanel()
Method returns a JPanel with JButtons for each note of the Guitar
Parameters:
string - First..Sixth string of the guitar
Returns:
a JPanel with appropriate JButtons
setSizes
private void setSizes()
This method sets the sizes of the JToggleButtons
paintComponent
public void paintComponent(java.awt.Graphics g)
Method Paint the Guitar Neck on the Background of this JPanel.
Overrides:
paintComponent in class javax.swing.JComponent
switchColor
private void switchColor(int string)
Switch the color of the string
Parameters:
string - values 1 to 6
getIconsForString
private javax.swing.ImageIcon[] getIconsForString(int string)
Method getIconsForString returns an Array [] of ImageIcons with the images of the
appropriate Notes for each string of the Guitar.
Parameters:
string - An integer from 1 to 6 representing the First..Sixth string of a Guitar.
Returns:
an ImageIcon [] array.
setNote
public void setNote(int pitch)
Sets the note with a specific pitch on the virtual guitar
Parameters:
pitch - the pitch value.
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
214
«Εικονική αναπαράσταση µουσικών κοινοτήτων στο διαδίκτυο»
clearAll
public void clearAll()
main
public static void main(java.lang.String[] args)
Main -> For testing purposes
Parameters:
args Overview Package Class Use Tree Deprecated Index Help
PREV CLASS NEXT CLASS
SUMMARY: NESTED | FIELD | CONSTR | METHOD
FRAMES NO FRAMES All Classes All Classes
DETAIL: FIELD | CONSTR | METHOD
Τµήµα Εφαρµοσµένης Πληροφορικής & Πολυµέσων
215
Fly UP