# Συντονιστής κιθάρας (Python)

Χρησιμοποιήστε GTK+ και GStreamer για να φτιάξετε ένα απλό πρόγραμμα συντονιστή κιθάρας για το GNOME. Αναδεικνύει πώς να χρησιμοποιήσετε τον σχεδιαστή διεπαφών.
Έργο τεκμηρίωσης GNOME
gnome-doc-list@gnome.org
Johannes Schmid
jhs@gnome.org
Marta Maria Casetti
mmcasetti@gmail.com 2013
Marta Maria Casetti
mmcasetti@gmail.com 2013
Ελληνική μεταφραστική ομάδα GNOME
team@gnome.gr 2012-2015
Δημήτρης Σπίγγος
dmtrs32@gmail.com 2012, 2013
Μαρία Θουκιδίδου
marablack3@gmail.com 2014
Θάνος Τρυφωνίδης
tomtryf@gmail.com 2014, 2015

# Συντονιστής κιθάρας

      Σε αυτόν τον οδηγό, θα φτιάξουμε ένα πρόγραμμα που παίζει μουσικούς τόνους και μπορεί να συντονίσει μια κιθάρα. Θα μάθετε να:

        Ρυθμίζετε το κύριο έργο στο Anjuta
        Δημιουργείτε απλό GUI με τον σχεδιαστή UI του Anjuta
        Χρησιμοποιείτε το GStreamer για να παίζετε ήχους

      Θα χρειαστείτε τα παρακάτω για να μπορέσετε να ακολουθήσετε αυτό το μάθημα:

        Ένα εγκατεστημένο αντίγραφο του Anjuta IDE
        Βασική γνώση της γλώσσας προγραμματισμού Python

# Δημιουργία έργου με το Anjuta

Πριν ξεκινήσετε να προγραμματίζετε, πρέπει να δημιουργήσετε ένα καινούργιο έργο στο Anjuta. Έτσι θα δημιουργηθούν όλα τα απαραίτητα αρχεία που χρειάζονται για την εκτέλεση του κώδικα αργότερα. Επίσης θα ήταν χρήσιμο να τα κρατάτε όλα μαζί.

Ξεκινήστε το Anjuta και πατήστε αρχείονέοέργο για να ανοίξετε τον οδηγό του έργου.

Επιλέξτε PyGTK (automake) από την καρτέλα Python, πατήστε συνέχεια και συμπληρώστε τις λεπτομέρειές σας στις επόμενες λίγες σελίδες. Χρησιμοποιήστε ως όνομα του έργου και του καταλόγου το guitar-tuner.

Πατήστε Εφαρμογή και το έργο θα δημιουργηθεί. Ανοίξτε src/guitar_tuner.py από τις καρτέλες έργο ή αρχείο. Θα πρέπει να δείτε κάποιο κώδικα που ξεκινάει με τις γραμμές:

from gi.repository import Gtk, GdkPixbuf, Gdk import os, sys

# Εκτέλεση του κώδικα για πρώτη φορά

Ο περισσότερος κώδικας στο αρχείο είναι πρότυπο κώδικα. Φορτώνει ένα (κενό) παράθυρο από το αρχείο περιγραφής της διεπαφής χρήστη και το εμφανίζει. Περισσότερες πληροφορίες υπάρχουν πιο κάτω· προσπεράστε αυτή τη λίστα αν καταλαβαίνετε τα βασικά:

Οι γραμμές `import` στην αρχή λένε στην Python να φορτώσει τις βιβλιοθήκες του συστήματος και της διεπαφής χρήστη που χρειάζονται.

Μια κλάση δηλώνεται ότι θα είναι η κύρια κλάση για το πρόγραμμά μας. Στην μέθοδο `__init__` το κύριο παράθυρο φορτώνεται από το αρχείο GtkBuilder (src/guitar-tuner.ui) και τα σήματα συνδέονται.

Συνδέοντας σήματα είστε σε θέση να καθορίζετε τι θα συμβεί όταν ένα κουμπί πατηθεί, ή όταν συμβεί κάποιο άλλο σήμα. Εδώ, καλείται η μέθοδος `destroy` όταν κλείνετε το παράθυρο (και τερματίζει την εφαρμογή).

Η συνάρτηση `main` εκτελείται προκαθορισμένα μόλις τρέξετε ένα πρόγραμμα σε Python. Δημιουργεί ένα στιγμιότυπο της κύριας κλάσης και ξεκινάει τον κύριο βρόχο για να εμφανίσει το παράθυρο.

Ο κώδικας είναι έτοιμος να χρησιμοποιηθεί, οπότε μπορείτε να τον εκτελέσετε πηγαίνοντας ΕκτέλεσηΕκτέλεση.

