Blame platform-demos/cs/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="cs">
Packit 1470ea
Packit 1470ea
  <info>
Packit 1470ea
    <link type="guide" xref="cpp#examples"/>
Packit 1470ea
Packit 1470ea
    <desc>Jak použít GTKmm a GStreamermm k sestavení jednoduché aplikace pro GNOME fungující jako kytarová ladička. Předvedeme si, jako používat návrhář rozhraní.</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>Dokumentační projekt 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>Kytarová ladička</title>
Packit 1470ea
Packit 1470ea
<synopsis>
Packit 1470ea
  

V této lekci vytvoříme program, který přehrává tóny, které můžete použít k ladění kytary. Naučíte se, jak udělat tyto věci:

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

Vytvořit základní projekt ve studiu Anjuta.

</item>
Packit 1470ea
    <item>

Vytvořit jednoduché GUI v návrháři GUI ve studiu Anjuta.

</item>
Packit 1470ea
    <item>

Použít GStreamer k přehrání zvuku.

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

Abyste mohli pokračovat v této lekci, budete potřebovat následující:

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

Nainstalovanou kopii <link xref="getting-ready">IDE Anjuta</link>

</item>
Packit 1470ea
    <item>

Základní znalosti programování v jazyce C++

</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>Vytvoření projektu ve studiu Anjuta</title>
Packit 1470ea
  

Než začnete s kódováním, musíte ve studiu Anjuta vytvořit nový projekt. Tím se vytvoří všechny soubory, které budete později potřebovat k sestavení a spuštění kódu. Je to také užitečné kvůli udržení všeho pohromadě.

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

Spusťte IDE Anjuta a klikněte na <guiseq><gui>Soubor</gui> <gui>Nový</gui> <gui>Projekt</gui></guiseq>, aby se otevřel průvodce projektem.

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

Na kartě <gui>C++</gui> zvolte <gui>GTKmm (jednoduchý)</gui>. Klikněte na <gui>Pokračovat</gui> a na několika následujících stránkách vyplňte své údaje. Jako název projektu a složky použijte <file>guitar-tuner</file>.

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

Ujistěte se, že <gui>Konfigurovat externí balíčky</gui> je zapnuto. Na následující stránce vyberte v seznamu gstreamermm-0.10, aby se knihovna GStreamer zahrnula do vašeho projektu.

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

Klikněte na <gui>Dokončit</gui> a projekt se vám vytvoří. Otevřete <file>src/main.cc</file> z karty <gui>Projekt</gui> nebo <gui>Soubor</gui>. Měli byste vidět kód začínající řádky:

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>Prvotní sestavení kódu</title>
Packit 1470ea
  

Jedná se o zcela základní kód C++ nastavující GTKmm. Podrobněji je to popsáno dále. Pokud základům rozumíte, tak tento sezmam přeskočte:

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

Tři řádky s #include na začátku vkládají config (užitečný pro definice sestavení pomocí autoconf), gtkmm (uživatelské rozhraní) a iostream (STL). Funkce z těchto knihoven jsou použity ve zbytku kódu.

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

Funkce main vytvoří nové okno otevřením souboru GtkBuilder (<file>src/guitar-tuner.ui</file> definovaný a pár řádků dřív) a zobrazí jej v okně. Soubor obsahuje popis uživatelského rozhraní a všech jeho prvků. K návrhu uživatelského rozhraní můžete použít editor v IDE Anjuta.

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

Poté se volá několik funkcí, které nastaví a spustí aplikaci. Funkce kit.run spustí hlavní smyčku GTKmm, která spustí uživatelské rozhraní a začne naslouchat událostem (jako jsou kliknutí nebo zmáčknutí kláves).

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

Kód je připravený k použití, takže jej můžete zkompilovat kliknutím na <guiseq><gui>Sestavit</gui> <gui>Sestavit projekt</gui></guiseq> (nebo zmáčknutím <keyseq><key>Shift</key> <key>F7</key></keyseq>).

Packit 1470ea
  

V následujícím okně zmáčkněte <gui>Spustit</gui>, aby se nakonfigurovalo ladicí sestavení. Stačí to udělat jen jednou, pro první sestavení.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="ui">
Packit 1470ea
  <title>Vytvoření uživatelského rozhraní</title>
Packit 1470ea
  

Popis uživatelského rozhraní se nachází v souboru GtkBuilder. Když chcete uživatelské rozhraní upravit, otevřete <file>src/guitar_tuner.ui</file>. Přepnete se tím do návrháře rozhraní. Navrhované okno je uprostřed, widgety a jejich vlastnosti jsou nalevo a paleta dostupných widgetů je napravo.

Packit 1470ea
  

Rozvržení každého uživatelského rozhraní v GTK+ je provedeno pomocí boxů a mřížek. Zde použijeme svislý GtkButtonBox, do kterého přiřadíme šest GtkButtons, jedno pro každou z kytarových strun.

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
   

