Selasa, 17 Maret 2015

GTK Programming : Membuat Idle dan Timeout


Sampai sekarang, banyak kontributor yang mengupayakan GTK menjadi thread-safe, namun hal itu rupanya sangat sulit. Untuk mengakses widget dengan fungsi GTK secara bersamaan dari thread, banyak yang merekomendasikan untuk menggunakan idle atau time out. Setelah memahami 2 konsep ini, Anda dapat mengombinasikannya dengan thread tanpa harus kawatir masalah keamanan dalam multithreading.  Jadi, apa itu idle dan timeout?
 
Idle

Idle adalah suatu fungsi yang disisipkan pada main thread. Biasanya idle digunakan untuk mengakses widget secara terus menerus saat program berjalan.
Seperti yang telah kita ketahui sebelumnya, gtk_main() sebenarnya bekerja menerima event dan melanjutkannya kepada callback yang sesuai. Dengan menambahkan sebuah idle, fungsi yang kita inginkan akan dieksekusi setelah gtk_main() menangani handle.


Untuk menambahkan idle, kita dapat memilih satu dari 2 macam metode, yaitu dengan metode dari GDK atau dengan metode dari GLib. Menurut beberapa sumber, metode dari GDK lebih aman, namun ada pula sumber yang mengatakan keduanya sama saja. Jika dilihat dari dokumentasi GTK, penggunaan metode dari GLib ataupun GDK sama sekali tidak dipermasalahkan, namun programmer dianjukan untuk memakai fungsi dari GDK.

GDK:

guint gdk_threads_add_idle (GSourceFunc function, gpointer data);

GLib:
guint g_idle_add (GSourceFunc function, gpointer data);

function : Argumen ini berupa alamat ke fungsi callback GSourceFunc yang ingin didaftarkan. GSourceFunc merupakan fungsi khusus untuk membuat idle dan timeout. Bentuk fungsinya seperti berikut:

gboolean nama_callback (gpointer user_data);
{
   //do something
}

Fungsi callback ini akan terus dipanggil selama kita masih mengembalikan TRUE. Saat fungsi selesai dengan return FALSE, maka secara otomatis idle dihapus.  

data : Argumen kedua ini berupa pointer ke data yang dikirimkan pada fungsi callback. Sifatnya opsional, jadi bisa dikosongi.
 
Timeout

Timeout kurang lebih sama dengan idle. Perbedaanya, sebelum menjalankan fungsi callback, interval akan diperiksa terlebih dahulu.


Metode untuk membuat timeout juga disediakan oleh GDK dan GLib, sama halnya dengan idle. Parameter function dan data memiliki ketentuan pemakaian yang sama dengan fungsi yang dijelaskan sebelumnya. Fungsi berikut memiliki parameter interval, yaitu jangka waktu yang dipakai sebagai patokan sebelum pemanggilan fungsi callback. Satuan interval ditulis dalam milidetik, jadi, jika ingin callback dipanggil setiap 1 detik, gunakan argumen 1000 pada parameter interval.

GDK:

guint gdk_threads_add_timeout (guint interval, GSourceFunc function, gpointer data);

GLib:
guint g_timeout_add (guint interval, GSourceFunc function, gpointer data);



Contoh Kode
#include<stdio.h>
#include<gtk/gtk.h>

GtkWidget *window;
int num = 0;
char str[20];

gboolean timeout (gpointer user_data)
{
   sprintf((char*)&str,"Timeout: %d x", num);
   gtk_window_set_title(GTK_WINDOW(window),(char*)&str);
   num++;
   return TRUE;
}

void window_destroy (GtkWidget *object, gpointer user_data)
{
    g_print("Event destroy diterima :) \n");
    gtk_main_quit();
}

int main(int argc, char *argv[])
{
    gtk_init(&argc, &argv);
    //window baru
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window),"GtkWindow");
    //hubungkan signal destroy
    g_signal_connect (window, "destroy", G_CALLBACK (window_destroy),NULL);
    //daftar timeout. Fungsi akan dipanggil setiap 1000 ms (1 detik)
    gdk_threads_add_timeout(1000,timeout,0);
    //tampilkan widget
    gtk_widget_show_all(window);
    gtk_main();
    return 0;
}

Kode di atas akan membuat timeout dengan interval 1000 ms. Fungsi timeout() didaftarkan sebagai callback. Sehingga setiap satu detik, fungsi tersebut dipanggil. Dalam fungsi tersebut kita mengubah titlebar window dengan jumlah total pemanggilan fungsi callback.

