Σε αυτό το μάθημα, θα δημιουργήσουμε μια εφαρμογή που παίζει τόνους και μπορεί να συντονίσει μια κιθάρα. Θα μάθετε πώς να:
Εγκαταστήσετε ένα βασικό έργο χρησιμοποιώντας το Anjuta IDE.
Δημιουργήσετε ένα απλό GUI με τον σχεδιαστή UI του
Χρησιμοποιήσετε τη βιβλιοθήκη GStreamer για να παίξει ήχους.
Θα χρειαστείτε τα παρακάτω για να μπορέσετε να ακολουθήσετε αυτό το μάθημα:
Βασική γνώση της γλώσσας προγραμματισμού Vala.
Ένα εγκατεστημένο αντίγραφο του
Πριν ξεκινήσετε να προγραμματίζετε, πρέπει να δημιουργήσετε ένα καινούργιο έργο στο Anjuta. Έτσι θα δημιουργηθούν όλα τα απαραίτητα αρχεία που χρειάζονται για την εκτέλεση του κώδικα αργότερα. Επίσης θα ήταν χρήσιμο να τα κρατάτε όλα μαζί.
Ξεκινήστε το
Πατήστε στην καρτέλα
Βεβαιωθείτε ότι η
Κλικ στην
using GLib;
using Gtk;
Ο κώδικας φορτώνει ένα (κενό) παράθυρο από το αρχείο περιγραφής διεπαφής χρήστη και το εμφανίζει. Περισσότερες λεπτομέρειες δίνονται παρακάτω· μπορεί να επιλέξετε να προσπεράστε αυτή τη λίστα αν καταλαβαίνετε τα βασικά:
Οι δύο γραμμές using
εισάγουν χώρους ονομάτων έτσι ώστε να μην τους ονομάσουμε ρητά.
Ο κατασκευαστής της κλάσης Main
δημιουργεί ένα νέο παράθυρο ανοίγοντας ένα αρχείο GtkBuilder (
Η σύνδεση σημάτων είναι πώς ορίζετε τι συμβαίνει όταν πατάτε ένα κουμπί, ή όταν συμβεί κάποιο άλλο συμβάν. Εδώ, καλείται η συνάρτηση on_destroy
(και τερματίζει την εφαρμογή) όταν κλείνετε το παράθυρο.
Η στατική συνάρτηση main
τρέχει από προεπιλογή όταν ξεκινάτε μια εφαρμογή Vala. Καλεί λίγες συναρτήσεις που δημιουργούν την κύρια κλάση, ρυθμίζουν και έπειτα εκτελούν την εφαρμογή. Η συνάρτηση Gtk.main
ξεκινά τον κύριο βρόχο του GTK, που εκτελεί τη διεπαφή χρήστη και ξεκινά την απάντηση για συμβάντα (όπως κλικ και πατήματα πλήκτρου).
Αυτός ο κώδικας είναι έτοιμος να χρησιμοποιηθεί. έτσι μπορείτε να τον μεταγλωττίσετε με κλικ
Μια περιγραφή της διεπαφής χρήστη (UI) περιέχεται στο αρχείο του GtkBuilder
Η διάταξη κάθε διεπαφής χρήστη στο Gtk+ οργανώνεται σε πλαίσια και πίνακες. Ας χρησιμοποιήσουμε εδώ ένα κάθετο GtkButtonBox για να αποδώσουμε έξι GtkButtons, ένα για κάθε μία από τις έξι χορδές της κιθάρας.
Στην καρτέλα
Μπορείτε επίσης να αλλάξετε τον
Τώρα, από την ενότητα
Έχοντας το κουμπί ακόμα επιλεγμένο, κυλήστε κάτω στην καρτέλα
Η καρτέλα
Πηγαίνετε στην καρτέλα clicked
του κουμπιού. Μπορείτε να το χρησιμοποιήσετε για να συνδέσετε έναν χειριστή σημάτων που θα καλείται όταν πατηθεί το κουμπί από τον χρήστη. Για να το κάνετε αυτό, κλικ στο σήμα και πληκτρολογήστε main_on_button_clicked
στη στήλη
Επαναλάβετε τα παραπάνω βήματα για τα υπόλοιπα κουμπιά, προσθέστε τις επόμενες 5 χορδές με τα ονόματα A, D, G, B, και e.
Αποθηκεύστε τη σχεδίαση UI (πατώντας
Αυτή η ενότητα θα δείξει πώς να παράξει ο κώδικας ήχους. GStreamer είναι ο σκελετός πολυμέσων του GNOME - μπορείτε να τον χρησιμοποιήσετε για παίξιμο, εγγραφή και επεξεργασία βίντεο, ήχου, ροών ιστοκάμερας και τα παρόμοια. Εδώ, θα το χρησιμοποιήσουμε για να παράξουμε τόνους μιας συχνότητας.
Εννοιολογικά, το GStreamer λειτουργεί ως εξής: δημιουργείτε μια διοχέτευση που περιέχει διάφορα στοιχεία επεξεργασίας που πηγαίνουν από την πηγή στο ταμιευτήρα (έξοδο). Η πηγή μπορεί να είναι ένα αρχείο εικόνας, βίντεο, ή μουσικής, για παράδειγμα, και η έξοδος μπορεί να είναι γραφικό στοιχείο ή κάρτα ήχου.
Ανάμεσα στην πηγή και στην έξοδο, μπορείτε να εφαρμόσετε διάφορα φίλτρα και οι μετατροπείς να χειριστούν εφέ, μετατροπές μορφών και λοιπά. Κάθε στοιχείο της διοχέτευσης έχει ιδιότητες που μπορούν να χρησιμοποιηθούν για να αλλάξουν τη συμπεριφορά τους.
Ένα παράδειγμα διοχέτευσης GStreamer.
Σε αυτό το παράδειγμα θα χρησιμοποιήσουμε μια πηγή παραγωγής τόνων που λέγεται audiotestsrc
και θα στείλουμε την έξοδο στην προεπιλεγμένη συσκευή ήχου του συστήματος, autoaudiosink
. Πρέπει μόνο να ρυθμίσουμε την συχνότητα της παραγωγής τόνου· αυτό είναι διαθέσιμο μέσα από την ιδιότητα freq
του audiotestsrc
.
Χρειάζεται να προσθέσουμε μια γραμμή για αρχικοποίηση του GStreamer· βάλτε τον παρακάτω κώδικα στην γραμμή πάνω από την κλήση Gtk.init
στη συνάρτηση main
:
Gst.init (ref args);
Μετά, αντιγράψτε την ακόλουθη συνάρτηση στο Main
:
Gst.Element sink;
Gst.Element source;
Gst.Pipeline pipeline;
private void play_sound(double frequency)
{
pipeline = new Gst.Pipeline ("note");
source = Gst.ElementFactory.make ("audiotestsrc",
"source");
sink = Gst.ElementFactory.make ("autoaudiosink",
"output");
/* set frequency */
source.set ("freq", frequency);
pipeline.add (source);
pipeline.add (sink);
source.link (sink);
pipeline.set_state (Gst.State.PLAYING);
/* stop it after 200ms */
var time = new TimeoutSource(200);
time.set_callback(() => {
pipeline.set_state (Gst.State.NULL);
return false;
});
time.attach(null);
}
Οι τρεις πρώτες γραμμές δημιουργούν τα στοιχεία πηγή και έξοδο του GStreamer (Gst.Element
), και ένα στοιχείο διοχέτευσης (το οποίο θα χρησιμοποιηθεί σαν περιέκτης για τα δυο άλλα στοιχεία). Αυτά είναι μεταβλητές κλάσεων, έτσι ορίζονται έξω από τη μέθοδο. Δίνουμε το όνομα "note" στη διοχέτευση· ονομάζουμε την πηγή "source" και ρυθμίζεται στην πηγή audiotestsrc
· και ονομάζουμε την έξοδο "output" και ρυθμίζεται στην έξοδο autoaudiosink
(προεπιλεγμένη έξοδος κάρτας ήχου).
Η κλήση στο source.set
ορίζει την ιδιότητα freq
του στοιχείου πηγής σε frequency
, η οποία έχει περαστεί ως όρισμα στη συνάρτηση play_sound
. Αυτή είναι η συχνότητα της νότας σε Hertz· πολλές χρήσιμες συχνότητες θα οριστούν αργότερα.
Το pipeline.add
βάζει την πηγή και την έξοδο στη διοχέτευση. Η διοχέτευση είναι ένα Gst.Bin
,που είναι απλά ένα στοιχείο που μπορεί να περιέχει πολλαπλά άλλα στοιχεία GStreamer. Γενικά, μπορείτε να προσθέσετε όσα στοιχεία θέλετε στη διοχέτευση προσθέτοντας περισσότερες κλήσεις στο pipeline.add
.
Κατόπιν, το sink.link
χρησιμοποιείται για σύνδεση των στοιχείων μαζί, έτσι ώστε η έξοδος της πηγής (ένας τόνος) να πηγαίνει στην είσοδο της εξόδου (η οποία μετά είναι έξοδος στην κάρτα ήχου). Το pipeline.set_state
χρησιμοποιείται έπειτα για την εκκίνηση της αναπαραγωγής, ρυθμίζοντας την κατάσταση της σωλήνωσης να παίξει (Gst.State.PLAYING
).
Δεν θέλουμε να παίζουμε έναν ενοχλητικό ήχο για πάντα, οπότε το τελευταίο πράγμα που κάνει ο play_sound
είναι να προσθέσει έναν TimeoutSource
. Αυτό ορίζει ένα χρονικό όριο που θα σταματήσει τον ήχο· περιμένει για 200 ms πριν καλέσει τον χειριστή σήματος που ορίστηκε στη γραμμή που σταματά και καταστρέφει τη διοχέτευση. Επιστρέφει false
για να αφαιρέσει την ίδια από το χρονικό όριο, αλλιώς θα συνέχιζε να καλείται κάθε 200 ms.
Στον σχεδιαστή διεπαφών χρήστη, κάνατε όλα τα κουμπιά να καλούν την ίδια συνάρτηση, Main
μας. Πρέπει να προσθέσουμε αυτή την συνάρτηση στο πηγαίο αρχείο.
Για να το κάνετε αυτό, στο αρχείο διεπαφής χρήστη (guitar_tuner.ui), επιλέξτε ένα από τα κουμπιά με κλικ πάνω του, έπειτα ανοίξτε
public void on_button_clicked (Gtk.Button sender) {
}
Μπορείτε επίσης να πληκτρολογήσετε απλά των κώδικα στην αρχή της κλάσης αντί της χρήσης συρσίματος και απόθεσης.
Αυτός ο χειριστής σήματος έχει μόνο ένα όρισμα: το Gtk.Widget
που κάλεσε η συνάρτηση (στην περίπτωσή μας, πάντοτε ένα Gtk.Button
).
Θέλουμε να παίξουμε τον σωστό ήχο όταν ο χρήστης πατά ένα κουμπί. Για αυτό, ζωντανεύουμε τον χειριστή σήματος που ορίσαμε παραπάνω, on_button_clicked
. Θα μπορούσαμε να έχουμε συνδέσει κάθε κουμπί σε διαφορετικό χειριστή σήματος, αλλά αυτό θα μπορούσε να οδηγήσει σε εκτεταμένο διπλασιασμό του κώδικα. Αντίθετα, μπορούμε να χρησιμοποιήσουμε την ετικέτα του κουμπιού για να καταλάβουμε ποιο κουμπί πατήθηκε:
public void on_button_clicked (Gtk.Button sender) {
var label = sender.get_child () as Gtk.Label;
switch (label.get_label()) {
case "E":
play_sound (329.63);
break;
case "A":
play_sound (440);
break;
case "D":
play_sound (587.33);
break;
case "G":
play_sound (783.99);
break;
case "B":
play_sound (987.77);
break;
case "e":
play_sound (1318);
break;
default:
break;
}
}
Το Gtk.Button
που πατήθηκε περνά ως όρισμα (sender
) στο on_button_clicked
. Μπορούμε να πάρουμε την ετικέτα αυτού του κουμπιού χρησιμοποιώντας τον get_child
και έπειτα να πάρουμε το κείμενο από αυτήν την ετικέτα χρησιμοποιώντας get_label
.
Η πρόταση διακόπτη συγκρίνει το κείμενο ετικέτας με τις νότες που μπορούμε να παίξουμε και καλείται ο play_sound
με την κατάλληλη συχνότητα για αυτήν την νότα. Αυτό παίζει τον τόνο· ο ρυθμιστής κιθάρας είναι έτοιμος!
Όλος ο κώδικας πρέπει να είναι έτοιμος τώρα. Κλικ
Εάν δεν το έχετε ήδη κάνει, επιλέξτε την εφαρμογή
Αν αντιμετωπίσετε προβλήματα με το μάθημα, συγκρίνετε τον κώδικά σας με αυτόν τον κώδικα αναφοράς.
Για να βρείτε περισσότερα για τη γλώσσα προγραμματισμού Vala ίσως θελήσετε να κοιτάξετε το μάθημα Vala και το τεκμηρίωση API Vala
Εδώ είναι κάποιες ιδέες για το πώς μπορείτε να επεκτείνετε αυτή την απλή παρουσίαση:
Βάλτε το πρόγραμμα να περνάει αυτόματα μέσα από τις νότες.
Κάντε το πρόγραμμα να αναπαράγει ηχογραφήσεις από αληθινές χορδές κιθάρας που έχουν εισαχθεί.
Για να το κάνετε αυτό, πρέπει να ρυθμίσετε μια πιο περίπλοκη διοχέτευση GStreamer που θα σας επιτρέπει να φορτώνετε και να αναπαράγετε αρχεία ήχου. Θα πρέπει να διαλέξετε τα στοιχεία GStreamer decoder και demuxer με βάση τον τύπο του αρχείου των ηχογραφημένων ήχων — για παράδειγμα το MP3 χρησιμοποιεί διαφορετικά στοιχεία από το Ogg Vorbis.
Ίσως χρειαστεί να συνδέσετε τα στοιχεία με πιο περίπλοκους τρόπους. Αυτό μπορεί να συμπεριλαμβάνει τη χρήση Εννοιών GStreamer που δεν καλύπτουμε σε αυτόν τον οδηγό, όπως και pad. Ίσως βρείτε χρήσιμη και την εντολή
Αυτόματη ανάλυση νότων που παίζει ο χρήστης.
Μπορείτε να συνδέσετε μικρόφωνο και να ηχογραφήσετε από αυτό χρησιμοποιώντας την πηγή εισόδου. Ίσως κάποια μορφή της ανάλυσης φάσματος θα σας βοηθούσε να καταλάβετε ποια νότα παίζει;