Blame platform-demos/ca/guitar-tuner.cpp.page

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.cpp" xml:lang="ca">
Packit 1470ea
Packit 1470ea
  <info>
Packit 1470ea
    <link type="guide" xref="cpp#examples"/>
Packit 1470ea
Packit 1470ea
    <desc>Use GTKmm and GStreamermm 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="2011-03-17" status="review"/>
Packit 1470ea
    <credit type="author">
Packit 1470ea
      <name>Projecte de documentació del 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
  </info>
Packit 1470ea
Packit 1470ea
<title>Guitar tuner</title>
Packit 1470ea
Packit 1470ea
<synopsis>
Packit 1470ea
  

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:

Packit 1470ea
  <list>
Packit 1470ea
    <item>

Creació d'un projecte a l'Anjuta

</item>
Packit 1470ea
    <item>

Create a simple GUI with Anjuta's UI designer

</item>
Packit 1470ea
    <item>

Use GStreamer to play sounds

</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>

Basic knowledge of the C++ programming language

</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>Creació d'un projecte a l'Anjuta</title>
Packit 1470ea
  

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.

Packit 1470ea
  <steps>
Packit 1470ea
    <item>
Packit 1470ea
    

Inicieu l'Anjuta i feu clic a <guiseq><gui>Fitxer</gui><gui>Nou</gui><gui>Projecte</gui></guiseq> per obrir l'auxiliar de projectes.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Trieu <gui>GTKmm (simple)</gui> a la pestanya <gui>C++</gui>, feu clic a <gui>Continua</gui> i empleneu les dades de les pàgines següents de l'auxiliar. Utilitzeu <file>guitar-tuner</file> com a nom de projecte i de directori.

Packit 1470ea
   	</item>
Packit 1470ea
    <item>
Packit 1470ea
    

Make sure that <gui>Configure external packages</gui> is selected. On the next page, select

Packit 1470ea
       gstreamermm-0.10 from the list to include the GStreamermm library in your project.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Feu clic a <gui>Aplica</gui> i es crearà el projecte. Obriu el fitxer <file>src/main.cc</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:

Packit 1470ea
    
Packit 1470ea
#include <gtkmm.h>
Packit 1470ea
#include <iostream>]]>
Packit 1470ea
    </item>
Packit 1470ea
  </steps>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="build">
Packit 1470ea
  <title>Build the code for the first time</title>
Packit 1470ea
  

This is a very basic C++ code setting up GTKmm. More details are given below;

Packit 1470ea
  skip this list if you understand the basics:

Packit 1470ea
  <list>
Packit 1470ea
  <item>
Packit 1470ea
    

The three #include lines at the top include the config (useful autoconf build defines), gtkmm (user interface) and iostream (STL). Functions from these libraries are used in the rest of the code.

Packit 1470ea
   </item>
Packit 1470ea
   <item>
Packit 1470ea
    

The main function creates a new window by opening a GtkBuilder file (<file>src/guitar-tuner.ui</file>, defined a few lines above) 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.

Packit 1470ea
   </item>
Packit 1470ea
   <item>
Packit 1470ea
    

Afterwards it calls a few functions which set up and then run the application. The kit.run function starts the GTKmm main loop, which runs the user interface and starts listening for events (like clicks and key presses).

Packit 1470ea
   </item>
Packit 1470ea
  </list>
Packit 1470ea
Packit 1470ea
  

This code is ready to be used, so you can compile it by clicking <guiseq><gui>Build</gui><gui>Build Project</gui></guiseq> (or press <keyseq><key>Shift</key><key>F7</key></keyseq>).

Packit 1470ea
  

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.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="ui">
Packit 1470ea
  <title>Create the user interface</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 left, and the palette of available widgets is on the right.

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. Also change the <gui>Name</gui> property to <gui>button_E</gui>. This is the name we will refer

Packit 1470ea
    to the widget later in code.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Repeat the above steps for the other buttons, adding the next 5 strings with the labels A, D, G, B, and e and the names button_A, etc.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Save the UI design (by clicking <guiseq><gui>File</gui><gui>Save</gui></guiseq>) and close the file.

Packit 1470ea
    </item>
Packit 1470ea
  </steps>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="gst">
Packit 1470ea
  <title>GStreamer pipelines</title>