Hasil

Read more

GTK Programming : Tipe Variabel Dasar GLib

GTK dibangun dengan mengimplementasikan GLib. Sehingga banyak tipe data yang mengikuti standar dari GLib. Pada dasarnya semua tipe data tersebut merupakan tipe data standar bahasa C yang didefinisikan sesuai konvensi GLib. Sederhananya, hampir semua tipe dasar GLib sama seperti fungsi standar C dengan tambahan karakter “g” di awal dan menyingkat keyword “unsigned” dengan karakter “u”.

Berikut ini adalah daftar lengkap tipe dasar GLib dan persamaannya dengan tipe standar yang biasa diimplementasikan pada bahasa C.



Tipe GLib
Tipe C
Tipe GLib
Tipe C
gboolean
int
gint16
signed short
gpointer
void*
guint16
unsigned short
gconstpointer
const void*
gint32
signed int
gchar
char
guint32
unsigned int
guchar
unsigned char
gint64
signed long
gint
int
guint64
unsigned long
guint
unsigned int
gfloat
float
gshort
short
gdouble
double
gushort
unsigned short
gsize
unsigned long
glong
long
gssize
signed long
gulong
unsigned long
goffset
unsigned long
gint8
signed char
gintptr
signed int
guint8
unsigned char
guintptr
unsigned int


Banyak tipe GLib yang memiliki kesamaan tipe dasar C, misalnya gsize dan gulong. Walaupun begitu, GLib tidak menggunakan tipe-tipe tersebut secara sembarangan. Misalnya tipe gulong digunakan untuk menampung data umum, sementara itu gsize lebih direkomendasikan untuk menyimpan ukuran suatu data dalam byte. Tipe gboolean merupakan definisi lain dari tipe int. Kita tahum tipe int dapat menampung data beragam, tapi penggunaan gboolean lebih direkomendasikan untuk menampung angka 0 atau 1 saja. Tipe gint8, guint8, dan lainnya juga demikian. Pada dasarnya kelompok tipe ini sama seperti tipe gint, guint dan lainnya. Bedanya fungsi gint dan lainnya dapat dipakai untuk menampung data umum, sementara guint8 dan lainnya direkomendasikan untuk menampung data yang erat kaitannya dengan pehitungan matematis.

Perbedaan penggunaan setiap tipe data tadi hanyalah rekomendasi. Jika anda tahu bahwa antara kedua tipe memiiliki kesamaan, anda bebas untuk menggunakan salah satu diantaranya. Bahkan anda juga boleh menggunakan tipe standar C saja.
Read more

Minggu, 15 Maret 2015

GTK Programming : GtkRange dan GtkScale


GtkRange merupakan kelas dasar yang diturunkan pada widget berjenis adjustment atau widget yang dkhususkan untuk peyesuaian level. Widget ini menyimpan beberapa properti untuk mengatur kerja widget. GtkScale adalah salah satu turunan GtkRange. Bentuk GtkScale panjang dengan dilengkapi satu buah kontrol slider untuk mengatur levelnya.

Tulisan ini lebih bermaksud untuk memperkenalkan GtkScale, namun karena widget ini turunan GtkRange, untuk menggunakannya kita harus sekaligus mengenal dan mempelajari GtkRange.

GtkScale dapat dengan mudah dibuat dengan fungsi gtk_scale_new_with_range(). Fungsi ini akan membuat sebuah widget sesuai dengan argumen yang diberikan.


GtkWidget *gtk_scale_new_with_range (GtkOrientation orientation, gdouble min, gdouble max, gdouble step);

Argumen yang digunakan dalam fungsi di atas adalah sebagai berikut:
  • orientation : GTK_ORIENTATION_VERTICAL atau GTK_ORIENTATION_HORIZONTAL
  • min : Nilai terendah yang bisa diatur melalui GtkScale
  • max : Nilai tertinggi
  • step : Perubahan nilai saat GtkScale diatur dengan arrow keyboard. Misalnya nilainya 2, maka saat menekan tombol panah atas, nilai GtkScale akan bergeser ke 2 nilai lebih tinggi.

Contoh Kode
#include<gtk/gtk.h>