Vyberte <gui>GtkButtonBox</gui> z oddílu <gui>Kontejnery</gui> v <gui>Paletě</gui> napravo a vložte jej do okna. V panelu <gui>Vlastnosti</gui> nastavte počet prvků na 6 (pro 6 strun) a orientaci na svislou.

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

Nyní v paletě zvolte <gui>GtkButton</gui> a vložte jej do první části boxu.

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

Dokud je tlačítko ještě vybráno, změňte vlastnost <gui>Popisek</gui> na kartě <gui>Widgety</gui> na <gui>E</gui>. Bude se jednat o dolní strunu E. Také změňte vlastnost <gui>Název</gui> na <gui>button_E</gui>. Tímto názvem se na widget budeme později odkazovat v kódu.

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

Opakujte předchozí kroky po ostatní tlačítka, tj. přidejte dalších 5 řetězců s popisky A, D, G, B a e a názvy button_A, atd.

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

Uložte návrh uživatelského rozhraní (kliknutím na <guiseq><gui>Soubor</gui> <gui>Uložit</gui></guiseq>) a soubor zavřete.

Packit 1470ea
    </item>
Packit 1470ea
  </steps>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="gst">
Packit 1470ea
  <title>Roury systému GStreamer</title>
Packit 1470ea
  

GStreamer je základní multimediální rámec GNOME. Můžete jej použít k přehrávání, nahrávání a zpracování videa, zvuku, vysílání z webové kamery a podobně. Zde jej použijeme ke generování tónu s jednou frekvencí. GStreamermm je vazba C++ na GStreamer, kterou zde použijeme.

Packit 1470ea
  

Koncepčně GStreamer funguje následovně: Vytvoříte rouru (pipeline) obsahující různé prvky zpracující směrem od zdroje (source) do cíle (sink), tj. výstupu. Zdrojem může být například soubor s obrázkem, videosoubor nebo hudební soubor, výstupem pak widget nebo zvuková karta.

Packit 1470ea
  

Na cestě mezi zdrojem a cílem můžete použít různé filtry a převodníky k vytvoření efektů, převodníky formátů atd. Každý prvek roury má vlastnosti, které můžete použít ke změně jeho chování.

Packit 1470ea
  <media type="image" mime="image/png" src="media/guitar-tuner-pipeline.png">
Packit 1470ea
    

Příklad roury systému GStreamer.

Packit 1470ea
  </media>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="usinggst">
Packit 1470ea
  <title>Používání GStreamermm</title>
Packit 1470ea
  

Aby bylo možné používat knihovnu GStreamermm, je nutné ji inicializovat. To provedeme přidáním následujícího řádku s kódem za řádek Gtk::Main kit(argc, argv); v <file>main.cc</file>:

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

Když jsme u toho, ujistěte se také, že v <file>main.cc</file> je správně deklarováno include pro <file>gstreamermm.h</file>.

Packit 1470ea
Packit 1470ea
  

V tomto příkladu použijeme jako zdroj tónový generátor nazývaný audiotestsrc a výstup pošleme do výchozího systémového zvukového zařízení autoaudiosink. Nastavit potřebujeme jen frekvenci tónového generátoru. Ta je přístupná přes vlastnost freq zmíněného audiotestsrc.

Packit 1470ea
Packit 1470ea
  

Pro zjednodušení práce s rourou nadefinujeme pomocnou třídu Sound. Provedeme to v <file>main.cc</file>, abychom zachovali tuto ukázku jednoduchou, ale normálně byste k tomu použili samostatný soubor:

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
	/* Zastaví to po 200 ms */
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
  

Kód má následující účel:

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

V konstruktoru se vytvoří prvky GStreamer typu zdroj a cíl (Gst::Element) a prvek typu roura (který bude použit jako kontejner pro první dva prvky). Roura dostane název „note“. Zdroj je pojmenován „source“ a je nastaven jako audiotestsrc. Cíl je pojmenován „output“ a je nastaven jako autoaudiosink (výchozí výstup zvukové karty). Jakmile jsou prvky přidány do roury a spojeny dohromady, je roura připravena k použití.

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

start_playing nastaví zdrojový prvek, aby hrál příslušnou frekvenci, a následně spustí rouru, takže zvuk se začne opravdu hrát. Protože tento zvuk nechceme poslouchat navěky, nastavíme časový limit pro zastavení roury pomocí volání stop_playing po 200 ms.

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

Ve funkci stop_playing, která je zavolána po uplynutí časového limitu, je zastavena roura a zvuk tak přestané znít. GStreamermm používá počítání odkazů pomocí objektu Glib::RefPtr, takže po zlikvidování třídy Sound je paměť automaticky uvolněna.

Packit 1470ea
    </item>
Packit 1470ea
  </steps>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="signals">
Packit 1470ea
  <title>Připojení signálů</title>
Packit 1470ea
  

Když uživatel klikne na tlačítko, chceme přehrát správný zvuk. To znamená, že musíme napojit signál, který je spuštěn uživatelovým kliknutím na tlačítko. Také chceme volané funkci poskytnout informaci, který tón má zahrát. GTKmm toto usnadňuje, protože můžeme lehce propojit informace s knihovnou sigc.

