In this tutorial you will create an application which plays tones that you can use to tune a guitar. You will learn how to:
Set up a basic project using the Anjuta IDE.
Create a simple GUI with
Use the GStreamer library to play sounds.
You'll need the following to be able to follow this tutorial:
Basic knowledge of the Vala programming language.
An installed copy of
Antes de comezar a programar, deberá configurar un proxecto novo en Anjuta. Isto creará todos os ficheiros que precise para construír e executar o código máis adiante. Tamén é útil para manter todo ordenado.
Start
Click on the
Make sure that
Click
The code loads an (empty) window from the user interface description file and displays it. More details are given below; you may choose to skip this list if you understand the basics:
The two using
lines import namespaces so we don't have to name them explicitly.
The constructor of the Main
class creates a new window by opening a GtkBuilder file (
Connecting signals is how you define what happens when you push a button, or when some other event happens. Here, the on_destroy
function is called (and quits the app) when you close the window.
The static main
function is run by default when you start a Vala application. It calls a few functions which create the Main class, set up and then run the application. The Gtk.main
function starts the GTK main loop, which runs the user interface and starts listening for events (like clicks and key presses).
This code is ready to be used, so you can compile it by clicking
A description of the user interface (UI) is contained in the GtkBuilder file
The layout of every UI in GTK+ is organized using boxes and tables. Let's use a vertical GtkButtonBox here to assign six GtkButtons, one for each of the six guitar strings.
In the
You can also change the
Now, from the
While the button is still selected, scroll down in the
The
Click on the clicked
signal of the button. You can use this to connect a signal handler that will be called when the button is clicked by the user. To do this, click on the signal and type main_on_button_clicked
in the
Repita os pasos anteriores para o resto dos botóns, engadindo as 5 cordas restantes cos nomes A, D, G, B e e.
Garde o deseño da IU (premendo
This section will show you how to create the code to produce sounds. GStreamer is GNOME's multimedia framework — you can use it for playing, recording, and processing video, audio, webcam streams and the like. Here, we'll be using it to produce single-frequency tones.
Conceptually, GStreamer works as follows: You create a pipeline containing several processing elements going from the source to the sink (output). The source can be an image file, a video, or a music file, for example, and the output could be a widget or the soundcard.
Between source and sink, you can apply various filters and converters to handle effects, format conversions and so on. Each element of the pipeline has properties which can be used to change its behaviour.
Un exemplo de tubería de GStreamer.
In this example we will use a tone generator source called audiotestsrc
and send the output to the default system sound device, autoaudiosink
. We only need to configure the frequency of the tone generator; this is accessible through the freq
property of audiotestsrc
.
We need to add a line to initialize GStreamer; put the following code on the line above the Gtk.init
call in the main
function:
Then, copy the following function into Main
class:
{
pipeline.set_state (Gst.State.NULL);
return false;
});
time.attach(null);
}]]>
The first three lines create source and sink GStreamer elements (Gst.Element
), and a pipeline element (which will be used as a container for the other two elements). Those are class variables so they are defined outside the method. The pipeline is given the name "note"; the source is named "source" and is set to the audiotestsrc
source; and the sink is named "output" and set to the autoaudiosink
sink (default sound card output).
The call to source.set
sets the freq
property of the source element to frequency
, which is passed in as an argument to the play_sound
function. This is just the frequency of the note in Hertz; some useful frequencies will be defined later on.
pipeline.add
puts the source and sink into the pipeline. The pipeline is a Gst.Bin
, which is just an element that can contain multiple other GStreamer elements. In general, you can add as many elements as you like to the pipeline by adding more calls to pipeline.add
.
Next, sink.link
is used to connect the elements together, so the output of source (a tone) goes into the input of sink (which is then output to the sound card). pipeline.set_state
is then used to start playback, by setting the state of the pipeline to playing (Gst.State.PLAYING
).
We don't want to play an annoying tone forever, so the last thing play_sound
does is to
add a TimeoutSource
. This sets a timeout for stopping the sound; it waits for 200 milliseconds before
calling a signal handler defined inline that stops and destroys the pipeline. It returns false
to
remove itself from the timeout, otherwise it would continue to be called every 200 ms.
In the UI designer, you made it so that all of the buttons will call the same function, Main
. We need to add that function in the source file.
To do this, in the user interface file (guitar_tuner.ui) select one of the buttons by clicking on it, then open
You can also just type the code at the beginning of the class instead of using the drag and drop.
This signal handler has only one argument: the Gtk.Widget
that called the function (in our case, always a Gtk.Button
).
We want to play the correct sound when the user clicks a button. For this, we flesh out the signal handler which we defined above, on_button_clicked
. We could have connected every button to a different signal handler, but that would lead to a lot of code duplication. Instead, we can use the label of the button to figure out which button was clicked:
The Gtk.Button
that was clicked is passed as an argument (sender
) to on_button_clicked
. We can get the label of that button by using get_child
, and then get the text from that label using get_label
.
The switch statement compares the label text to the notes that we can play, and play_sound
is called with the frequency appropriate for that note. This plays the tone; we have a working guitar tuner!
All of the code should now be ready to go. Click
If you haven't already done so, choose the
If you run into problems with the tutorial, compare your code with this reference code.
To find out more about the Vala programming language you might want to check out the Vala Tutorial and the Vala API Documentation
Aquí hai algunhas ideas sobre como pode estender esta sinxela demostración:
Facer que o programa reproduza de forma cíclica as notas.
Facer que o programa reproduza gravacións de cordas de guitarras que se están afinando.
To do this, you would need to set up a more complicated GStreamer pipeline which allows you to load and play back music files. You'll have to choose decoder and demuxer GStreamer elements based on the file format of your recorded sounds — MP3s use different elements to Ogg Vorbis files, for example.
You might need to connect the elements in more complicated ways too. This could involve using GStreamer concepts that we didn't cover in this tutorial, such as pads. You may also find the
Analizar automaticamente as notas que toca o músico.
You could connect a microphone and record sounds from it using an input source. Perhaps some form of spectrum analysis would allow you to figure out what notes are being played?