Packit 1470ea
  

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. GStreamermm is the C++ binding to GStreamer which

Packit 1470ea
  we will use here.

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
    

An example GStreamer pipeline.

Packit 1470ea
  </media>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="usinggst">
Packit 1470ea
  <title>Using GStreamermm</title>
Packit 1470ea
  

To use GStreamermm, it has to be initialised. We do that by adding the following line of code next to the

Packit 1470ea
  Gtk::Main kit(argc, argv); line in <file>main.cc</file>:

Packit 1470ea
  	Gst::init (argc, argv);
Packit 1470ea
  

While we are on it, also make sure that the <file>gstreamermm.h</file> is included in <file>main.cc</file> properly.

Packit 1470ea
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
  

To simplify the handling of the pipeline we will define a helper class Sound. We do

Packit 1470ea
  that in <file>main.cc</file> in order to keep this example simple, whereas you might usually want
Packit 1470ea
  to use a separate file:

Packit 1470ea
  
Packit 1470ea
class Sound
Packit 1470ea
{
Packit 1470ea
	public:
Packit 1470ea
		Sound();
Packit 1470ea
Packit 1470ea
		void start_playing(double frequency);
Packit 1470ea
		bool stop_playing();
Packit 1470ea
Packit 1470ea
	private:
Packit 1470ea
		Glib::RefPtr<Gst::Pipeline> m_pipeline;
Packit 1470ea
		Glib::RefPtr<Gst::Element> m_source;
Packit 1470ea
		Glib::RefPtr<Gst::Element> m_sink;
Packit 1470ea
};
Packit 1470ea
Packit 1470ea
Sound::Sound()
Packit 1470ea
{
Packit 1470ea
	m_pipeline = Gst::Pipeline::create("note");
Packit 1470ea
	m_source = Gst::ElementFactory::create_element("audiotestsrc",
Packit 1470ea
	                                               "source");
Packit 1470ea
	m_sink = Gst::ElementFactory::create_element("autoaudiosink",
Packit 1470ea
	                                             "output");
Packit 1470ea
	m_pipeline->add(m_source);
Packit 1470ea
	m_pipeline->add(m_sink);
Packit 1470ea
	m_source->link(m_sink);
Packit 1470ea
}
Packit 1470ea
Packit 1470ea
void Sound::start_playing (double frequency)
Packit 1470ea
{
Packit 1470ea
	m_source->set_property("freq", frequency);
Packit 1470ea
	m_pipeline->set_state(Gst::STATE_PLAYING);
Packit 1470ea
Packit 1470ea
	/* stop it after 200ms */
Packit 1470ea
	Glib::signal_timeout().connect(sigc::mem_fun(*this, &Sound::stop_playing),
Packit 1470ea
	                               200);
Packit 1470ea
}
Packit 1470ea
Packit 1470ea
bool Sound::stop_playing()
Packit 1470ea
{
Packit 1470ea
	m_pipeline->set_state(Gst::STATE_NULL);
Packit 1470ea
	return false;
Packit 1470ea
}
Packit 1470ea
]]>
Packit 1470ea
Packit 1470ea
  

The code has the following purpose:

Packit 1470ea
  <steps>
Packit 1470ea
    <item>
Packit 1470ea
    

In the constructor, source and sink GStreamer elements (Gst::Element) are created, 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). After the elements have been added to the pipeline and linked together, the pipeline is ready to run.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

start_playing sets the source element to play a particular frequency and then starts the pipeline so the sound

Packit 1470ea
    actually starts playing. As we don't want to have the annoying sound for ages, a timeout is set up to stop the pipeline
Packit 1470ea
    after 200 ms by calling stop_playing.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

In stop_playing which is called when the timeout has elapsed, the pipeline is stopped and as such there isn't

Packit 1470ea
    any sound output anymore. As GStreamermm uses reference counting through the Glib::RefPtr object, the memory
Packit 1470ea
    is automatically freed once the Sound class is destroyed.

Packit 1470ea
    </item>
Packit 1470ea
  </steps>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="signals">
Packit 1470ea
  <title>Connecting the signals</title>
Packit 1470ea
  

We want to play the correct sound when the user clicks a button. That means that we have to connect

Packit 1470ea
  to the signal that is fired when the user clicks the button. We also want to provide information to the