int main(int argc, char *argv[])
{
    GtkWidget *window, *box, *scale1, *scale2;
    gtk_init(&argc, &argv);
    //window baru
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window),"GtkScale");
    gtk_widget_set_size_request(window,250,100);
    //buat box
    box = gtk_box_new(GTK_ORIENTATION_VERTICAL,10);
    //buat GtkAdjustment dan GtkScale
    scale1 = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0,100,1);
    scale2 = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0,100,1);
    gtk_range_set_inverted(GTK_RANGE(scale2),TRUE);
    //pack
    gtk_box_pack_start(GTK_BOX(box),scale1,TRUE,TRUE,10);
    gtk_box_pack_start(GTK_BOX(box),scale2,TRUE,TRUE,10);
    gtk_container_add(GTK_CONTAINER(window), box);
    //tampilkan widget
    gtk_widget_show_all(window);
    gtk_main();
    return 0;
 Pada kode di atas, kita juga mencoba satu metode dasar yang disediakan oleh GtkRange, yaitu gtk_range_set_inverted(). Fungsi ini sangat berguna untuk mengatur arah slider. Misalnya sebelum memanggil ini nilai minimum ada di kiri dan maksimum ada di kanan, maka fungsi ini dapat mengubah letak nilai minimum dan maksimum menjadi kebalikannya. Coba lihat screenshot untuk melihat efeknya. Adapun bentuk fungsi gtk_range_set_inverted adalah sebagai berikut.
void gtk_range_set_inverted (GtkRange *range, gboolean setting);

Fungsi diatas akan memutar arah saat argumen setting adalah TRUE, untuk mengembalikan ke keadaan semula, kita cukup memanggil fungsi ini dengan argumen setting = FALSE.

Beberapa fungsi di bawah ini mungkin juga akan bermanfaat untuk memperluas fungsional program Anda.

Mengubah posisi dan nilai fill level GtkScale :

void gtk_range_set_value (GtkRange *range, gdouble value);
  Menyembunyikan/menampilkan fill level:
void gtk_range_set_show_fill_level (GtkRange *range, gboolean show_fill_level);
  Selain mengenal fungsi dasarnya, mungkin akan lebih baik jika Anda mengenal beberapa jenis callback yang ada pada GtkRange. Semua callback ini bisa dihubungkan dengan fungsi g_signal_connect() seperti pada tulisan-tulisan sebelumnya.

“change-value” : signal ini muncul saat kontrol slider GtkScale digerakkan oleh pengguna.
void user_function (GtkRange *range, gpointer user_data)
{
   //handler
}
 

“format-value” : Signal berasal berasal dari GtkScale. Dapat anda gunakan untuk mengganti angka fill level yang ditampilkan diatas widget. Signal ini juga dipanggil saat slider digerakkan.

gchar *user_function (GtkScale *scale, gdouble value, gpointer user_data)
{
   //handler
}
  Contoh penggunaannya adalah sebagai berikut:
...
#include<malloc.h>
...
gchar *scale_format_value (GtkScale *scale, gdouble value, gpointer user_data)
{
   char *val;
   val = (char*)malloc(50); //Jangan kawatir, GTK akan mengeksekusi free() setelah selesai.
   sprintf(val, "Value = %f", value);
   return val;
}

