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++
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
Na kartě
Ujistěte se, že
Klikněte na
#include <gtkmm.h>
#include <iostream>
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 (
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
V následujícím okně zmáčkněte
Popis uživatelského rozhraní se nachází v souboru GtkBuilder. Když chcete uživatelské rozhraní upravit, otevřete
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
Nyní v paletě zvolte
Dokud je tlačítko ještě vybráno, změňte vlastnost
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
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.
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
Gst::init (argc, argv);
Když jsme u toho, ujistěte se také, že v include
pro
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
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.
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.
Celý kód je nyní připraven ke spuštění. Klikněte na
Pokud jste tak ještě neučinili, zvolte aplikaci
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.
Ř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.
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
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.