# Δημιουργία της διεπαφής χρήστη

Μια περιγραφή της διεπαφής χρήστη (UI) περιέχεται στο αρχείο GtkBuilder. Για να επεξεργαστείτε τη διεπαφή χρήστη, ανοίξτε το src/guitar_tuner.ui. Θα βρεθείτε στο σχεδιαστή διεπαφής. Το παράθυρο σχεδίασης είναι στο κέντρο· τα γραφικά στοιχεία και οι ιδιότητες τους είναι στα δεξιά και η παλέτα των διαθέσιμων γραφικών στοιχείων στα αριστερά.

Η διάταξη κάθε διεπαφής χρήστη σε Gtk+ οργανώνεται σε κουτιά και πίνακες. Ας χρησιμοποιήσουμε εδώ ένα κάθετο GtkButtonBox για να τοποθετήσουμε έξι GtkButtons, ένα για κάθε μία από τις χορδές της κιθάρας.

Διαλέξτε ένα GtkButtonBox από το τμήμα Container στην Παλέτα στο δεξιά και προσθέστε το στο παράθυρο. Στο φάτνωμα Ιδιότητες καθορίστε τον αριθμό των στοιχείων σε 6 (για τις έξι χορδές της κιθάρας) και τον προσανατολισμό σε κάθετο.

Τώρα, διαλέξτε ένα GtkButton από την παλέτα και βάλτε το στο πρώτο μέρος του κουτιού.

Έχοντας το κουμπί ακόμα επιλεγμένο, αλλάξτε την Ετικέτα στην καρτέλα Γραφικά στοιχεία σε E. Αυτή θα είναι η χαμηλή χορδή Ε.

Πηγαίνετε στην καρτέλα Σήματα (μέσα στην καρτέλα Γραφικά στοιχεία) και βρείτε το σήμα `clicked` του κουμπιού. Μπορείτε να το χρησιμοποιήσετε για να συνδέσετε έναν χειριστή σημάτων που θα καλείται όταν πατηθεί το κουμπί από τον χρήστη. Για να το κάνετε αυτό, πατήστε πάνω στο σήμα και πληκτρολογήστε `on_button_clicked` στη στήλη χειριστής και πατήστε Επιστροφή.

Επαναλάβετε τα παραπάνω βήματα για τα υπόλοιπα κουμπιά, προσθέστε τις επόμενες 5 χορδές με τα ονόματα A, D, G, B, και e.

Αποθηκεύστε τη σχεδίαση UI (πατώντας αρχείοαποθήκευση) και κρατήστε το ανοιχτό.

# Εγγραφή του χειριστή σημάτων

Στον σχεδιαστή διεπαφών χρήστη, κάνατε όλα τα κουμπιά να καλούν την ίδια συνάρτηση, on_button_clicked, όταν πατηθούν. Πρέπει να προσθέσουμε αυτή την συνάρτηση στο πηγαίο κώδικα.

Για να το κάνετε αυτό, ανοίξτε το guitar_tuner.py, έχοντας ανοιχτό και το αρχείο της διεπαφής χρήστη. Πηγαίνετε στην καρτέλα σήματα που είχατε χρησιμοποιήσει για να ορίσετε το όνομα του σήματος. Τώρα πάρτε την γραμμή όπου ορίσατε το σήμα clicked και σύρετε την στον πηγαίο κώδικα μέσα στην κλάση. Ο ακόλουθος κώδικας θα προστεθεί στον πηγαίο σας αρχείο:

def on_button_clicked (self, button):

Ο χειριστής σημάτων έχει δυο παράμετρους: τον τυπικό δείκτη κλάσης της Python και το `Gtk.Button` που καλεί την συνάρτηση.

Για την ώρα, θα αφήσουμε το χειριστή σημάτων άδειο καθώς θα ασχοληθούμε με το γράψιμο του κώδικα που θα παράγει τους ήχους.

# Διοχετεύσεις GStreamer

Το Gtreamer είναι ο σκελετός πολυμέσων του GNOME — μπορείτε να το χρησιμοποιήσετε για να αναπαράγετε, ηχογραφήσετε, και να επεξεργαστείτε βίντεο, ήχο, ροές βίντεο και τα λοιπά. Εδώ, θα το χρησιμοποιήσουμε για να παράγουμε μονές-συχνότητες τόνων.

Εννοιολογικά, το GStreamer λειτουργεί ως εξής: δημιουργείς μια διοχέτευση που περιέχει διάφορα επεξεργαζόμενα στοιχεία που πηγαίνουν από την πηγή στην έξοδο. Η πηγή μπορεί να είναι ένα αρχείο εικόνας, βίντεο, ή και μουσικής, για παράδειγμα, και η έξοδος μπορεί να είναι ένα γραφικό στοιχείο ή η κάρτα ήχου.

