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í. Dokumentační projekt GNOME gnome-doc-list@gnome.org Johannes Schmid jhs@gnome.org Marta Maria Casetti mmcasetti@gmail.com 2013 Kytarová ladička

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:

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

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

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

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

Nainstalovanou kopii IDE Anjuta

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

Vytvoření projektu ve studiu Anjuta

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ě.

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

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

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

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

#include <gtkmm.h> #include <iostream>
Prvotní sestavení kódu

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:

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.

Funkce main vytvoří nové okno otevřením souboru GtkBuilder (src/guitar-tuner.ui 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.

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).

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

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

Vytvoření uživatelského rozhraní

Popis uživatelského rozhraní se nachází v souboru GtkBuilder. Když chcete uživatelské rozhraní upravit, otevřete src/guitar_tuner.ui. 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.

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.

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

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

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

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.

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

Roury systému GStreamer

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.

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.

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í.

Příklad roury systému GStreamer.

Používání GStreamermm

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 main.cc:

Gst::init (argc, argv);

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

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.

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

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

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

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í.

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.

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.

Připojení signálů

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.

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ě:

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

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.

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);:

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

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.

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.

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.

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.

Sestavení a spuštění aplikace

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

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

Ukázková implementace

Pokud v této lekci narazíte na nějaké problémy, porovnejte si svůj kód s tímto ukázkovým kódem.

Náměty ke čtení

Řada věcí předvedených výše je podrobně vysvětlena v Kniha o GTKmm, která se zabývá více i klíčovými koncepty pro plnohodnotné použití GTKmm. Mohla by vás zajímat i referenční dokumentace GStreamermm.

Další postup

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

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

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

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 dekodér a demultiplexor podle formátu souborů s vašimi zvukovými nahrávkami – například MP3 používá jiné prvky než Ogg Vorbis.

Můžete také potřebovat prvky propojit mnohem komplikovanějším způsobem. Toho lze dosáhnout pomocí konceptů GStreamer, které jsme v této lekci neprobírali. Mezi ně patří například přípojné body. Hodit se vám může také příkaz gst-inspect.

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

Mohli byste připojit mikrofón a nahrávat z něj zvuky pomocí vstupního zdroje. Zjistit, který tón je přehráván, by vám možná pomohla spektrální analýza.