GtkWidget *scale;
int main(int argc, char *argv[])
{
    ...
    g_signal_connect (scale, "format-value", G_CALLBACK (scale_format_value),NULL);
    ...
     
Hasil



Read more

GTK Programming : Membuat Thread dengan GLib


Thread adalah bagian dari proses, namun thread bukanlah proses. Dalam sebuah proses minimal terdapat satu buah thread utama, disebut juga sebagai main thread. Dalam program C, main thread adalah kode yang berada pada fungsi main() sekaligus fungsi-fungsi yang dipanggil dari main().

Thread biasanya dibuat untuk menjalankan tugas lebih cepat, atau digunakan saat ada 2 tugas yang harus dikerjakan secara bersamaan. Misalnya dalam sebuah video player, kita tidak bisa hanya bekerja dengan main thread, setidaknya ada 1 atau 2 lagi thread lainnya. Thread utama untuk menerima input/perintah dari user, thread kedua untuk mengolah suara dan thread ketiga untuk mengolah video. Tentu saja hal ini tidak bisa dilakukan dengan 3 fungsi yang berjalan secara berurutan, ketiganya harus berjalan bersamaan.
 
Dengan membuat thread baru, itu artinya kita membuat fungsi lain berjalan bersamaan dengan fungsi main() dalam waktu yang sama. Dengan berjalan bersamaan, program dapat berjalan lebih cepat. Tapi hal itu bukan berarti akan membuat semuanya lebih mudah.

Program yang menjalankan lebih dari satu thread, harus menjaga agar data global tidak diakses secara bersamaan. Jika tidak, hal yang tak diinginkan dapat terjadi sewaktu-waktu. Sehingga program yang mengimplementasikan multithreading harus mempertimbangkan syncronization primitives.

Kita tidak akan membahas bagaimana mengimplementasikan syncronization primitives. Tapi sekarang kita akan membahas permasalahan thread di GTK yang sangat erat kaitannya dengan multithreading.

Sebuah library dikatakan thread-safe apabila dapat diakses oleh banyak thread secara bersamaan. GTK mungkin aman dipakai untuk banyak program, tetapi rupanya GTK sampai sekarang belum tergolong thread-safe. Jadi, GTK hanya diperbolehkan untuk diakses dari main thread saja.
Semua fungsi callback sebenarnya dieksekusi sebagai bagian dari main thread, jadi jangan kawatir. Lagipula, tidak banyak keperluan berkaitan GTK yang harus diakses melalui thread. Jika ada, maka kita sebaiknya menggunakan idle dan timer untuk melakukannya. Selengkapnya tentang idle dan timer akan dibahas pada kesempatan lain yaa..

Baik, sekarang kita bahas bagaimana membuat thread. Walaupun kita tidak bisa mengakses GTK dari sini, nantinya kita akan menemui banyak sekali hal yang harus dilakukan secara multithreading.
Untuk membuat sebuah thread, gunakan fungsi berikut.


GThread *g_thread_new (const gchar *name, GThreadFunc func, gpointer data);

Fungsi di atas mengembalikan struktur GThread. Struktur ini bersifat opaque, atau tidak bisa diakses secara langsung. Kita hanya perlu tahu bahwa struktur ini berisi tentang informasi thread. Fungsi ini menggunakan 3 argumen, yaitu:
  • name : identitas thread. Digunakan untuk keperluan debug, jadi cukup isikan sesuai dengan keinginan anda. Maksial 16 karakter
  • func : Pointer ke fungsi GThreadFunc, yaitu fungsi yang digunakan sebagai thread.
  • data : Data yang digunakan sebagai argumen pada fungsi GThreadFunc.

GThreadFunc
Berbeda dengan fungsi main thread seperti biasa (int main()). Bentuk fungsi thread yang dibuat harus memiliki bentuk sebagai berikut.

gpointer nama_fungsi (gpointer data);
{
   //lakukan sesuatu
}

Return value bukan berupa int, tapi berupa data dalam bentuk pointer. Untuk mengetahui data yang dikembalikan oleh thread, gunakan fungsi berikut.

gpointer g_thread_join (GThread *thread);


Contoh
#include<gtk/gtk.h>

/* thread ini mengeprint pesan
 * lalu pause/sleep selama 1 detik
 * selama 10 kali
 * setelah itu mengembalikan nilai pointer ke string "abcde"
 */
char *r = "abcde \n";
gpointer thread(gpointer data)
{
    int i;
    for(i=10;i!=0;i--){
        g_print("Pesan dari thread() \n");
        g_usleep(1000000);
    }
    return r;
}

int main(int argc, char *argv[])
{
    GThread *t;
    //buat thread
    t = g_thread_new("mythread", thread,0);
    
    //cetak pesan dan sleep 10x
    int i;
    for(i=10;i!=0;i--)
    {
        g_print("Pesan dari main() \n");
        g_usleep(1000000);
    }
    //dapatkan return value
    g_print("Nilai return dari thread: %s \n",(char *)g_thread_join(t) );
}

Kode di atas juga menunjukkan bagaimana menggunakan fungsi g_usleep(). Fungsi ini digunakan untuk melakukan penundaan/pause dalam kurun waktu sekian microsecond.


void g_usleep (gulong microseconds);

Sekali lagi, ingat, jangan memanggil fungsi GTK dari thread :)

Hasil


Read more

GTK Programming : Yang Terlewat, gtk_main_quit()


Setelah sekian banyak tulisan tentang GTK saya posting, ada satu hal yang sengaja saya tunda waktu postingnya. Hal itu saya maksudkan untuk mengurangi kerumitan kode program saat penjelasan.