Packit 1470ea
Packit 1470ea
  

Funkce, která je volána, když uživatel klikne na tlačítko, může být hezky jednoduchá, protože všechny zajímavé věci jsou nyní provedeny v pomocí třídě:

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
  

Toto je jen pomocná třída, kterou jsem nadeklarovali dříve, aby přehrávala správné frekvence. Kvůli přehlednějšímu kódy bychom také měli být schopni napojit se přímo do třídy bez použití funkce, ale necháme to tak, kvůli použití jako příkladu.

Packit 1470ea
Packit 1470ea
  

Kód nastavující signály by měl být přidán do funkce main() přímo za řádek builder->get_widget("main_window", main_win);:

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
	

Nejprve vytvoříme instanci naší pomocné třídy, kterou chceme nyní použít a deklarujeme proměnnou pro tlačítko, které na ni chceme napojit.

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

Následně obdržíme objekt tlačítka od uživatelského rozhraní, které bylo vytvořeno ze souboru s uživatelským rozhraním. Pamatujte, že button_E je název, který jsme dali prvnímu tlačítku.

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

Nakonec napojíme signál clicked. To není úplně přímočaré, protože je to uděláno typově plně bezpečným způsobem a prakticky chceme obsluze signálu předat frekvenci a naši pomocnou třídu. sigc::ptr_fun(&on_button_clicked) vytvoří slot pro metodu on_button_clicked, kterou jsme nadefinovali dříve. Pomocí sigc::bind jsme schopni předat dodatečné argumenty do slotu a v tomto případě tak předáme frekvenci (jako double) a naši pomocnou třídu.

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

Teď, když máte nastavené tlačítko E, musíme propojit ostatní tlačítka s jejich správnými frekvencemi: 440 pro A, 587.33 pro D, 783.99 pro G, 987.77 pro H (v anglické notaci B) a 1318.5 pro horní E. To se provede stejným způsobem, akorát se obsluze předá jiná frekvence.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="run">
Packit 1470ea
  <title>Sestavení a spuštění aplikace</title>
Packit 1470ea
  

Celý kód je nyní připraven ke spuštění. Klikněte na <guiseq><gui>Sestavit</gui> <gui>Sestavit projekt</gui></guiseq>, aby se vše znovu sestavilo, a pak na <guiseq><gui>Spustit</gui> <gui>Spustit</gui></guiseq>, aby se aplikace spustila.

Packit 1470ea
  

Pokud jste tak ještě neučinili, zvolte aplikaci <file>Debug/src/guitar-tuner</file> v dialogovém okně, které se objeví. Nakonec klikněte na <gui>Spustit</gui> a užijte si ji!

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="impl">
Packit 1470ea
 <title>Ukázková implementace</title>
Packit 1470ea
 

Pokud v této lekci narazíte na nějaké problémy, porovnejte si svůj kód s tímto <link href="guitar-tuner/guitar-tuner.cc">ukázkovým kódem</link>.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="further">
Packit 1470ea
  <title>Náměty ke čtení</title>
Packit 1470ea
  

Řada věcí předvedených výše je podrobně vysvětlena v <link href="http://library.gnome.org/devel/gtkmm-tutorial/stable/">Kniha o GTKmm</link>, která se zabývá více i klíčovými koncepty pro plnohodnotné použití GTKmm. Mohla by vás zajímat i <link href="http://library.gnome.org/devel/gstreamermm/">referenční dokumentace GStreamermm</link>.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="next">
Packit 1470ea
  <title>Další postup</title>
Packit 1470ea
  

Zde je pár nápadů, jak byste mohli tuto jednoduchou ukázku rozšířit:

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

Přidat do programu možnost cyklicky procházet tóny.

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

Naučit program přehrávat nahrávky vybrnkání jednotlivých reálných kytarových strun.

Packit 1470ea
   

Abychom to mohli udělat, potřebujeme sestavit mnohem složitější rouru GStreamer, která umožní načíst a přehrát hudební soubory. Budete muset zvolit prvky GStreamer typu <link href="http://gstreamer.freedesktop.org/documentation/plugins.html">dekodér a demultiplexor</link> podle formátu souborů s vašimi zvukovými nahrávkami – například MP3 používá jiné prvky než Ogg Vorbis.

Packit 1470ea
   

Můžete také potřebovat prvky propojit mnohem komplikovanějším způsobem. Toho lze dosáhnout pomocí <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-intro-basics.html">konceptů GStreamer</link>, které jsme v této lekci neprobírali. Mezi ně patří například <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-intro-basics-pads.html">přípojné body</link>. Hodit se vám může také příkaz <cmd>gst-inspect</cmd>.

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

Automaticky analyzovat tóny, které uživatel zahraje.

Packit 1470ea
   

Mohli byste připojit mikrofón a nahrávat z něj zvuky pomocí <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-autoaudiosrc.html">vstupního zdroje</link>. Zjistit, který tón je přehráván, by vám možná pomohla <link href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-plugin-spectrum.html">spektrální analýza</link>.

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