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 programovacího jazyka 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 <config.h>
#include <gtk/gtk.h>
C je celkem „upovídaný“ jazyk, takže nebuďte překvapeni, že soubor obsahuje poměrně hodně kódu. Většina toho je kód šablony. Načte (prázdné) okno ze souboru s popisem uživatelského rozhraní a zobrazí jej. Dále to podrobněji rozebereme. Pokud jste již pochopili základy, tak tento seznam můžete přeskočit:
Tři řádky #include
na začátku vkládají knihovny config
(užitečné definice pro sestavení pomocí autotools), gtk
(uživatelské rozhraní) a gi18n
(internacionalizace). Funkce z těchto knihoven se používají ve zbytku kódu.
Funkce create_window
vytvoří nové okno ze souboru GtkBulder (
Napojení signálu je způsob, jak definovat, co se má stát, když zmáčknete tlačítko nebo se prostě něco přihodí. Zde je zavolána metoda destroy
(a ukončení aplikace) při zavření okna.
Funkce main
se spustí jako výchozí, když spustíte aplikaci napsanou v jazyce C. Volá pár funkcí, které nastaví a spustí aplikaci. Funkce gtk_main
spustí hlavní smyčku GTK, která spustí uživatelské rozhraní a začne naslouchat událostem (jako je kliknutí nebo zmáčknutí klávesy).
Podmíněná definice ENABLE_NLS
nastavuje gettext
, což je základní konstrukce pro překládání aplikací do národních jazyků. Tyto funkce určují, jak mají překladové nástroje pracovat s vaší aplikací za běhu.
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
Zatímco je tlačítko stále vybráno, změňte vlastnost
Přepněte se na kartu clicked
tlačítka. Můžete jej použít k napojení na obsluhu signálu, která bude volána, když uživatel na tlačítko klikne. Provede se to kliknutím na signál a vepsáním on_button_clicked
do sloupce
Zopakujte předchozí kroky pro ostatní tlačítka, takže přidáte následujících 5 strun s názvy A, D, G, B a e.
Návrh uživatelského rozhraní uložte (kliknutím na
V návrháři uživatelského rozhraní můžete nastavit to, že všechna tlačítka budou při kliknutí volat stejnou funkci
K tomu otevřete
void on_button_clicked (GtkWidget* button, gpointer user_data)
{
}
Obsluha signálu má dva argumenty: ukazatel na GtkWidget
, který funkci zavolal (v našem případě vždy GtkButton
) a ukazatel na nějaká „uživatelská data“, která si můžete nadefinovat, ale zde je nebudeme chtít použít. (Uživatelská data můžete nastavit zavoláním gtk_builder_connect_signals
. Normálně se použivá k předání ukazatele na datovou strukturu, ke které můžete potřebovat přístup uvnitř obsluhy signálu.)
Prozatím ponecháme obsluhu signálu prázdnou a budeme pracovat na psaní kódu pro vyluzování zvuků.
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í.
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.
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
.
Vložte do #include <gtk/gtk.h>
:
#include <gst/gst.h>
Tímto se vloží knihovna GStreamer. Potřebujete také přidat řádek inicializující GStreamer. Vložte následující kód na řádek nad volání gtk_init
do funkce main
:
gst_init (&argc, &argv);
Pak nakopírujte následující funkci do on_button_clicked
:
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");
/* nastaví frekvenci */
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);
/* zastaví to po 500 ms */
g_timeout_add (LENGTH, (GSourceFunc) pipeline_stop, pipeline);
}
Prvních pět řádků vytvoří prvky GStreamer typu zdroj a cíl (GstElement
) 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).
Volání g_object_set
nastaví vlastnost freq
zdrojového prvku na frequency
, která byla předána jako argument funkci play_sound
. Jedná se o frekvenci tónu v hertzích. Správné frekvence nadefinujeme později.
gst_bin_add_many
vloží zdroj a cíl do roury. Roura je GstBin
, což je zase jen prvek, který může obsahovat více dalších prvků GStreamer. Obecně můžete přidat tolik prvků, kolik chcete, pomocí předáním více argumentů do gst_bin_add_many
.
Následně je gst_element_link
použito k propojení prvků navzájem, takže výstup prvku source
(tón) putuje do vstupu prvku sink
(což je výstup do zvukové karty). gst_element_set_state
je použito ke spuštění přehrávání nastavením stavu roury na přehrávání (GST_STATE_PLAYING
).
Nechceme ale hrát nějaký tón navždycky, takže poslední věcí, kterou play_sound
udělá, je, že zavolá g_timeout_add
. Tím se nastaví časový limit pro zastavení zvuku. Čeká v délce LENGTH
milisekund a pak zavolá funkci pipeline_stop
, která vrátí FALSE
, jinak by se v jejím volání pokračovalo.
Nyní budeme psát funkci pipeline_stop
, která je volána z g_timeout_add
. Vložte následující kód nad funkci play_sound
:
#define LENGTH 500 /* Délka přehrávání v ms */
static gboolean
pipeline_stop (GstElement* pipeline)
{
gst_element_set_state (pipeline, GST_STATE_NULL);
g_object_unref (pipeline);
return FALSE;
}
Zavolání gst_element_set_state
zastaví přehrávání roury a g_object_unref
zruší odkazy na rouru, zlikviduje ji a uvolní její paměť.
Když uživatel klikne na tlačítko, chceme zahrát správný zvuk. Nejdříve ze všeho potřebujeme znát frekvence pro šest kytarových strun, které jsou definovány (na začátku
/* Řetězce pro jednotlivé frekvence */
#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
Nyní oživíme obsluhu signálu, kterou jsme zadeklarovali již dříve po názvem on_button_clicked
. Mohli bychom mít napojená všechna tlačítka na různé obslužné funkce, ale to by vedlo ke zbytečné duplicitě kódu. Místo toho použijeme popisek každého z tlačítek ke zjištění, na které tlačítko bylo kliknuto:
/* Zpětná volání pro tlačítka */
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);
}
Ukazatel na GtkButton
, na které bylo kliknuto je předán jako argument (button
) do on_button_clicked
. Text tohoto tlačítka můžeme získat pomocí gtk_button_get_label
.
Text se porovnává s notami, které máme pomocí g_str_equal
a play_sound
je voláno s příslušnou frekvencí odpovídající notě. Tím se zahraje tón a my máme konečně fungující kytarovou ladičku!
Celý kód by nyní měl být připravený k fungová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.
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.