Ανάμεσα στην πηγή και στην έξοδο, μπορείτε να εφαρμόσετε διάφορα φίλτρα και οι μετατροπείς να χειριστούν εφέ, μετατροπές μορφών και λοιπά. Κάθε στοιχείο της διοχέτευσης έχει ιδιότητες που μπορούν να χρησιμοποιηθούν για να αλλάξουν τη συμπεριφορά τους.

Ένα παράδειγμα διοχέτευσης GStreamer.

# Ρύθμιση της διοχέτευσης

Σε αυτό το απλό παράδειγμα θα χρησιμοποιήσουμε μια πηγή παραγωγής τόνων, την `audiotestsrc` και θα στείλουμε την έξοδο στην προεπιλεγμένη συσκευή ήχου του συστήματος, `autoaudiosink`. Πρέπει μόνο να ρυθμίσουμε την συχνότητα της παραγωγής τόνου· αυτό είναι εφικτό μέσα από την ρύθμιση `freq` του `audiotestsrc`.

Αλλάξτε τη γραμμή import στο αρχείο guitar_tuner.py, μόνο στην αρχή σε :

from gi.repository import Gtk, Gst, GObject

Το `Gst` περιέχει τη βιβλιοθήκη GStreamer. Επίσης πρέπει να αρχικοποιήσετε σωστά το GStreamer το οποίο γίνεται στη μέθοδο `main()` με την προσθήκη αυτής γραμμής πάνω από την γραμμή `app = GUI()`:

Gst.init_check(sys.argv)

Μετά, αντιγράψτε την ακόλουθη συνάρτηση κάπου στην κλάση στο guitar_tuner.py:

def play_sound(self, frequency): pipeline = Gst.Pipeline(name='note') source = Gst.ElementFactory.make('audiotestsrc', 'src') sink = Gst.ElementFactory.make('autoaudiosink', 'output')

source.set_property('freq', frequency) pipeline.add(source) pipeline.add(sink) source.link(sink) pipeline.set_state(Gst.State.PLAYING)

GObject.timeout_add(self.LENGTH, self.pipeline_stop, pipeline)

Οι τρεις πρώτες γραμμές δημιουργούν τα στοιχεία πηγή, έξοδος και διοχέτευση (το οποίο θα χρησιμοποιηθεί σαν υποδοχέας για τα δυο άλλα στοιχεία). Δίνουμε το όνομα "note" στη διοχέτευση· ονομάζουμε την πηγή "source" και το ρυθμίζετε στην πηγή `audiotestsrc`· και ονομάζουμε την έξοδο "output" και την ρυθμίζετε στην έξοδο `autoaudiosink` (προεπιλεγμένη κάρτα ήχου).

Το κάλεσμα της `source.set_property` ορίζει την ιδιότητα `freq` του στοιχείου πηγή σε `frequency`, η οποία έχει περαστεί σαν παράμετρος στη συνάρτηση `play_sound`. Αυτή είναι η συχνότητα της νότας σε Hertz· πολλές χρήσιμες συχνότητες θα οριστούν αργότερα.

Οι επόμενες δύο γραμμές καλούν το `pipeline.add`, βάζοντας την πηγή και την έξοδο στη διοχέτευση. Η διοχέτευση μπορεί να περιέχει διάφορα στοιχεία του GStreamer. Γενικά, μπορείτε να προσθέσετε όσα στοιχεία θέλετε στη διοχέτευση καλώντας συνεχόμενα τη μέθοδο `add`.

Μετά η `pipeline.set_state` χρησιμοποιείται για να ξεκινήσει η αναπαραγωγή, αλλάζοντας την κατάσταση της διοχέτευσης σε αναπαραγωγή (`Gst.State.PLAYING`).

# Διακοπή αναπαραγωγής

Δεν θέλουμε να παίζουμε έναν ενοχλητικό ήχο για πάντα, οπότε το τελευταίο πράγμα που κάνει η `play_sound` είναι να καλεί το `GObject.timeout_add`. Αυτό ορίζει ένα χρονικό περιθώριο που θα σταματήσει τον ήχο· περιμένει για `LENGTH` χιλιοστά του δευτερολέπτου πριν καλέσει τη συνάρτηση `pipeline_stop`, και θα συνεχίσει να την καλεί μέχρι η `pipeline_stop` να επιστρέψει `False`.

