Jumat, 09 Januari 2015

Membuat MP3 Player untuk Linux dengan C


Setelah cukup lama vakum dari dunia pemrograman, tiba-tiba saja timbul dari dalam diri saya untuk koding. Memang benar pemrograman itu walaupun sulit tetap mengasyikkan. Jadi, masalah mood dan semangat koding itu sama sekali tiak dipengaruhi oleh masalah kesulitan dalam koding, tapi, karena faktor X. Sampai sekarang saya belum tahu persis apa itu faktor X :3 #GJ #curhat

Anda pasti tanya, kenapa harus pakai C, buka C++, pascal, atau bahasa tingkat tinggi lainnya?

Saya tidak bisa menjawabnya. Entah kenapa saya suka yang susah-susah. Ya, walaupun sebagian besar yang saya buat susah itu selalu gagal. Tapi ini semua saya lakukan karena prinsip dan juga mencontoh oleh sosok-sosok yang saya idolakan. Tidak ada yang memuaskan jika kita meraih sesuatu itu dengan kemudahan. Itulah yang saya percaya. Lagipula saya belum pernah menemukan multimedia player populer yang ditulis dengan bahasa tingkat tinggi. Hehehe

Oke, langsung aja dah
Seperti judulnya, postingan ini akan menunjukkan cara membuat MP3 player sederhana dengan C.

libmpg123
Ini adalah library untuk membantu program melakukan decode file MP3. Sebelum program ini, XMMS juga sudah lebih dulu memakai library ini gan.
Alasan memilih libmpg123 adalah karena library ini multiplatform, jadi mudah jika agan berencana membuat port untuk Windows.
Untuk tutorial kali ini, saya pakai ubuntu, jadi jika anda tidak pakai Ubuntu, mohon sesuaikan sendiri ya. Coba mengunduh atau menelusurinya di google.
Tapi, jika ternyata ada yang suka postingan ini, nanti saya coba sertakan file-file yang dibutuhkan dalam postingan ini sekalian.
Untuk mendownload librarynya gunakan perintah :

sudo apt-get install libmpg123-0

Selain butuh librarynya, program ini juga perlu headernya agar bisa menggunakan fungsi yang disediakan library.

sudo apt-get install libmpg123-dev


Pengguna non-ubuntu bisa mengunjungi www.mpg123.de untuk informasi lebih lanjut.

libao
Sama halnya dengan libmpg123, libao ini juga saya pilih karena multiplatform. Fungsi libao beda ya. Libao adalah library yang menyediakan fungsi abstraksi untuk mengeluarkan suara pada berbagai macam audio device. Audio device yang didukung libao sangat lengkap, tapi, tentu saja itu tidak akan saya bahas disini.

Berikutnya, kita juga harus menginstall library dan headernya ya...

sudo apt-get install libao4
sudo apt-get install libao-dev



Proses Memutar MP3

Di atas tadi sudah saya kenalkan 2 library yang diperlukan untuk membuat pemutar MP3. Apa sih, kaitannya program yang kita buat dengan kedua library tadi?

Biarkan saya coba jelaskan. Singkatnya, libmpg123 bertugas membuka MP3 dan mendekodenya menjadi data yang dikenal audio device. Hasil dekode tadi tidak bisa langsung dikirim ke device oleh libmpg123, karena tugasnya memang hanya unduk mendekode. Mengirim kode ke device adalah tugas libao.

Berikut ini adalah mekanisme lengkapnya:

1. Inisialisasi libmpg123
1.1. Memanggil mpg123_init();
1.2. Memperoleh handle baru dengan mpg123_new()

2. Inisialisasi libao
2.1. Panggil ao_initialize()
2.2. Mengetahui ID audio driver default yang terhubung dengan ao_default_driver_id(). Driver ID diperlukan libao untuk menentukan audio device mana yang menjadi output saat memanggil fungsi ao_open_live().

3. Membuka dan menyiapkan MP3
3.1. Buka MP3 dengan mpg123_open()
3.2. Siapkan buffer dengan fungsi malloc. Buffer ini digunakan untuk menyimpan samples. Samples nilai dalam bentuk kode yang dipahami audio device untuk menghasilkan suara. Samples ini didapatkan dari proses decode MP3. Perlu diketahui musik yang terdengar di speaker merupakan deretan samples yang diterjemahkan oleh audio device. Ukuran satu buah samples ditentukan dengan mpg123_outblock();
3.3. Hubungkan libao dengan audio device dengan ao_open_live().

4. Dekode dan mainkan MP3
4.1. Gunakan mpg123_read() untuk mendekode MP3, sehingga dihasilkan samples demi samples.
4.2. Untuk setiap samples yang terbaca, kirimkan ke audio device untuk menghasilkan suara. Dalam hal ini libao menyediakan ao_play() untuk melakukannya.

