Neste titorial faremos un programa que reproduce tonos que pode usar para afinar unha guitarra. Aprenderá como:
Configurar un proxecto básico en Anjuta
Crear unha GUI sinxela co deseñador de UI de Anjuta
Usar GStreamer para reproducir sons.
You'll need the following to be able to follow this tutorial:
An installed copy of the Anjuta IDE
Coñecemento básico da linguaxe de programación C
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.
Inicie Anjuta e prema
Choose
Make sure that
Prema
#include ]]>
C is a rather verbose language, so don't be surprised that the file contains quite a lot of code. Most of it is template code. It loads an (empty) window from the user interface description file and shows it. More details are given below; skip this list if you understand the basics:
The three #include
lines at the top include the config
(useful autoconf build defines), gtk
(user interface) and gi18n
(internationalization) libraries. Functions from these libraries are used in the rest of the code.
The create_window
function 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 destroy
function is called (and quits the app) when you close the window.
The main
function is run by default when you start a C application. It calls a few functions which 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).
The ENABLE_NLS
conditional definition sets up gettext
, which is a framework for translating applications. These functions specify how translation tools should handle your app when you run them.
This code is ready to be used, so you can compile it by clicking
Prema
A description of the user interface (UI) is contained in the GtkBuilder file. To edit the user interface, open
The layout of every UI in GTK+ is organized using boxes and tables. Let's use a vertical
Select a
Now, choose a
While the button is still selected, change the
Switch to 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 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
In the UI designer, you made it so that all of the buttons will call the same function,
To do this, open
This signal handler has two arguments: a pointer to the GtkWidget
that called the function (in our case, always a GtkButton
), and a pointer to some "user data" that you can define, but which we won't be using here. (You can set the user data by calling gtk_builder_connect_signals
; it is normally used to pass a pointer to a data structure that you might need to access inside the signal handler.)
For now, we'll leave the signal handler empty while we work on writing the code to produce sounds.
GStreamer é un marco de traballo multimedia de GNOME — vostede pode usalo para reproducir, gravar e procesar vídeo, son, fluxos de cámara web e semellantes. Aquí, usarémolo para producir tonos dunha única frecuencia.
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 simple 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
.
Insert the following line into ]]>
line:
]]>
Isto inclúe a biblioteca GSTreamer. Tamén precisa unha liña para inicializar GStreamer; poña a seguinte liña de código antes da chamada gtk_init
na función main
:
Despois, copie a seguinte función en on_button_clicked
baleira:
The first five lines create source and sink GStreamer elements (GstElement
), and a pipeline element (which will be used as a container for the other two elements). 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).
A chamada a g_object_set
estabelecer a propiedade freq
do elemento orixe a frequency
, a cal se pasa como un argumento á función play_sound
. Isto só é a frecuencia da nota en Hertz, algunhas das frecuencias máis útiles definiranse máis tarde.
gst_bin_add_many
puts the source and sink into the pipeline. The pipeline is a GstBin
, 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 arguments to gst_bin_add_many
.
Next, gst_element_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). gst_element_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 call g_timeout_add
. This sets a timeout for stopping the sound; it waits for LENGTH
milliseconds before calling the function pipeline_stop
, and will keep calling it until pipeline_stop
returns FALSE
.
Agora, escríbese o código da función pipeline_stop
, chamada por g_timeout_add
. Inserte o código seguinte enriba da función play_sound
:
The call to gst_element_set_state
stops the playback of the pipeline and g_object_unref
unreferences the pipeline, destroying it and freeing its memory.
Quérese reproducir o son correcto cando un usuario preme un botón. En primeiro lugar, precísase coñecer as frecuencias das seis cordas da guitarra, que están definidas (ao principio de
Now to flesh out the signal handler that we defined earlier, 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:
A pointer to the GtkButton
that was clicked is passed as an argument (button
) to on_button_clicked
. We can get the text of that button using gtk_button_get_label
.
The text is then compared to the notes that we have using g_str_equal
, 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
Se ten problemas ao executar este titorial compare o seu código con este código de referencia.
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?