Τώρα θα γράψουμε τη συνάρτηση `pipeline_stop`, η οποία καλείται από το `GObject.timeout_add`. Προσθέστε τον ακόλουθο κώδικα πάνω από τη συνάρτηση `play_sound`:

def pipeline_stop(self, pipeline): pipeline.set_state(Gst.State.NULL) return False

Πρέπει να ορίσετε τη σταθερά `LENGTH` μέσα στην κλάση, οπότε προσθέστε αυτόν τον κώδικα στην αρχή της κύριας κλάσης:

LENGTH = 500

Η κλήση στη `pipeline.set_state` σταματά την αναπαραγωγή της διοχέτευσης.

# Ορισμός των τόνων

Θέλουμε να παίζουμε το σωστό ήχο όταν ο χρήστης πατάει ένα κουμπί. Πρώτα από όλα, χρειαζόμαστε να ξέρουμε τις συχνότητες για τις έξι χορδές της κιθάρας, οι οποίες είναι ορισμένες (στην αρχή της κύριας κλάσης) μέσα σε ένα λεξικό ώστε να μπορούμε εύκολα να τις απεικονίσουμε στα ονόματα των χορδών:

# Frequencies of the strings frequencies = { 'E': 329.63, 'A': 440, 'D': 587.33, 'G': 783.99, 'B': 987.77, 'e': 1318.5 }

Για να δούμε τον χειριστή σημάτων που ορίσαμε πριν, `on_button_clicked`. Θα μπορούσαμε να είχαμε συνδέσει όλα τα κουμπιά σε διαφορετικό χειριστή σημάτων, αλλά αυτό θα οδηγούσε σε πολλές επαναλήψεις του κώδικα. Αντί αυτού, μπορούμε να χρησιμοποιήσουμε τις ετικέτες στα κουμπιά για να δούμε ποιο πατήθηκε:

def on_button_clicked(self, button): label = button.get_child() text = label.get_label()

self.play_sound (self.frequencies[text])

Το κουμπί που πατήθηκε περνάει σαν παράμετρος (`button`) στο `on_button_clicked`. Μπορούμε να πάρουμε την ετικέτα του κουμπιού χρησιμοποιώντας το `button.get_child`, και το κείμενο από την ετικέτα χρησιμοποιώντας το `label.get_label`.

Το κείμενο της ετικέτας χρησιμοποιείται σαν κλειδί για το λεξικό και καλείται η `play_sound` με την κατάλληλη συχνότητα από την νότα. Αυτό παίζει τον τόνο· ο συντονιστής κιθάρας είναι έτοιμος!

# Τρέξτε την εφαρμογή

Το πρόγραμμα πρέπει να είναι έτοιμο τώρα. Για να ξεκινήσετε το πρόγραμμα πατήστε ΕκτέλεσηΕκτέλεση. Απολαύστε το!

# Υλοποίηση αναφοράς

Αν αντιμετωπίσετε προβλήματα με το μάθημα, συγκρίνετε τον κώδικά σας με αυτόν τον κώδικα αναφοράς.

# Επόμενα βήματα

Εδώ είναι κάποιες ιδέες για το πώς μπορείτε να επεκτείνετε αυτή την απλή παρουσίαση:

Βάλτε το πρόγραμμα να περνάει αυτόματα μέσα από τις νότες.

Κάντε το πρόγραμμα να αναπαράγει ηχογραφήσεις από αληθινές χορδές κιθάρας που έχουν εισαχθεί.

Για να το κάνετε αυτό, πρέπει να ρυθμίσετε μια πιο περίπλοκη διοχέτευση GStreamer που θα σας επιτρέπει να φορτώνετε και να αναπαράγετε αρχεία ήχου. Θα πρέπει να διαλέξετε τα στοιχεία GStreamer decoder και demuxer με βάση τον τύπο του αρχείου των ηχογραφημένων ήχων — για παράδειγμα το MP3 χρησιμοποιεί διαφορετικά στοιχεία από το Ogg Vorbis.

Ίσως χρειαστεί να συνδέσετε τα στοιχεία με πιο περίπλοκους τρόπους. Αυτό μπορεί να συμπεριλαμβάνει τη χρήση Εννοιών GStreamer που δεν καλύπτουμε σε αυτόν τον οδηγό, όπως και pad. Ίσως βρείτε χρήσιμη και την εντολή gst-inspect.

Αυτόματη ανάλυση νότων που παίζει ο χρήστης.

Μπορείτε να συνδέσετε μικρόφωνο και να ηχογραφήσετε από αυτό χρησιμοποιώντας την πηγή εισόδου. Ίσως κάποια μορφή της ανάλυσης φάσματος θα σας βοηθούσε να καταλάβετε ποια νότα παίζει;