Setiap program GTK, selalu memanggil fungsi gtk_main() setelah menyiapkan dan menampilkan semua widgetnya. Apa anda penasaran apa yang ada di gtk_main()?

Fungsi gtk_main() sebenarnya adalah fungsi untuk menunggu event. Saat event diterima, gtk_main() memanggil fungsi callback yang telah didaftarkan dengan g_signal_connect().  Banyak programmer GTK awalnya mengira, saat window ditutup program akan berhenti dengan sendirinya. Tapi saat mereka menjalankan program melalui terminal, mereka tahu, bahwa program ternyata masih tetap berjalan. Saat tombol tutup di pojok window kita klik, itu hanya menutup window saja. Saat itu gtk_main() akan terus berjalan menunggu event.

Untuk menghentikan gtk_main(), kita hanya bisa melakukannya dengan fungsi gtk_main_quit(). Darimana kita mengeksekusi fungsi tersebut? Program kan terus membaca event?
Sebenarnya saat window ditutup, ia mengeluarkan signal “destroy”, tepat setelah window menghilang dari desktop. Bagian inilah yang dapat kita manfaatkan untuk membelokkan gtk_main() ke fungsi callback untuk menangani event “destroy” tadi. Dalam fungsi callback kita sisipkan saja kode gtk_main_quit(), dan selesailah sudah.

Jika kita sebelumnya mengalokasikan memory atau resource, semua sebaiknya kita bebaskan dari fungsi callback ini.

Source code 


#include<gtk/gtk.h>
#include<malloc.h>

void window_destroy (GtkWidget *object, gpointer user_data)
{
    g_print("Event destroy diterima :) \n");
    gtk_main_quit();
}

int main(int argc, char *argv[])
{
    GtkWidget *window;
    gtk_init(&argc, &argv);
    //window baru
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window),"GtkWindow");
    //hubungkan signal
    g_signal_connect (window, "destroy", G_CALLBACK (window_destroy),NULL);
    //tampilkan widget
    gtk_widget_show_all(window);
    gtk_main();
    //Setelah gtk_main_quit() dipanggil...
    g_print("Hey, gtk_main_quit() sudah dipanggil :) \n");
    return 0;
}


Hasil
Read more

Jumat, 13 Maret 2015

Google Akan Menutup Google Code, Pemilik Blog Harus Waspada


Apa anda pernah menitipkan sendal dan sepatu di Google Code? Eh, maksud saya source code. :v
Jika anda bukan programmer dan merasa tidak pernah menghosting apapun, jangan santai dulu. Setahu saya, banyak template blogger yang menghosting javascript dan css di Google Code. Jadi, siap-siap aja deh ya..
Saran saya, coba telusuri link javascript atau css dari template Anda. Jika mengarah ke Google Code, segera unduh, cari hosting baru, dan ganti dengan link yang baru.

Kenapa Google menutup layanan ini?
Padahal Google Code adalah layanan yang masih sangat aktif digunakan oleh para programmer untuk menyimpan source codenya. Entah bagaimana nasib project-project ini nantinya. Tapi saya harap tidak akan ada masalah, karena setiap akun mendapatkan notifikasi melalui email. Google menyediakan waktu untuk membiarkan member berakomodasi atau memindahkan proyek mereka ke layanan lain, misalnya GitHub dan Sourceforge.


Menurut informasi yang berhasil saya peroleh, Google Code mulai hari ini tidak menerima pembuatan project baru mulai hari ini, namun proyek yang sudah ada masih bisa menerima pembaharuan. Selanjutnya, pada bulan Agustus kita tidak bisa lagi memperbaharui proyek. Namun, semua file masih bisa diakses dan diunduh hingga pada 26 Januari 2016. Karena pada tanggal itulah saat dimana Google benar-benar menutup layanan Google Code.

Berhentinya layanan Google Code bukan tanpa alasan. Alasan pertama, mungkin karena Google kalah bersaing dengan layanan lain. Alasan kedua, adalah karena pihak Google mendapati terjadinya peningkatan spam dan penipuan di layanan Google Code. Meningkatnya spam ini diakibatkan oleh banyaknya klien yang memindahkan proyek mereka ke tempat hosting lain.

Itulah kenapa alasan Google menutup Google Code dan kenapa hal ini berpengaruh pada pemilik blog. Kita berdoa saja, mudah-mudahan Google dapat merubah pikirannya, ya... :)
Read more