5. Selesai
5.1. Panggil free() untuk membebaskan buffer
5.2. Tutup dan hapus handle dengan memanggil mpg123_close() disusul dengan memanggil mpg123_delete(). Proses ini pada dasarnya adalah menghapus memori yang dipakai untuk menyimpan informasi berkaitan dengan MP3 yang kita buka.
5.3. Hentikan library mpg123 dengan mpg123_exit(). Fungsi ini pada dasarnya adalah kebalikan dari mpg123_init()
5.4. Sama halnya dengan libmpg123, handle yang dibuat oleh libao juga harus ditutup. Lakukan dengan ao_close().
5.5. Panggil ao_shutdown() untuk menghentikan library.


Kode Pemutar MP3
#include <mpg123.h>
#include <ao/ao.h>

#define MP3_FILE "/home/irvan/test.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;
   
      
      
//inisialisasi MPG123
    printf("Komputoo MP3 player\nMembuka %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);
    }

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



Pembahasan

1. Inisialisasi libmpg123
Inisialisasi dilakukan dengan fungsi mpg123_init(). Pada tahap ini libmpg123 mengalokasikan resource serta mengolah konfigurasi untuk melakukan kerjanya secara garis besar.

int mpg123_init (void);

Fungsi mpg123_init() mengembalikan nilai 0 (MPG123_OK) jika tidak ditemukan kesalahan.

Sebelum membuka MP3, kita harus me-request sebuah handle kepada libmpg123. Handle berupa pointer ke structure

mpg123_handle* mpg123_new (const char * decoder, int *error)

Parameter decoder merupakan pointer ke string yang menunjukkan nama audio decoder yang dipilih. Parameter ini dapat diberi argumen 0, agar libmpg123 menentukan secara otomatis. Namun jika anda mau, anda bisa menggunakan fungsi mpg123_supported_decoders (). Fungsi ini mengembalikan pointer array string yang berisi deretan decoder yang didukung komputer anda.

const char** mpg123_supported_decoders (void)

Parameter kedua dapat dikosongi. Jika mau, anda bisa menyertakan sebuah variabel untuk menampung kode status error apabila terjadi kegagalan saat membuat handle. Kode tersebut dapat dengan mudah dideskripsikan dimana letak spesifik kesalahannya dengan fungsi mpg123_plain_strerror (). Fungsi ini mengembalikan string yang berisi keterangan error secara detail.

const char* mpg123_plain_strerror (int errcode);



2. Inisialisasi libao

Libao yang digunakan harus berjalan berdasarkan konfigurasi default. Proses pembacaan konfigurasi ini dilakukan saat sinyal inisialisasi dipanggil dengan API ao_initialize(). Konfigurasi untuk sekala umum ini disimpan pada “etc/libao.conf” dan ada pula konfigurasi lain untuk pengaturan spesifik setiap user yang disimpan pada folder “~/libao”.

void ao_initialize(void);

Setelah menginisialisasi libao, kita tidak dapat langsung terhubung dengan audio device. Karena beberapa komputer mungkin memiliki lebih dari satu audio device, libao mengharuskan kita untuk menentukannya terlebih dulu. Untuk melakukannya kita bisa menggunakan salah satu dari dua metode, yaitu dengan ao_default_driver_id() atau dengan ao_driver_id(). Fungsi ao_default_driver_id() memilihkan device secara otomatis, biasanya adalah device yang terpilih sebagai default device oleh sistem. Sementara itu fungsi ao_driver_id() mengizinkan kita untuk memilih driver secara spesifik berdasarkan nama uniknya. Info lebih lanjut: https://xiph.org/ao/doc/drivers.html

int ao_default_driver_id(char *short_name);

int ao_driver_id(char *short_name);


Pemanggilan fungsi diatas mengembalingan sebuah ID untuk driver yang terpilih. Nomor unik Driver ID adalah nilai yang diperlukan saat mengakses device, sehingga sebaiknya kita menyimpannya dalam sebuah variabel. Untuk memeriksa kesalahan, pastikan Driver ID yang dikembalikan dari pemanggilan fungsi bukan bernilai -1. Karena nilai ini merupakan indikasi terjadinya error.


3. Membuka dan menyiapkan MP3

Setelah libmpg123 siap dan sebuah handle sudah kita buat, maka libmpg123 sudah siap mendekode file MP3 yang kita inginkan.
Pertama-tama, pilih file MP3 dengan mpg123_open(). Parameter pertama merupakan handle yang telah dibuat dengan mpg123_new() dan parameter keduanya adalah nama file. Jika fungsi error, maka nilai yang dikembalikan merupakan bilangan acak selain 0.

int mpg123_open (mpg123_handle *mh, const char *path)

Ada satu beberapa hal lagi yang harus dipersiapkan sebelum mendekode MP3. Salah satunya yang paling penting adalah menyediakan memori(buffer) untuk menyimpan hasil dekode dalam bentuk samples. Ukuran relatif setiap 1 samples ini ditentukan dengan fungsi mpg123_outblock(). Alokasi memori dapat dilakukan dengan berbagai metode secara bebas, misalnya dengan fungsi malloc() yang disediakan C.

size_t mpg123_outblock(mpg123_handle *mh);

