1<?xml version="1.0" encoding="utf-8"?>
2<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="guitar-tuner.py" xml:lang="ca">
3
4  <info>
5    <title type="text">Guitar tuner (Python)</title>
6    <link type="guide" xref="py#examples"/>
7
8    <desc>Use GTK+ and GStreamer to build a simple guitar tuner application for GNOME. Shows off how to use the interface designer.</desc>
9
10    <revision pkgversion="0.1" version="0.1" date="2010-12-02" status="stub"/>
11    <credit type="author">
12      <name>Projecte de documentació del GNOME</name>
13      <email its:translate="no">gnome-doc-list@gnome.org</email>
14    </credit>
15    <credit type="author">
16      <name>Johannes Schmid</name>
17      <email its:translate="no">jhs@gnome.org</email>
18    </credit>
19    <credit type="editor">
20      <name>Marta Maria Casetti</name>
21      <email its:translate="no">mmcasetti@gmail.com</email>
22      <years>2013</years>
23    </credit>
24    <credit type="editor">
25      <name>Marta Maria Casetti</name>
26      <email its:translate="no">mmcasetti@gmail.com</email>
27      <years>2013</years>
28    </credit>
29  </info>
30
31<title>Guitar tuner</title>
32
33<synopsis>
34  <p>In this tutorial, we're going to make a program which plays tones that you can use to tune a guitar. You will learn how to:</p>
35  <list>
36    <item><p>Creació d'un projecte a l'Anjuta</p></item>
37    <item><p>Create a simple GUI with Anjuta's UI designer</p></item>
38    <item><p>Use GStreamer to play sounds</p></item>
39  </list>
40  <p>You'll need the following to be able to follow this tutorial:</p>
41  <list>
42    <item><p>An installed copy of the <link xref="getting-ready">Anjuta IDE</link></p></item>
43    <item><p>Basic knowledge of the Python programming language</p></item>
44  </list>
45</synopsis>
46
47<media type="image" mime="image/png" src="media/guitar-tuner.png"/>
48
49<section id="anjuta">
50  <title>Creació d'un projecte a l'Anjuta</title>
51  <p>Abans de començar a programar, heu de crear un projecte nou a l'Anjuta. L'Anjuta crearà tots els fitxers necessaris per, més endavant, construir i executar el codi. És molt útil per així mantenir-ho tot junt.</p>
52  <steps>
53    <item>
54    <p>Inicieu l'Anjuta i feu clic a <guiseq><gui>Fitxer</gui><gui>Nou</gui><gui>Projecte</gui></guiseq> per obrir l'auxiliar de projectes.</p>
55    </item>
56    <item>
57    <p>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.</p>
58   	</item>
59    <item>
60    <p>Feu clic a <gui>Aplica</gui> i es crearà el projecte. Obriu el fitxer <file>src/guitar_tuner.py</file> des de la pestanya de <gui>Projecte</gui> o de <gui>Fitxer</gui>. El fitxer ja conté unes línies de codi que comencen amb:</p>
61    <code mime="test/x-python"><![CDATA[
62from gi.repository import Gtk, GdkPixbuf, Gdk
63import os, sys]]></code>
64    </item>
65  </steps>
66</section>
67
68<section id="run">
69  <title>Run the code for the first time</title>
70  <p>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:</p>
71
72  <list>
73  <item>
74    <p>The <code>import</code> lines at the top include the tell Python to load the user interface and system
75libraries needed.</p>
76   </item>
77   <item>
78    <p>A class is declared that will be the main class for our application. In the <code>__init__</code> method
79	the main window is loaded from the GtkBuilder file (<file>src/guitar-tuner.ui</file>) and the
80	signals are connected.</p>
81    <p>Connecting signals is how you define what happens when you push a button, or when some other event happens. Here, the <code>destroy</code> method is called (and quits the app) when you close the window.</p>
82   </item>
83   <item>
84    <p>The <code>main</code> function is run by default when you start a Python application. It just creates
85	an instance of the main class and starts the main loop to bring up the window.</p>
86   </item>
87  </list>
88
89  <p>This code is ready to be used, so you can run it by clicking <guiseq><gui>Run</gui><gui>Execute</gui></guiseq>.</p>
90</section>
91
92<section id="ui">
93  <title>Create the user interface</title>
94  <p>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.
95  </p>
96  <p>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.</p>
97
98<media type="image" mime="image/png" src="media/guitar-tuner-glade.png"/>
99
100  <steps>
101   <item>
102   <p>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
103six strings) and the orientation to vertical.</p>
104   </item>
105   <item>
106    <p>Now, choose a <gui>GtkButton</gui> from the palette and put it into the first part of the box.</p>
107   </item>
108   <item>
109    <p>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.</p>
110    </item>
111    <item>
112     <p>Switch to the <gui>Signals</gui> tab (inside the <gui>Widgets</gui> tab) and look for the <code>clicked</code> 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 <code>on_button_clicked</code> in the <gui>Handler</gui> column and press <key>Return</key>.</p>
113    </item>
114    <item>
115    <p>Repeat the above steps for the other buttons, adding the next 5 strings with the names <em>A</em>, <em>D</em>, <em>G</em>, <em>B</em>, and <em>e</em>.</p>
116    </item>
117    <item>
118    <p>Save the UI design (by clicking <guiseq><gui>File</gui><gui>Save</gui></guiseq>) and keep it open.</p>
119    </item>
120  </steps>
121</section>
122
123<section id="signal">
124  <title>Write the signal handler</title>
125  <p>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.</p>
126<p>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
127<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:</p>
128<code mime="text/x-csrc"><![CDATA[
129def on_button_clicked (self, button):
130]]></code>
131
132  <p>This signal handler has two arguments: the usual Python class pointer, and the <code>Gtk.Button</code> that called the function.</p>
133  <p>For now, we'll leave the signal handler empty while we work on writing the code to produce sounds.</p>
134</section>
135
136<section id="gstreamer">
137  <title>GStreamer pipelines</title>
138  <p>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.</p>
139  <p>Conceptually, GStreamer works as follows: You create a <em>pipeline</em> containing several processing elements going from the <em>source</em> to the <em>sink</em> (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.</p>
140  <p>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.</p>
141  <media type="image" mime="image/png" src="media/guitar-tuner-pipeline.png">
142    <p>An example GStreamer pipeline.</p>
143  </media>
144</section>
145
146<section id="pipeline">
147  <title>Set up the pipeline</title>
148  <p>In this simple example we will use a tone generator source called <code>audiotestsrc</code> and send the output to the default system sound device, <code>autoaudiosink</code>. We only need to configure the frequency of the tone generator; this is accessible through the <code>freq</code> property of <code>audiotestsrc</code>.</p>
149
150  <p>Change the import line in <file>guitar_tuner.py</file>, just at the beginning to :</p>
151  <code mime="test/x-python"><![CDATA[from gi.repository import Gtk, Gst, GObject ]]></code>
152  <p>The <code>Gst</code> includes the GStreamer library. You also need to initialise GStreamer properly which
153     is done in the <code>main()</code> method with this call added above the <code>app = GUI()</code>
154     line:</p>
155  <code mime="test/x-python"><![CDATA[Gst.init_check(sys.argv)]]></code>
156  <p>Then, copy the following function into the class in <file>guitar_tuner.py</file> somewhere:</p>
157  <code mime="test/x-python"><![CDATA[
158def play_sound(self, frequency):
159	pipeline = Gst.Pipeline(name='note')
160	source = Gst.ElementFactory.make('audiotestsrc', 'src')
161	sink = Gst.ElementFactory.make('autoaudiosink', 'output')
162
163	source.set_property('freq', frequency)
164	pipeline.add(source)
165	pipeline.add(sink)
166	source.link(sink)
167	pipeline.set_state(Gst.State.PLAYING)
168
169	GObject.timeout_add(self.LENGTH, self.pipeline_stop, pipeline)]]></code>
170  <steps>
171    <item>
172    <p>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 <code>audiotestsrc</code> source; and the sink is named "output" and set to the <code>autoaudiosink</code> sink (default sound card output).</p>
173    </item>
174    <item>
175    <p>The call to <code>source.set_property</code> sets the <code>freq</code> property of the source element to <code>frequency</code>, which was passed as an argument to the <code>play_sound</code> function. This is just the frequency of the note in Hertz; some useful frequencies will be defined later on.</p>
176    </item>
177    <item>
178    <p>The next two lines call <code>pipeline.add</code>, 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 <code>add</code> method repeatedly.</p>
179    </item>
180    <item>
181    <p>Next <code>pipeline.set_state</code> is used to start playback, by setting the state of the pipeline to playing (<code>Gst.State.PLAYING</code>).</p>
182    </item>
183  </steps>
184
185</section>
186
187<section id="playback">
188  <title>Stopping playback</title>
189  <p>We don't want to play an annoying tone forever, so the last thing <code>play_sound</code> does is to call <code>GObject.timeout_add</code>. This sets a timeout for stopping the sound; it waits for <code>LENGTH</code> milliseconds before calling the function <code>pipeline_stop</code>, and will keep calling it until <code>pipeline_stop</code> returns <code>False</code>.</p>
190  <p>Now, we'll write the <code>pipeline_stop</code> function which is called by <code>GObject.timeout_add</code>. Insert the following code <em>above</em> the <code>play_sound</code> function:</p>
191  <code mime="test/x-python"><![CDATA[
192def pipeline_stop(self, pipeline):
193	pipeline.set_state(Gst.State.NULL)
194	return False
195]]></code>
196  <p>You need to define the <code>LENGTH</code> constant inside the class, so add this code at the beginning of the
197main class:</p>
198  <code mime="test/x-python"><![CDATA[
199LENGTH = 500
200]]></code>
201  <p>The call to <code>pipeline.set_state</code> stops the playback of the pipeline.</p>
202</section>
203
204<section id="tones">
205  <title>Define the tones</title>
206  <p>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
207we can easily map them to the names of the strings:</p>
208  <code mime="test/x-python"><![CDATA[
209# Frequencies of the strings
210frequencies = {
211	'E': 329.63,
212	'A': 440,
213	'D': 587.33,
214	'G': 783.99,
215	'B': 987.77,
216	'e': 1318.5
217}
218]]></code>
219  <p>Now to flesh out the signal handler that we defined earlier, <code>on_button_clicked</code>. 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:</p>
220  <code mime="test/x-python"><![CDATA[
221def on_button_clicked(self, button):
222	label = button.get_child()
223	text = label.get_label()
224
225	self.play_sound (self.frequencies[text])
226]]></code>
227  <p>The button that was clicked is passed as an argument (<code>button</code>) to <code>on_button_clicked</code>. We can get the label of that button by using <code>button.get_child</code>, and then get the text from that label using <code>label.get_label</code>.</p>
228  <p>The label text is then used as a key for the dictionary and <code>play_sound</code> is called with the frequency appropriate for that note. This plays the tone; we have a working guitar tuner!</p>
229</section>
230
231<section id="run2">
232  <title>Execució de l'aplicació</title>
233  <p>All of the code should now be ready to go. Click <guiseq><gui>Run</gui><gui>Execute</gui></guiseq> to start the application. Enjoy!</p>
234</section>
235
236<section id="impl">
237 <title>Implementació de referència</title>
238 <p>Si teniu algun problema amb el programa d'aprenentatge, compareu el codi amb el <link href="guitar-tuner/guitar-tuner.py">codi de referència</link>.</p>
239</section>
240
241<section id="next">
242  <title>Next steps</title>
243  <p>Here are some ideas for how you can extend this simple demonstration:</p>
244  <list>
245   <item>
246   <p>Have the program automatically cycle through the notes.</p>
247   </item>
248   <item>
249   <p>Make the program play recordings of real guitar strings being plucked.</p>
250   <p>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.</p>
251   <p>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.</p>
252   </item>
253   <item>
254   <p>Automatically analyze notes that the user plays.</p>
255   <p>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?</p>
256   </item>
257  </list>
258</section>
259
260</page>
261