Inilah GNOME Builder, Software IDE Untuk Lingkungan Desktop GNOME

 
GNOME bukan hanya menjadi lingkungan desktop terbesar di Linux. Bisa jadi GNOME adalah pelopor desktop environment yang inovatif di lingkungan Linux. Sampai saat ini GNOME tetap aktif bekerja dan berkreasi untuk menciptakan desktop environment yang senyaman mungkin bagi user.  Seperti itulah pendapat saya tentang GNOME. :)

GTK Sangat erat kaitannya dengan lingkungan desktop GNOME. Sebagai widget toolkit defaut, perkembangan GTK+ akan menentukan bagaimana GNOME berkembang. Jika sebelumnya sudah ada Glade sebagai user interface designer GTK, maka sekarang GNOME akan mencoba mengembangkan software yang lebih dari itu. Software ini bernama GNOME Builder, atau cukup disebut Builder.


Builder adalah sebuah software Integrated Development Environment(IDE) yang dispesialisasikan untuk lingkungan desktop GNOME. Walaupun begitu, bukan tidak mungkin jika software ini dapat dijalankan pada desktop lain. Saat ini pengembangannya masih sedang dalam tahap awal dan pihaknya masih belum tahu kapan versi stabil akan dirilis. Sembari melanjutkan pngembangan, tim developer juga sedang melakukan kegiatan penggalangan dana untuk mendukung pengembangan fitur, yang direncanakan.
Adapaun beberapa fitur yang direncanakan dan sedang dalam tahap pengerjaan adalah sebagai berikut.
  • Project Management
  • Asset Catalog
  • Auto completition dan Indentation
  • Glade Built-In
  • Dll

Sepertinya GTK Builder tidak akan jauh berbeda seperti IDE lainnya. Tapi, yang membuatnya istimewa adalah fitur Glade yang sudah Built-in. Fitur ini memungkinkan proses desain user interface dapat dilakukan dengan mudah seperti layaknya Visual Studio.

Saya sudah tak sabar untuk menanti rilis stabil yang pertama. Harapannya, jumlah programmer GTK semakin meningkat dengan diciptakan software ini. :)
Anda juga tak sabar kan? Hmm, mungkin dengan sedikit bantuan donasi dari Anda, project ini bisa segera diselesaikan :)
https://wiki.gnome.org/Apps/Builder/Fundraiser
hehehe :)
Read more

Membaca Tag ID3 Pada MP3 Player


Tulisan ini dimaksudkan untuk melanjutkan yang sebelumnya, tentang Tutorial Pembuatan MP3 Player.

Saat spesifikasi format MP3 diciptakan, terdapat satu masalah yang belum sempat terpecahkan. File MP3 tidak mendukung metode untuk menympan informasi tentang suara MP3. Akhirnya muncullah ide di luar spesifikasi untuk menambahkan potongan informasi metadata di bagian belakang data MP3.

Tag ID3 awalnya hanya menyimpan informasi tentang judul lagu, artis, album, tahun, komentar dan genre saja. Namun, spesifikasi yang baru memungkinkan sebuah file MP3 memiliki informasi yang lebih lengkap, misalnya gambar album, rating dan nomor track.

Ada 2 versi tag ID3, yaitu ID3v1 dan ID3v2. Fungsinya tidak berbeda, namun struktur datanya sedikit berbeda diantara keduanya. ID3v2 adalah spesifikasi yang lebih baru, sehingga dapat menampung informasi lebih lengkap.

Sebuah file MP3 yang menyimpan informasi lebih lengkap dengan ID3v2, akan tetap menyimpan data ID3v1. Hal ini dimaksudkan untuk menjaga kompatibilitas software pemutar MP3 yang terdahulu yang masih belum mendukung ID3v2.

Untuk memperoleh informasi tag ID3, mpg123 menyediakan sebuah fungsi mpg123_id3() untuk memperoleh data ID3.

int mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_id3v2 **v2);

Fungsi diatas menggunakan 2 buah parameter. Salah satu parameter boleh diberi argumen 0 (NULL) jika tidak ingin mendapatkan salah satu data ID3. Jika berhasil fungsi ini mengembalikan nilai 0 (MPG123_OK). Parameter v1 adalah pointer ke pointer struktur yang menampung informasi tag id3v1. Berikut ini adalah bentuk strukturnya.

typedef struct
{
    char tag[3];         /**< Always "TAG". */
    char title[30];      /**< Title string.  */
    char artist[30];     /**< Artist string. */
    char album[30];      /**< Album string. */
    char year[4];        /**< Year string. */
    char comment[30];    /**< Comment string. */
    unsigned char genre; /**< Genre index. */
} mpg123_id3v1;

