|
Packit |
1470ea |
|
|
Packit |
1470ea |
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="guitar-tuner.py" xml:lang="gl">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<title type="text">Guitar tuner (Python)</title>
|
|
Packit |
1470ea |
<link type="guide" xref="py#examples"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>Use GTK+ and GStreamer to build a simple guitar tuner application for GNOME. Shows off how to use the interface designer.</desc>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<revision pkgversion="0.1" version="0.1" date="2010-12-02" status="stub"/>
|
|
Packit |
1470ea |
<credit type="author">
|
|
Packit |
1470ea |
<name>Proxecto de documentación de GNOME</name>
|
|
Packit |
1470ea |
<email its:translate="no">gnome-doc-list@gnome.org</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="author">
|
|
Packit |
1470ea |
<name>Johannes Schmid</name>
|
|
Packit |
1470ea |
<email its:translate="no">jhs@gnome.org</email>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="editor">
|
|
Packit |
1470ea |
<name>Marta Maria Casetti</name>
|
|
Packit |
1470ea |
<email its:translate="no">mmcasetti@gmail.com</email>
|
|
Packit |
1470ea |
<years>2013</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="editor">
|
|
Packit |
1470ea |
<name>Marta Maria Casetti</name>
|
|
Packit |
1470ea |
<email its:translate="no">mmcasetti@gmail.com</email>
|
|
Packit |
1470ea |
<years>2013</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
|
|
Packit |
1470ea |
<mal:name>Fran Dieguez</mal:name>
|
|
Packit |
1470ea |
<mal:email>frandieguez@gnome.org</mal:email>
|
|
Packit |
1470ea |
<mal:years>2012-2013.</mal:years>
|
|
Packit |
1470ea |
</mal:credit>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>Guitar tuner</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<synopsis>
|
|
Packit |
1470ea |
Neste titorial faremos un programa que reproduce tonos que pode usar para afinar unha guitarra. Aprenderá como:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>Configurar un proxecto básico en Anjuta </item>
|
|
Packit |
1470ea |
<item>Crear unha GUI sinxela co deseñador de UI de Anjuta </item>
|
|
Packit |
1470ea |
<item>Usar GStreamer para reproducir sons. </item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
You'll need the following to be able to follow this tutorial:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>An installed copy of the <link xref="getting-ready">Anjuta IDE</link> </item>
|
|
Packit |
1470ea |
<item>Coñecemento básico da linguaxe de programación Python </item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</synopsis>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<media type="image" mime="image/png" src="media/guitar-tuner.png"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="anjuta">
|
|
Packit |
1470ea |
<title>Cree un proxecto de Anjuta</title>
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Inicie Anjuta e prema <guiseq><gui>Ficheiro</gui><gui>Novo</gui><gui>Proxecto</gui></guiseq> para abrir o asistente de proxectos.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Choose <gui>PyGTK (automake)</gui> from the <gui>Python</gui> tab, click <gui>Continue</gui>, and fill out your details on the next few pages. Use <file>guitar-tuner</file> as project name and directory.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Prema <gui>Aplicar</gui> e crearase o proxecto. Abra <file>src/guitar_tuner.py</file> desde as lapelas <gui>Proxecto</gui> ou <gui>Ficheiro</gui>. Debería ver algo de código que comece coas liñas:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
from gi.repository import Gtk, GdkPixbuf, Gdk
|
|
Packit |
1470ea |
import os, sys]]>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="run">
|
|
Packit |
1470ea |
<title>Executar o código por primeira vez</title>
|
|
Packit |
1470ea |
Most of the code in the file 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:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The import lines at the top include the tell Python to load the user interface and system
|
|
Packit |
1470ea |
libraries needed.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
A class is declared that will be the main class for our application. In the __init__ method
|
|
Packit |
1470ea |
the main window is loaded from the GtkBuilder file (<file>src/guitar-tuner.ui</file>) and the
|
|
Packit |
1470ea |
signals are connected.
|
|
Packit |
1470ea |
Connecting signals is how you define what happens when you push a button, or when some other event happens. Here, the destroy method is called (and quits the app) when you close the window.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The main function is run by default when you start a Python application. It just creates
|
|
Packit |
1470ea |
an instance of the main class and starts the main loop to bring up the window.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Este código está listo para o seu uso, polo que pode executalo premendo <guiseq><gui>Executar</gui><gui>Executar</gui></guiseq>.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="ui">
|
|
Packit |
1470ea |
<title>Crear a interface de usuario</title>
|
|
Packit |
1470ea |
A description of the user interface (UI) is contained in the GtkBuilder file. To edit the user interface, open <file>src/guitar_tuner.ui</file>. This will switch to the interface designer. The design window is in the center; widgets and widgets' properties are on the right, and the palette of available widgets is on the left.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The layout of every UI in GTK+ is organized using boxes and tables. Let's use a vertical <gui>GtkButtonBox</gui> here to assign six <gui>GtkButtons</gui>, one for each of the six guitar strings.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<media type="image" mime="image/png" src="media/guitar-tuner-glade.png"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Select a <gui>GtkButtonBox</gui> from the <gui>Container</gui> section of the <gui>Palette</gui> on the right and put it into the window. In the <gui>Properties</gui> pane, set the number of elements to 6 (for the
|
|
Packit |
1470ea |
six strings) and the orientation to vertical.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Now, choose a <gui>GtkButton</gui> from the palette and put it into the first part of the box.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
While the button is still selected, change the <gui>Label</gui> property in the <gui>Widgets</gui> tab to <gui>E</gui>. This will be the low E string.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Switch to the <gui>Signals</gui> tab (inside the <gui>Widgets</gui> tab) and look for 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 <gui>Handler</gui> column and press <key>Return</key>.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Repita os pasos anteriores para o resto dos botóns, engadindo as 5 cordas restantes cos nomes A, D, G, B e e.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Garde o deseño da IU (premendo <guiseq><gui>Ficheiro</gui><gui>Gardar</gui></guiseq>) e déixeo aberto.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="signal">
|
|
Packit |
1470ea |
<title>Escribir o manexador de sinais</title>
|
|
Packit |
1470ea |
In the UI designer, you made it so that all of the buttons will call the same function, <gui>on_button_clicked</gui>, when they are clicked. We need to add that function in the source file.
|
|
Packit |
1470ea |
To do this, open <file>guitar_tuner.py</file> while the user interface file is still open. Switch to the <gui>Signals</gui> tab, which you already used to set the signal name. Now take the row where you set the
|
|
Packit |
1470ea |
<gui>clicked</gui> signal and drag it into to the source file inside the class. The following code will be added to your source file:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def on_button_clicked (self, button):
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
This signal handler has two arguments: the usual Python class pointer, and the Gtk.Button that called the function.
|
|
Packit |
1470ea |
For now, we'll leave the signal handler empty while we work on writing the code to produce sounds.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="gstreamer">
|
|
Packit |
1470ea |
<title>Tuberías de GStreamer</title>
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
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.
|
|
Packit |
1470ea |
<media type="image" mime="image/png" src="media/guitar-tuner-pipeline.png">
|
|
Packit |
1470ea |
Un exemplo de tubería de GStreamer.
|
|
Packit |
1470ea |
</media>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="pipeline">
|
|
Packit |
1470ea |
<title>Configurar a tubería</title>
|
|
Packit |
1470ea |
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 .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Change the import line in <file>guitar_tuner.py</file>, just at the beginning to :
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The Gst includes the GStreamer library. You also need to initialise GStreamer properly which
|
|
Packit |
1470ea |
is done in the main() method with this call added above the app = GUI()
|
|
Packit |
1470ea |
line:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Then, copy the following function into the class in <file>guitar_tuner.py</file> somewhere:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def play_sound(self, frequency):
|
|
Packit |
1470ea |
pipeline = Gst.Pipeline(name='note')
|
|
Packit |
1470ea |
source = Gst.ElementFactory.make('audiotestsrc', 'src')
|
|
Packit |
1470ea |
sink = Gst.ElementFactory.make('autoaudiosink', 'output')
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
source.set_property('freq', frequency)
|
|
Packit |
1470ea |
pipeline.add(source)
|
|
Packit |
1470ea |
pipeline.add(sink)
|
|
Packit |
1470ea |
source.link(sink)
|
|
Packit |
1470ea |
pipeline.set_state(Gst.State.PLAYING)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
GObject.timeout_add(self.LENGTH, self.pipeline_stop, pipeline)]]>
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The first three lines create source and sink GStreamer elements 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).
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The call to source.set_property sets the freq property of the source element to frequency , which was passed 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.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
The next two lines call pipeline.add , putting the source and sink into the pipeline. The pipeline can contain multiple other GStreamer elements. In general, you can add as many elements as you like to the pipeline by calling its add method repeatedly.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
A seguinte pipeline.set_state úsase para iniciar a reprodución, estabelecendo o estado da tubería a reprodución (Gst.State.PLAYING ).
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="playback">
|
|
Packit |
1470ea |
<title>Deter a reprodución</title>
|
|
Packit |
1470ea |
We don't want to play an annoying tone forever, so the last thing play_sound does is to call GObject.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 .
|
|
Packit |
1470ea |
Agora, escríbese o código da función pipeline_stop , chamada por GObject.timeout_add . Inserte o código seguinte enriba da función play_sound :
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def pipeline_stop(self, pipeline):
|
|
Packit |
1470ea |
pipeline.set_state(Gst.State.NULL)
|
|
Packit |
1470ea |
return False
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
You need to define the LENGTH constant inside the class, so add this code at the beginning of the
|
|
Packit |
1470ea |
main class:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
LENGTH = 500
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
The call to pipeline.set_state stops the playback of the pipeline.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="tones">
|
|
Packit |
1470ea |
<title>Definir os tonos</title>
|
|
Packit |
1470ea |
We want to play the correct sound when the user clicks a button. First of all, we need to know the frequencies for the six guitar strings, which are defined (at the beginning of the main class) inside a dictionary so
|
|
Packit |
1470ea |
we can easily map them to the names of the strings:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
# Frequencies of the strings
|
|
Packit |
1470ea |
frequencies = {
|
|
Packit |
1470ea |
'E': 329.63,
|
|
Packit |
1470ea |
'A': 440,
|
|
Packit |
1470ea |
'D': 587.33,
|
|
Packit |
1470ea |
'G': 783.99,
|
|
Packit |
1470ea |
'B': 987.77,
|
|
Packit |
1470ea |
'e': 1318.5
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
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:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
def on_button_clicked(self, button):
|
|
Packit |
1470ea |
label = button.get_child()
|
|
Packit |
1470ea |
text = label.get_label()
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
self.play_sound (self.frequencies[text])
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
The button that was clicked is passed as an argument (button ) to on_button_clicked . We can get the label of that button by using button.get_child , and then get the text from that label using label.get_label .
|
|
Packit |
1470ea |
The label text is then used as a key for the dictionary and play_sound is called with the frequency appropriate for that note. This plays the tone; we have a working guitar tuner!
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="run2">
|
|
Packit |
1470ea |
<title>Executar o aplicativo</title>
|
|
Packit |
1470ea |
Todo o código debería estar listo. Prema <guiseq><gui>Executar</gui><gui>Executar</gui></guiseq> para iniciar o aplicativo. Góceo!
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="impl">
|
|
Packit |
1470ea |
<title>Implementación de referencia</title>
|
|
Packit |
1470ea |
Se ten problemas ao executar este titorial compare o seu código con este <link href="guitar-tuner/guitar-tuner.py">código de referencia</link>.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="next">
|
|
Packit |
1470ea |
<title>Seguintes pasos</title>
|
|
Packit |
1470ea |
Aquí hai algunhas ideas sobre como pode estender esta sinxela demostración:
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Facer que o programa reproduza de forma cíclica as notas.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Facer que o programa reproduza gravacións de cordas de guitarras que se están afinando.
|
|
Packit |
1470ea |
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 <link href="http://gstreamer.freedesktop.org/documentation/plugins.html">decoder and demuxer</link> GStreamer elements based on the file format of your recorded sounds — MP3s use different elements to Ogg Vorbis files, for example.
|
|
Packit |
1470ea |
You might need to connect the elements in more complicated ways too. This could involve using <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-intro-basics.html">GStreamer concepts</link> that we didn't cover in this tutorial, such as <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-intro-basics-pads.html">pads</link>. You may also find the <cmd>gst-inspect</cmd> command useful.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
Analizar automaticamente as notas que toca o músico.
|
|
Packit |
1470ea |
You could connect a microphone and record sounds from it using an <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-autoaudiosrc.html">input source</link>. Perhaps some form of <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-plugin-spectrum.html">spectrum analysis</link> would allow you to figure out what notes are being played?
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
</page>
|