1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
|
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="guitar-tuner.c" xml:lang="sv">
<info>
<title type="text">Gitarrstämmare (C)</title>
<link type="guide" xref="c#examples"/>
<desc>Använd GTK+ och GStreamer för att bygga ett enkelt gitarrstämmarprogram för GNOME. Visar hur gränssnittsdesignern används.</desc>
<revision pkgversion="0.1" version="0.1" date="2010-12-02" status="review"/>
<credit type="author">
<name>Dokumentationsprojekt för GNOME</name>
<email its:translate="no">gnome-doc-list@gnome.org</email>
</credit>
<credit type="author">
<name>Johannes Schmid</name>
<email its:translate="no">jhs@gnome.org</email>
</credit>
<credit type="editor">
<name>Marta Maria Casetti</name>
<email its:translate="no">mmcasetti@gmail.com</email>
<years>2013</years>
</credit>
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
<mal:name>Sebastian Rasmussen</mal:name>
<mal:email>sebras@gmail.com</mal:email>
<mal:years>2019</mal:years>
</mal:credit>
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
<mal:name>Anders Jonsson</mal:name>
<mal:email>anders.jonsson@norsjovallen.se</mal:email>
<mal:years>2021</mal:years>
</mal:credit>
</info>
<title>Gitarrstämmare</title>
<synopsis>
<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>
<list>
<item><p>Konfigurerar ett grundläggande projekt i Anjuta</p></item>
<item><p>Skapar ett enkelt grafiskt användargränssnitt med Anjutas användargränssnittsdesigner</p></item>
<item><p>Använder GStreamer för att spela upp ljud</p></item>
</list>
<p>Du behöver följande för att kunna följa denna handledning:</p>
<list>
<item><p>En installerad kopia av den <link xref="getting-ready">integrerade utvecklingsmiljön Anjuta</link></p></item>
<item><p>Grundläggande kunskap i programmeringsspråket C</p></item>
</list>
</synopsis>
<media type="image" mime="image/png" src="media/guitar-tuner.png"/>
<section id="anjuta">
<title>Skapa ett projekt i Anjuta</title>
<p>Innan du börjar koda kommer du behöva konfigurera ett nytt projekt i Anjuta. Detta kommer skapa alla filer som du behöver för att bygga och köra koden senare. Det är också användbart för att hålla allting samlat.</p>
<steps>
<item>
<p>Starta Anjuta och klicka på <guiseq><gui>Arkiv</gui><gui>Ny</gui><gui>Projekt</gui></guiseq> för att öppna projektguiden.</p>
</item>
<item>
<p>Välj <gui>GTK+ (enkel)</gui> från fliken <gui>C</gui>, klicka på <gui>Fortsätt</gui>, och fyll i dina detaljer på de nästkommande sidorna. Använd <file>guitar-tuner</file> som projektnamn och katalog.</p>
</item>
<item>
<p>Säkerställ att <gui>Konfigurera externa paket</gui> är i läget <gui>PÅ</gui>. På nästa sida, välj <em>gstreamer-0.10</em> från listan för att inkludera GStreamer-biblioteket i ditt projekt.</p>
</item>
<item>
<p>Klicka på <gui>Verkställ</gui> så kommer projektet skapas åt dig. Öppna <file>src/main.c</file> från flikarna <gui>Projekt</gui> eller <gui>Filer</gui>. Du bör se kod som börjar med raderna:</p>
<code mime="text/x-csrc">
#include <config.h>
#include <gtk/gtk.h></code>
</item>
</steps>
</section>
<section id="build">
<title>Bygg koden för första gången</title>
<p>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:</p>
<list>
<item>
<p>The three <code>#include</code> lines at the top include the <code>config</code> (useful autoconf build defines), <code>gtk</code> (user interface) and <code>gi18n</code> (internationalization) libraries. Functions from these libraries are used in the rest of the code.</p>
</item>
<item>
<p>The <code>create_window</code> function creates a new window by opening a GtkBuilder file (<file>src/guitar-tuner.ui</file>, defined a few lines above), connecting its signals and then displaying it in a window. The GtkBuilder file contains a description of a user interface and all of its elements. You can use Anjuta's editor to design GtkBuilder user interfaces.</p>
<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> function is called (and quits the app) when you close the window.</p>
</item>
<item>
<p>The <code>main</code> 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 <code>gtk_main</code> function starts the GTK main loop, which runs the user interface and starts listening for events (like clicks and key presses).</p>
</item>
<item>
<p>The <code>ENABLE_NLS</code> conditional definition sets up <code>gettext</code>, which is a framework for translating applications. These functions specify how translation tools should handle your app when you run them.</p>
</item>
</list>
<p>Denna kod är klar att användas, så du kan kompilera den genom att klicka på <guiseq><gui>Bygg</gui><gui>Bygg projekt</gui></guiseq> (eller trycka <keyseq><key>Skift</key><key>F7</key></keyseq>).</p>
<p>Press <gui>Execute</gui> on the next window that appears to configure a debug build. You only need to do this once, for the first build.</p>
</section>
<section id="ui">
<title>Skapa användargränssnittet</title>
<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 left, and the palette of available widgets is on the right.
</p>
<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>
<media type="image" mime="image/png" src="media/guitar-tuner-glade.png"/>
<steps>
<item>
<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
six strings) and the orientation to vertical.</p>
</item>
<item>
<p>Now, choose a <gui>GtkButton</gui> from the palette and put it into the first part of the box.</p>
</item>
<item>
<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>
</item>
<item>
<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>
</item>
<item>
<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>
</item>
<item>
<p>Save the UI design (by clicking <guiseq><gui>File</gui><gui>Save</gui></guiseq>) and keep it open.</p>
</item>
</steps>
</section>
<section id="signal">
<title>Skapa signalhanteraren</title>
<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>
<p>To do this, open <file>main.c</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
<gui>clicked</gui> signal and drag it into to the source file at a
position that is outside any function. The following code will be added to your source file:</p>
<code mime="text/x-csrc"><![CDATA[
void on_button_clicked (GtkWidget* button, gpointer user_data)
{
}]]></code>
<p>This signal handler has two arguments: a pointer to the <code>GtkWidget</code> that called the function (in our case, always a <code>GtkButton</code>), 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 <code>gtk_builder_connect_signals</code>; it is normally used to pass a pointer to a data structure that you might need to access inside the signal handler.)</p>
<p>För tillfället kommer vi lämna signalhanteraren tom medan vi arbetar med att skriva koden för att skapa ljud.</p>
</section>
<section id="gstreamer">
<title>GStreamer-rörledningar</title>
<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>
<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>
<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>
<media type="image" mime="image/png" src="media/guitar-tuner-pipeline.png">
<p>Exempel på en GStreamer-rörledning.</p>
</media>
</section>
<section id="pipeline">
<title>Konfigurera rörledningen</title>
<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>
<p>Infoga följande rad i <file>main.c</file>, just under raden <code>#include <gtk/gtk.h></code>:</p>
<code mime="text/x-csrc">#include <gst/gst.h></code>
<p>Detta inkluderar GStreamer-biblioteket. Du behöver också lägga till en rad för att initiera GStreamer; stoppa in följande kod på raden ovanför <code>gtk_init</code>-anropen i <code>main</code>-funktionen:</p>
<code>gst_init (&argc, &argv);</code>
<p>Kopiera sedan in följande funktion i <file>main.c</file>, ovanför den tomma funktionen <code>on_button_clicked</code>:</p>
<code mime="text/x-csrc"><![CDATA[static void
play_sound (gdouble frequency)
{
GstElement *source, *sink;
GstElement *pipeline;
pipeline = gst_pipeline_new ("note");
source = gst_element_factory_make ("audiotestsrc",
"source");
sink = gst_element_factory_make ("autoaudiosink",
"output");
/* set frequency */
g_object_set (source, "freq", frequency, NULL);
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
gst_element_link (source, sink);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* stop it after 500ms */
g_timeout_add (LENGTH, (GSourceFunc) pipeline_stop, pipeline);
}]]></code>
<steps>
<item>
<p>The first five lines create source and sink GStreamer elements (<code>GstElement</code>), 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>
</item>
<item>
<p>The call to <code>g_object_set</code> sets the <code>freq</code> property of the source element to <code>frequency</code>, which is 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>
</item>
<item>
<p><code>gst_bin_add_many</code> puts the source and sink into the pipeline. The pipeline is a <code>GstBin</code>, 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 <code>gst_bin_add_many</code>.</p>
</item>
<item>
<p>Next, <code>gst_element_link</code> is used to connect the elements together, so the output of <code>source</code> (a tone) goes into the input of <code>sink</code> (which is then output to the sound card). <code>gst_element_set_state</code> is then used to start playback, by setting the state of the pipeline to playing (<code>GST_STATE_PLAYING</code>).</p>
</item>
</steps>
</section>
<section id="stop">
<title>Stoppa uppspelning</title>
<p>We don't want to play an annoying tone forever, so the last thing <code>play_sound</code> does is to call <code>g_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>
<p>Now, we'll write the <code>pipeline_stop</code> function which is called by <code>g_timeout_add</code>. Insert the following code <em>above</em> the <code>play_sound</code> function:</p>
<code mime="text/x-csrc">
#define LENGTH 500 /* Uppspelningslängd i ms */
static gboolean
pipeline_stop (GstElement* pipeline)
{
gst_element_set_state (pipeline, GST_STATE_NULL);
g_object_unref (pipeline);
return FALSE;
}</code>
<p>The call to <code>gst_element_set_state</code> stops the playback of the pipeline and <code>g_object_unref</code> unreferences the pipeline, destroying it and freeing its memory.</p>
</section>
<section id="tones">
<title>Definiera tonerna</title>
<p>Vi vill spela rätt ljud när användaren klickar på en knapp. Först av allt behöver vi veta frekvenserna för de sex gitarrsträngarna, vilka är definierade (högst upp i <file>main.c</file>) enligt följande:</p>
<code mime="text/x-csrc"><![CDATA[
/* Frequencies of the strings */
#define NOTE_E 329.63
#define NOTE_A 440
#define NOTE_D 587.33
#define NOTE_G 783.99
#define NOTE_B 987.77
#define NOTE_e 1318.5]]></code>
<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>
<code mime="text/x-csrc"><![CDATA[
/* Callback for the buttons */
void on_button_clicked (GtkButton* button,
gpointer user_data)
{
const gchar* text = gtk_button_get_label (button);
if (g_str_equal (text, _("E")))
play_sound (NOTE_E);
else if (g_str_equal (text, _("A")))
play_sound (NOTE_A);
else if (g_str_equal (text, _("G")))
play_sound (NOTE_G);
else if (g_str_equal (text, _("D")))
play_sound (NOTE_D);
else if (g_str_equal (text, _("B")))
play_sound (NOTE_B);
else if (g_str_equal (text, _("e")))
play_sound (NOTE_e);
}
]]></code>
<p>A pointer to the <code>GtkButton</code> that was clicked is passed as an argument (<code>button</code>) to <code>on_button_clicked</code>. We can get the text of that button using <code>gtk_button_get_label</code>.</p>
<p>The text is then compared to the notes that we have using <code>g_str_equal</code>, 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>
</section>
<section id="run">
<title>Bygg och kör programmet</title>
<p>All of the code should now be ready to go. Click <guiseq><gui>Build</gui><gui>Build Project</gui></guiseq> to build everything again, and then <guiseq><gui>Run</gui><gui>Execute</gui></guiseq> to start the application.</p>
<p>If you haven't already done so, choose the <file>Debug/src/guitar-tuner</file> application in the dialog that appears. Finally, hit <gui>Run</gui> and enjoy!</p>
</section>
<section id="impl">
<title>Referensimplementation</title>
<p>Om du stöter på problem med handledningen kan du jämföra din kod med denna <link href="guitar-tuner/guitar-tuner.c">referenskod</link>.</p>
</section>
<section id="next">
<title>Nästa steg</title>
<p>Här är några idéer på hur du kan utöka denna enkla demonstration:</p>
<list>
<item>
<p>Have the program automatically cycle through the notes.</p>
</item>
<item>
<p>Make the program play recordings of real guitar strings being plucked.</p>
<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>
<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>
</item>
<item>
<p>Automatically analyze notes that the user plays.</p>
<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>
</item>
</list>
</section>
</page>
|