*Member tag digunakan untuk memeriksa apakah data yang diproleh valid ataukah tidak. Jika karakter yang ada dalam member ini bukan “TAG”, maka lebih baik anda memeriksanya.
*Member genre merupakan kode genre dari musik yang dibuka, untuk mengetahui daftar lengkapnya lihat link berikut : http://en.wikipedia.org/wiki/ID3.

Sementara itu parameter v2 adalah pointer ke pointer struktur penampung informasi ID3v2. Isi dari struktur ini sebenarnya lebih lengkap dibanding kan ID3v1, namun karena tulisan ini ditujukan untuk pembelajaran, dan mengutamakan kemudahan pemahaman pembaca, maka tulisan ini hanya akan menunjukkan dasarnya saja. Jadi untuk parameter kedua(v2), kita akan memberikan argumen 0. Walaupun begitu, anda bisa mencoba memperoleh ID3v2 dengan melihat bentuk strukturnya dalam dokumentasi libmpg123 :)  


Source Code
#include <mpg123.h>
#include <ao/ao.h>

#define MP3_FILE "/home/irvan/Closer To The Edge.mp3"
int main()
{
    mpg123_handle    *handle;
    ao_sample_format sample_format;
    ao_device        *device;
    int              driver_id;
    char             *buffer;
    unsigned int     ukuran_buffer;
    long             rate;
    int              channels;
    int              encoding;
    mpg123_id3v1     *id3v1;
      
      
//inisialisasi MPG123
    printf("Komputoo MP3 player\nMemutar %s...\n", MP3_FILE);
    printf("Menyiapkan libmpg123\n");
    mpg123_init();
    handle = mpg123_new(0, 0);
    if(handle == 0)
    {
        printf("Gagal membuat handle baru!\n");
        exit(EXIT_FAILURE);
    }
   
//inisialisasi AO
    printf("Menyiapkan libao\n");
    ao_initialize();
    driver_id = ao_default_driver_id();
    if(driver_id == -1)
    {
        printf("Driver ID tidak diketahui\n");
        exit(EXIT_FAILURE);
    }

//buka mp3
    if(mpg123_open(handle,MP3_FILE) != 0)
    {
        printf("Gagal membuka file!\n");
        exit(EXIT_FAILURE);
    }

//inisialisasi memori buffer untuk menyimpan hasil decode mp3
    ukuran_buffer = mpg123_outblock(handle);
    buffer = (char*) malloc(ukuran_buffer);

//inisialisasi struktur sample_format dari MP3 yang terbuka
    printf("Mengolah informasi MP3...\n");
    mpg123_getformat(handle, &rate, &channels, &encoding);
    sample_format.bits = mpg123_encsize(encoding) * 8;
    sample_format.rate = rate;
    sample_format.channels = channels;
    sample_format.byte_format = AO_FMT_NATIVE;
    sample_format.matrix = 0;
   
//inisialisasi ao sebelum playing
    device = ao_open_live(driver_id, &sample_format, 0);
    if(device == 0)
    {
        printf("ao_open_live error!\n");
        exit(EXIT_FAILURE);
    }

//lihat ID3
if (mpg123_id3(handle, &id3v1, 0) == MPG123_OK)
{
    printf("ID3v1: \n");
    printf(" - Title: %s \n", id3v1->title);
    printf(" - Artist: %s \n", id3v1->artist);
    printf(" - Album: %s \n", id3v1->album);
}

//decode dan play mp3
    printf("Memutar MP3...\n");
    size_t terbaca;
    while(mpg123_read(handle, buffer, ukuran_buffer, &terbaca) == 0)
    {
        ao_play(device, buffer, ukuran_buffer);
    }
   
//akhir
    printf("Selesai.\n");
    free(buffer);
    mpg123_close(handle);
    mpg123_delete(handle);
    mpg123_exit();
    ao_close(device);
    ao_shutdown();
   
}

Kode diatas hanya mencoba mencetak Judul, artis dan album saja. Jika anda ingin mencoba mengeprint tahun lagu, sebaiknya anda membuat sebuah buffer dulu, lalu mengopy 4 karakter tahun ke buffer tersebut, danjangan lupa untuk memberikan karakter \0 dibelakang tahun. Ini harus dilakukan karena string tersebut tidak disimpan dengan null-terminated.

