Minggu, 11 Januari 2015

Mengetahui Durasi MP3 dan Cara Seeking MP3 Player


Sudah paham kan tutorial yang saya jelaskan sebelumnya?
Saya harap begitu, karena pada kesempatan ini, kita akan mencoba bereksperimen menggunakan libmpg123 untuk memutar MP3 secara lebih spesifik lagi. Jika kemarin kita hanya membuat program memutar dari awal sampai akhir, maka hari ini kita akan mencoba memutar MP3 pada titik durasi tertentu, misalnya memutar maju pada durasi 1:10, atau mencoba mundur ke 0:50.

Masih ingin lanjut kan?

Perlu diketahui, meskipun penulisan program dengan C lebih sulit dibanding bahasa pemrograman tingkat tinggi, hasil program yang dihasilkan bersifat portabel, dan juga cepat. Program yang dibuat dengan bahasa tingkat tinggi umumnya dijalankan dengan interpreter. Memang benar perbeaannya tidak nampak. Tapi jika anda menekuni program ini semakin serius dan semakin kompleks, perbedaan yang signifikan itu akan segera muncul. Mungkin ini juga alasan kenapa MP3 player tidak ada yang ditulis dengan bahasa tingkat tinggi.
Bukan bermaksud menyinggung, saya hanya ingin memotivasi Anda. LOL :v

Kode Sepenuhnya
Sebelum mempelajari, saya izinkan agan untuk mencoba dan mengamati source codenya. Berikut ini hanyalah pengembangan kode dari tutorial sebelumnya.  Cara kompilasinya juga tetap sama. Bagian tambahan kode sudah saya tandai agar agan-agan lebih mudah fokus untuk mempelajari API yang baru saja.

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

#define MP3_FILE "/home/irvan/test.mp3"
int main(int argc, char *argv[])
{
    mpg123_handle       *handle;
    ao_sample_format    sample_format;
    ao_device           *device;
    int                    driver_id;
    char               *buffer;
    unsigned int        ukuran_buffer;
    long                rate; //sample rate
    int                    channels;
    int                    encoding;

      
//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);
    }

//dapatkan durasi total mp3
    printf("Mencari durasi total...\n");
    off_t    sample_total;
    double    durasi_total;
    sample_total = mpg123_length(handle);
    durasi_total = (double)sample_total / (double)rate;
    printf("- Total sample: %d\n", (int)sample_total);
    printf("- Sample rate: %d\n", (int)rate);
    printf("- Durasi total: %f detik\n", durasi_total);
   
//coba seeking ke 0:20
    printf("Meloncat ke 0:20\n");
    off_t frame_baru;
    frame_baru = mpg123_timeframe(handle, 20);
    mpg123_seek_frame(handle, frame_baru, SEEK_SET);


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



Mengetahui Durasi MP3
Meskipun fungsi API yang disediakan libmpg123 sudah lengkap, rupanya tidak semua hal bisa dilakukan secara instan. Durasi MP3 tidak dapat diproses secara langsung hanya dengan memanfaatkan sebuah API. Walaupun begitu, libmpg123 mempunyai beberapa fungsi dapat dipadukan untuk memperoleh durasi MP3 yang tepat.

Ada sedikit tambahan info yang belum sempat saya bahas sebelumnya. Awalnya saya mengira proses dekoding MP3 dilakukan secara satu kali saja. Satu file langsung didekode seluruhya dan diletakkan di memori, baru setelah itu diputar dengan libao. Ternyata saya salah. Nyatanya dekoding dilakukan secara looping menghasilkan samples.

Potongan samples yang belum didekode disebut frame. Proses dekode yang kita lihat kemarin sebenarnya adalah proses ekstraksi data dari frame. Setelah saya teliti lagi, satu kali pemanggilan fungsi mpg123_read() akan mendekode data hingga sebanyak 16 frame. Pada dasarnya banyaknya frame yang didekode dalam sekali pemanggilan tergantung ukuran buffer yang disediakan. Seperti yang kita ketahui, ukuran buffer ditentukan dengan fungsi mpg123_outblock(), jadi kesimpulannya, mpg123_outblock() berfungsi memberi rekomendasi ukuran buffer optimum.

Kita sudah melihat pada tutorial sebelumnya, bahwa rate diperoleh dengan fungsi mpg123_getformat(). Pada tutorial ini, rate perlu saya jelaskan lebih detil. Karena berhubungan erat dengan proses pencarian durasi total MP3. Rate umumnya lebih sering disebut sebagai sample rate. Samples rate secara detail merupakan jumlah data samples yang dikirim ke audio device setiap satu detik. Jadi jika kita ingin mengetahui durasi total MP3, caranya adalah dengan mencari jumlah total samples pada mp3, lalu membaginya dengan sample rate, dan dari situ kita mendapatkan durasi total MP3 dalam detik.