Tahap terakhir sebelum mendekode adalah menghubungkan libao dengan audio device serta mengatur output suara yang dihasilkan berdasakan pengaturan yang disimpan dalam MP3.

Pengaturan output tersebut diambil dari file dengan fungsi berikut:

int mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding);

Parameter pertama adalah handle. Parameter selanjutnya secara berurutan adalah pointer ke variabel-variabel untuk menyimpan rate, channel dan encoding. Rate merupakan kualitas suara yang dihasilkan dalam skala bps, artinya setiap detik ukuran data samples hasil dekode yang masuk ke audio device sebesar nilai rate. Channel adalah cara pengeluaran suara pada speaker, dapat berupa mono atau stereo. Terakhir adalah encoding. Encoding merupakan teknik pengorganisasian bilangan biner yang diterapkan pada MP3. Karena yang ini tiak terlalu ada kaitannya dengan tema kita hari ini, maka tidak perlu kita bahas.

Informasi yang telah kita ambil dari file MP3 selanjutnya kita kirimkan pengaturanya pada libao. Fungsi yang digunakan adalah ao_open_live().

ao_device* ao_open_live(int driver_id, ao_sample_format *format, ao_option *option);

Parameter pertama merupakan driver id yang telah kita peroleh pada tahap jauh sebelumnya. Parameter kedua adalah pointer ke structure ao_sample format. Struktur data inilah yang menyimpan informasi output. Fungsi ini mengembalikan handle yang diperlukan dalam pemutaran samples, jadi harus disimpan sampai pemutaran selesai.

typedef struct {
  int  bits; /* bits per sample */
  int  rate; /* samples per second (in a single channel) */
  int  channels; /* number of audio channels */
  int  byte_format; /* Byte ordering in sample */
  char *matrix; /* channel input matrix */
} ao_sample_format;


  • bits diperoleh dengan memanggil fungsi mpg123_encsize() dengan parameter jenis encoding yang telah diperoleh sebelumnya. Lalu kalikan hasilnya dengan 8. Angka 8 itu sendiri adalah jumlah bit dalam 1 byte.
  • rate dan channel ditentukan dari mpg123_getformat yang juga telah dilakukan sebelumnya.
  • byte_format tidak jauh berbeda dengan encoding. Byte_format menentukan teknik pengorganisasian angka digital yang digunakan oleh komputer kita(bukan oleh MP3).
  • matrix lebih baik dikosongi. Kunjungi link ini untuk info lebih lanjut https://xiph.org/ao/doc/ao_sample_format.html.

Dan, parameter terakhir dapat kita isikan secara opsional untuk memberikan instruksi spesial pada audio driver. Nilai ini sebaiknya dikosongi saja. Jika ingin mempelajari lebih jauh, kunjungi link berikut, https://xiph.org/ao/doc/drivers.html.


4. Dekode dan Memutar MP3
Proses dekode secara sederhana dapat dilakukan dengan fungsi mpg123_read(). Hasil pembacaan berupa sebuah samples yang siap dibaca audio device. Setiap pembacan satu samples, kita mengirimkan kode samples tersebut dengan fungsi ao_play(). Berikut ini adalah keterkaitan antara kedua fungsi.

    size_t ukuran_samples;
    while(mpg123_read(handle, buffer, ukuran_buffer, &ukuran_samples) == 0)
    {
        ao_play(device, buffer, ukuran_samples);
    }

Fungsi mpg123_read() menggunakan parameter pertama sebagai handle mp3 yang telah dibuka. Parameter kedua dan ketiga adalah pointer ke buffer serta ukuran buffer. Parameter terakhir merupakan pointer ke sebuah variabel yang menyimpan ukuran samples hasil pembacaan. Fungsi ini akan mengembalikan nilai 0 saat sukses, jika nilai yang dikembalikan adalah MPG123_DONE (-12), artinya samples yang dibaca itu adalah samples terakhir (akhir dari MP3).

Fungsi ao_play() mengirimkan samples ke audio device. Device yang dituju ditentukan oleh parameter pertama. Nilainya sudah kita peroleh dari pemanggilan ao_open_live(), parameter kedua adalah buffer yang menyimpan sebuah samples yang baru saja didekode dan diikuti parameter terakhir yang berupa ukuran samples.




 

5. Selesai
Setelah selesai, program sebaiknya menutup dan menghapus semua handle yang telah dibuat. Karena library sudah tak diperlukan lagi, maka library juga perlu di-uninisialisasi. Berikut adalah fungsi-fungsi yang dimaksud. Untuk penjelasannya baca ulang bagian paling atas.

int mpg123_close(mpg123_handle *mh);

void mpg123_delete(mpg123_handle *mh);

void mpg123_exit(void);

int ao_close(ao_device *device);

void ao_shutdown(void);




Kompilasi
gcc mp3play.c -o mp3play -l ao -l mpg123


Yep, demikian. Saya cape ngetik :p
Untuk tutorial selanjutnya, tentang seeking, pengaturan volume, dan lainnya akan dibahas pada tutorial selanjutnya.
Load disqus comments

0 comments