Hasil

Read more

Kamis, 05 Maret 2015

2 Tema Plymouth Keren Untuk Ubuntu Anda

 

Sudah bosan ya sama tampilan boot ubuntu yang itu-itu aja? :v
Oke, kali ini saya akan sedikit berbagi 2 tema plymouth yang menurut saya paling keren. Sebenarnya masih ada banyak pilihan tema di luar sana, tapi seperti biasa, entah kenapa tidak ada yang greget bagi saya :v

Dari hasil penelusuran saya, hanya ada 2 tema yang tampilannya sesuai dengan hati saya. Berikut ini screenshot dan link downloadnya..


Ubuntu Spinner Logo



Ubuntu Orange


Selamat mencoba :)
Read more

Rabu, 04 Maret 2015

Cara Memperbaiki Ubuntu Checking Disk Drive Error Setiap Booting


Setelah sekian kali mengalami kerusakan harddisk saya "hampir" kapok, tobat deh pokoknya "kalo bisa". Tapi bukan tobat yang sebenar-benarnya. Orang bilang tobat lombok. Setelah mengaku bersalah, saya ulangi lagi. hehehe :D

Awalnya saya suka gonta-ganti OS. Suka membuat virus sampai sistem rusak parah (Mentang-mentang punya CD Windows bajakan). Tapi pengalaman itu sudah lama sekali, dan akan selalu menjadi pelajaran berharga bagi saya. Sejak kerusakan terjadi, saya jadi mulai berhati-hati memperlakukan harddisk. Apalagi saya tahu, harddisk tipe ATA sudah mulai tergantikan oleh harddisk SATA. Akibatnya setiap terjadi kerusakan, gantinya ya, harddisk bekas. Meskipun demikian, saya masih sedikit merasa berat untuk tobat dan tidak mengulangi kesalahan.

Semenjak saya punya laptop baru, kelakuan saya semakin menjadi-jadi :v
Install ini itu, dibikin dual boot, dsb. Tidak terasa, namun dampaknya mulai terlihat setelah 2 tahun. Akhir-akhir ini saya coba macam-macam desktop environment di ubuntu saya. Ya, meskipun sudah jarang gonta ganti OS, intensitas pemakaian laptop saya lebih tinggi. Mungkin ini juga yang membuat harddisk saya mulai lapar, eh, capek...

Setiap boot, saya harus menunggu sistem melakukan scanning disk, dan setelah beberapa saat pasti ditemukan error. Bukan hanya itu, kira-kira setelah beberapa menit pemakaian desktop, tiba-tiba filesystem menjadi read-only. Jadi saya gak bisa apa-apa, selain melihat-lihat file. T_T

Ya, sepertinya ini awal dari tobat saya yang sebenarnya. Kalo sampai harddisk laptopnya rusak, wah, duit...
Awalnya saya coba install ulang, tapi tak ada efeknya. Tak setimpal dengan banyaknya data saya yang harus dikorbankan.
Percobaan kedua, saya masuk recovery mode, lalu menjalankan command fsck -f -p -c /dev/nama_device_root. Hmm, entah kenapa, saya rasa hasilnya kurang memuaskan.

Percobaan selanjutnya saya mengikuti sebuah postingan dari sebuah forum. dan Alhamdulillah, berhasil :) caranya sederhana, yaitu menggunakan command badblocks. Berikut ini langkahnya:
Pertama ketahui partisi root filesystem( / ), dengan menjalankan command mount.
Misalnya dalam system saya keluar hasil seperti berikut
irvan@irvan-Satellite-C800:~$ mount
/dev/sda5 on / type ext4 (rw,errors=continue)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/cgroup type tmpfs (rw)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)
none on /sys/fs/pstore type pstore (rw)
systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,user=irvan)
/dev/sda3 on /media/irvan/DATA type fuseblk (rw,nosuid,nodev,allow_other,default_permissions,blksize=4096)


Maka sekarang dapat diketahui, bahwa root berada pada /dev/sda5. Ok, sekarang jalankan perintah badblocks.
sudo badblocks -n -f /dev/sda5

*Ubah /dev/sda5 dengan lokasi partisi root anda sendiri.
*Jika error, coba masuk recovery mode saat boot.

Waktu scanning memang agak lama, tapi hasilnya memuaskan (y)
Anda senasib dengan saya? silahkan mencoba :)
Read more