Durasi = Total samples / Sample rate

Sample rate sudah kita peroleh dengan mpg123_getformat(). Sekarang bagaimana kita mencari jumlah samples total? Fungsi berikut ini adalah jawabannya...

off_t mpg123_length(mpg123_handle *mh);

Fungsi ini akan mencari dan mengembalikan nilai berupa jumlah sample total dari file MP3. Parameter yang diperlukan adalah sebuah handle dari file yang telah dibuka.

//dapatkan durasi total mp3
    printf("Mencari durasi total...\n");
    off_t    sample_total;
    double    durasi_total;
    sample_total = mpg123_length(handle);
    durasi_total = (double)sample_total / (double)rate;

    printf("- Total sample: %d\n", (int)sample_total);
    printf("- Sample rate: %d\n", (int)rate);
    printf("- Durasi total: %f detik\n", durasi_total);


NB: durasi sebaiknya disimpan dalam variabel pecahan tipe double. Durasi selalu dalam ukuran detik dan berupa bilangan pecahan. Misalnya diketahui durasi 258,12345; maka dapat diartikan 258 detik lebih 12345 milidetik.


Melakukan seeking
Salah satu hal dasar yang perlu diketahui program MP3, adalah mengetahui bagaimana melakukan navigasi ke durasi tertentu. Biasanya sebuah MP3 player dilengkapi dengan tombol navigasi berbentuk seperti progress bar. Kira-kira seperti itulah gambaran umum tentang seeking.

Libmpg123 mendukung beberapa metode seeking. Pertama, mpg123_seek(), untuk melakukan navigasi sample. Kedua, mpg123_feedseek(), khusus untuk navigasi frame pada input streaming dari internet. Kedua fungsi ini akan  kita bahas pada kesempatan lain. Sementara itu, tutorial ini hanya membahas fungsi seeking dengan mpg123_seek_frame(). Fungsi ini digunakan untuk melakukan navigasi ke frame lain. Setelah melakukan navigasi frame, maka ketika mpg123_read() dipanggil, posisi frame baru inilah yang akan didekode selanjutnya. Fungsi API untuk navigasi berdasarkan waktu/durasi tidak disediakan secara langsung, sebagai gantinya libmpg123 menyediakan fungsi mpg123_timeframe(). Fungsi ini berguna untuk mengetahui posisi frame yang berisi samples pada durasi yang diminta.

off_t mpg123_seek_frame(mpg123_handle *mh, off_t frameoff, int whence);

Fungsi diatas bekerja berdasarkan parameter ketiga (parameter whence). Parameter ini dapat diisi SEEK_SET, SEEK_CUR atau SEEK_END. Cara kerjanya sama seperti pengoperasian file pada pemrograman C. Jika whence=SEEK_SET, maka posisi frame baru diambil langsung dari parameter kedua(frameoff). Jika whence=SEEK_CUR, posisi frame baru adalah posisi frame sekarang ditambah parameter frameoff. Jika whence=SEEK_END, posisi frame merupakan frame-terakhir dikurangi parameter frameoff.

off_t mpg123_timeframe(mpg123_handle *mh, double sec);

Seperti biasanya, parameter pertama adalah handle. Sedangkan parameter kedua berupa waktu yang kita inginkan. Hasil fungsi ini meupakan index offset yang kita minta. Untuk menuju ke frame ini, kita menggunakan fungsi mpg123_seek_frame().

//coba seeking ke 0:20
    printf("Meloncat ke 0:20\n");

    off_t frame_baru;
    frame_baru = mpg123_timeframe(handle, 20);
    mpg123_seek_frame(handle, frame_baru, SEEK_SET);


Sekian tutorial kedua tentang MP3 player di Linux. Untuk tutorial selanjutnya kita akan mencoba menghitung time elapsed(durasi terlewat) dan time remaining(durasi tersisa) pada MP3 yang sedang diputar.

Jangan kawatir, setelah Anda tahu tutorial berikutnya, anda sudah bisa mengimplementasikan MP3 player dengan kemampuan Play, Pause dilengkapi kemampuan seeking(navigasi).

Rencananya saya juga menulis tutorial mencari ID3 Tag untuk mengetahui properti MP3, sampai perancangan MP3 player dengan GTK. So, jangan sampai ketinggalan update blog ini ;)

Like Fans Page-nya...
Load disqus comments

0 comments