Packit 1470ea
  called function which tone to play. GTKmm makes that quite easy as we can easily bind information with the sigc
Packit 1470ea
  library.

Packit 1470ea
Packit 1470ea
  

The function that is called when the user clicks a button can be pretty simple, as

Packit 1470ea
  all the interesting stuff is done in the helper class now:

Packit 1470ea
  
Packit 1470ea
static void
Packit 1470ea
on_button_clicked(double frequency, Sound* sound)
Packit 1470ea
{
Packit 1470ea
	sound->start_playing (frequency);
Packit 1470ea
}
Packit 1470ea
]]>
Packit 1470ea
  

It only calls the helper class we defined before to play the correct frequencies. With some more

Packit 1470ea
  clever code we would also have been able to directly connect to the class without using the function
Packit 1470ea
  but we will leave that to use as an exercise.

Packit 1470ea
Packit 1470ea
  

The code to set up the signals should be added to the main() function just after the

Packit 1470ea
  builder->get_widget("main_window", main_win); line:

Packit 1470ea
  
Packit 1470ea
Sound sound;
Packit 1470ea
Gtk::Button* button;
Packit 1470ea
Packit 1470ea
builder->get_widget("button_E", button);
Packit 1470ea
button->signal_clicked().connect (sigc::bind<double, Sound*>(sigc::ptr_fun(&on_button_clicked),
Packit 1470ea
                                              329.63, &sound));
Packit 1470ea
]]>
Packit 1470ea
	<steps>
Packit 1470ea
	<item>
Packit 1470ea
	

At first we create an instance of our helper class that we want to use now and declare a variable

Packit 1470ea
	for the button we want to connect to.

Packit 1470ea
	</item>
Packit 1470ea
	<item>
Packit 1470ea
	

Next, we receive the button object from the user interface that was created out of the user interface file. Remember

Packit 1470ea
	that button_E is the name we gave to the first button.

Packit 1470ea
	</item>
Packit 1470ea
	<item>
Packit 1470ea
	

Finally we connect the clicked signal. This isn't fully straightforward because this is done in a fully type-safe

Packit 1470ea
	way and we actually want to pass the frequency and our helper class to the signal handler.
Packit 1470ea
	sigc::ptr_fun(&on_button_clicked) creates a slot for the on_button_clicked method
Packit 1470ea
	we defined above. With sigc::bind we are able to pass additional arguments to the slot and in this
Packit 1470ea
	case we pass the frequency (as double) and our helper class.

Packit 1470ea
	</item>
Packit 1470ea
  </steps>
Packit 1470ea
  

Now that we have set up the E button we also need to connect the other buttons according to their frequencies:

Packit 1470ea
  440 for A,  587.33 for D, 783.99 for G, 987.77 for B and 1318.5 for the high E. This is done in the same way, just passing
Packit 1470ea
  a different frequency to the handler.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="run">
Packit 1470ea
  <title>Muntatge i execució de l'aplicació</title>
Packit 1470ea
  

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>Run</gui></guiseq> to start the application.

Packit 1470ea
  

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!

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="impl">
Packit 1470ea
 <title>Implementació de referència</title>
Packit 1470ea
 

Si teniu algun problema amb el programa d'aprenentatge, compareu el codi amb el <link href="guitar-tuner/guitar-tuner.cc">codi de referència</link>.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="further">
Packit 1470ea
  <title>Further Reading</title>
Packit 1470ea
  

Many of the things shown above are explained in detail in the

Packit 1470ea
  <link href="http://library.gnome.org/devel/gtkmm-tutorial/stable/">GTKmm book</link> which also
Packit 1470ea
  covers a lot more key concept for using the full power of GTKmm. You might also be interested
Packit 1470ea
  in the <link href="http://library.gnome.org/devel/gstreamermm/">GStreamermm reference documentation</link>.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="next">
Packit 1470ea
  <title>Next steps</title>
Packit 1470ea
  

Here are some ideas for how you can extend this simple demonstration:

Packit 1470ea
  <list>
Packit 1470ea
   <item>
Packit 1470ea
   

Have the program automatically cycle through the notes.

Packit 1470ea
   </item>
Packit 1470ea
   <item>
Packit 1470ea
   

Make the program play recordings of real guitar strings being plucked.

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
   

Automatically analyze notes that the user plays.

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>