Jumat, 19 Desember 2014

my life my faith my freedom

semua orang pasti berubah my man,
dulu gw berjalan dipinggiran sepertinya jalan tersebut bukan milik gw
menjadi pemberani tanpa pertimbangan
menjadi pengecut tanpa kesempatan
menjadi bodoh tanpa pengetahuan
menjadi pendusta pada semuanya
selalu bersembunyi dibalik kenyataan hidup
seperti seorang penakut gw lari terbirit birit dari setiap persimpangan yang harusnya gw sebrangi
sering malah gw terjun bebas ke jurang yg seharusnya gw putari saja.


meminjam tubuh orang lain adalah salah satu kebiasaan...
menjadi diri mereka adalah lebih baik... begitu dulu gw pikir...
mengingkari diri sendiri adalah jiwa yang terus berdetak...


pada suatu saat...
sampailah gw ditepian...
kelelahan,... capai,... dan muak...
tetap gw berdiri...
gw tampar mata dewa yang waktu itu mau masuk kedalam selimutnya...


 bunyi riak air yang membelai telapak kaki gw bicara...
"sekarang apa lagi yang kau mau..."
"siapakah dirimu..."
"apakah kehendakmu..."
"dimanakah tujuanmu..."
"meskipun kau jungkir balikkan dunia... kamu belum merdeka..."
"dan sekalipun kamu diam saja... kamu tetap tidak merdeka..."
"menghilang dan hadirmu sama saja artinya toh..."
"kamu bukan siapa siapa..."
"kamu ingkari atau kamu akui... itu sama saja"
"kamu bukan apa apa..."
"keberhasilan dan kegagalan..."
"pertemuan dan perjumpaan..."
"memiliki dan meratapi..."
"adalah sama nikmatnya..."

"ada dan tiada ... tidak akan pernah kamu ketahui..."
"jadi kamu mau apa lagi..."


terhempas gw penuh amarah...
riak air yang tidak berdosa...
buih asin yang begitu pengasih...
bulir pasir putih menyayangi gw...
semua mengurung tubuh telanjang gw...


dengan jiwa yang terbakar .... gw teriak...
"lalu untuk apa semua ini..."
gw pukul keras semuanya yang tidak berdosa, yang pengasih dan menyayangi gw...


dengan sisa tenaga... gw bangun... terduduk meringkuk telanjang dalam kegelapan...


Aku menyerah... kepada yang mengasihiku dan menyayangiku...
Ampunilah aku...
Aku...
Menyerah...





Senin, 17 Februari 2014

menempelkan source code ke blog dengan gist.github.com...

Banyak  alternative untuk menampilkan source code dalam format seperti dalam editor visual studio atau codeblock atau editor lainnya kedalam blog.

Salah satunya dengan memanfaatkan gist.github.com.
caranya:
1. buat akun di github
2. panggil  gist.github.com
3. paste source code kedalam kotak input / editor yang disediakan.
4. setelah pem-formatan dilakukan oleh gist, lihat ke bagian embed this gists, copy isinya.


 5. paste ke dalam HTML mode saat mengedit blog kita.



ini contohnya:

Sabtu, 04 Januari 2014

Console base Mp3 player(code::block + libao + mpg123 + multi object file)

Console base Mp3 player(code::block + libao + mpg123 + multi object file)
Pada artikel[libao + libmpg123 mingw gcc + code block sample...] yang merupakan revisi dari artikel[libao + libmpg123 visual studio 2013 sample...] telah dibahas mengenai contoh penggunaan library libao dan mpg123 untuk memutar file.mp3.hasil kompilasi dari kedua artikel tersebut dapat digunakan secara command line dengan menyertakan nama file.mp3 sebagai argument masukan command line tersebut, misalnya:

Testplay.exe r_william_advertising_space.mp3

Perintah tersebut akan memutar file r_william_advertising_space.mp3.
Ngulik - ngulik berlanjut, bagaimana jika kita ingin menjalankan banyak file.mp3 dalam satu folder, biasanya kita akan memanggil wildcard argument *.mp3 sebagai masukan testplay.exe.namun ketika dilakukan ternyata testplay.exe hanya akan mengenal satu masukan saja.
Nah sehubungan dengan bahasan artikel[bekerja dengan banyak file.cpp] kita akan mencoba untuk merekayasa source code tersebut agar dapat bekerja dengan argumen wildcard *.mp3 dan kita coba juga untuk memecah source code menjadi banyak file.cpp.ini akan kita lakukan dengan menggunakan code::block C++ IDE dan mingw gcc.

Source code aslinya adalah diambil dari[revisi:libao + libmpg123 mingw gcc + code block sample..] :
#include <mpg123.h>
#include <ao/ao.h>
#include <malloc.h>
#include <stdlib.h>
#include <windows.h>

#define BITS 8

int main(int argc, char *argv[])
{
    mpg123_handle *mh;
    unsigned char *buffer;
    size_t buffer_size;
    size_t done;
    int err, driver, channels, encoding;
    ao_device *dev;
    ao_sample_format format;
    long rate;
    ao_initialize();
    driver = ao_default_driver_id();

    // ========= inisial library =============

    mpg123_init();
    mh = mpg123_new(NULL, &err);
    buffer_size = mpg123_outblock(mh);
    buffer = (unsigned char*)malloc(buffer_size * sizeof(unsigned char));
    mpg123_param(mh, MPG123_RESYNC_LIMIT, -1, 0);
    char* filename = argv[1];
    mpg123_open(mh, filename);
    mpg123_getformat(mh, &rate, &channels, &encoding);

    // ************************************ 

    format.bits = mpg123_encsize(encoding) * BITS;
    format.rate = rate;
    format.channels = channels;
    format.byte_format = AO_FMT_NATIVE;
    format.matrix = 0;
    double secs;
    dev = ao_open_live(driver, &format, NULL);

    while (mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK)
    {
        ao_play(dev, buffer, done);
        fprintf(stderr, "Frame: %li\n", mpg123_tellframe(mh));
        mpg123_position(mh, 0, 0, NULL, NULL, &secs, NULL);
        fprintf(stderr, "[%d:%02d] Decoding of %s finished.\n", (int)(secs / 60), ((int)secs) % 60, filename);
    }

    /* clean up */

    free(buffer);
    ao_close(dev);
    mpg123_close(mh);
    mpg123_delete(mh);
    mpg123_exit();
    ao_shutdown();

    return 0;
}


Selain source code tersebut kita menggunakan source code tentang argument parsing yang dapat diperoleh di http ://www.cplusplus.com/forum/beginner/26251/ cari bagian m4ster r0shi tentang class CLPARSER. Berikut source code clparser tersebut.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
using namespace std;

class CLParser
{
public:
 
    CLParser(int argc_, char * argv_[], bool switches_on_ = false);
    ~CLParser(){}

    string get_arg(int i);
    string get_arg(string s);
private:

    int argc;
    vector<string> argv;
    bool switches_on;
    map<string, string> switch_map;
};

CLParser::CLParser(int argc_, char * argv_[], bool switches_on_)
{
    argc = argc_;
    argv.resize(argc);
    copy(argv_, argv_ + argc, argv.begin());
    switches_on = switches_on_;

    //map the switches to the actual
    //arguments if necessary
     if (switches_on)
    {
        vector<string>::iterator it1, it2;
        it1 = argv.begin();
        it2 = it1 + 1;

        while (true)
        {
            if (it1 == argv.end()) break;
            if (it2 == argv.end()) break;
            if ((*it1)[0] == '-')
                switch_map[*it1] = *(it2);
            it1++;
            it2++;
        }
    }
}

string CLParser::get_arg(int i)
{
    if (i >= 0 && i<argc)
        return argv[i];
    return "";
}

string CLParser::get_arg(string s)
{
    if (!switches_on) return "";
    if (switch_map.find(s) != switch_map.end())
        return switch_map[s];
    return "";
}

//////////////////////////////////////////////////////////////

int main(int argc, char * argv[])
{
    CLParser cmd_line(argc, argv, true);
    cout << "printing the whole arg list...\n" << endl;
    for (int i = 0; i<argc; i++)
        cout << cmd_line.get_arg(i) << endl;
    cout << "\nprinting the switch values...\n" << endl;

    string temp;
    temp = cmd_line.get_arg("-a");
    if (temp != "") cout << temp << endl;
    temp = cmd_line.get_arg("-b");
    if (temp != "") cout << temp << endl;
    temp = cmd_line.get_arg("-c");
    if (temp != "") cout << temp << endl;

    cout << "\nhit enter to quit";
    cin.get();
    return 0;
}

Dan tentu saja library libao dan libmpg123 serta code::block.
Oke kita mulai saja prosedurnya, harap diingat source code ini nanti akan menjadi dipecah - pecah untuk mendapatkan fakta sebenarnya tentang bekerja dengan banyak file object / file.cpp.


Pertama, mari kita buat folder untuk project kita ini misalnya di C : \myproj dan untuk projectnya sendiri diberi nama testmpgao.cbp.


Kemudian copy file developer(include, dan lib) libao dan libmpg123 kedalam folder tersebut :


Ilustrasi diatas menggambarkan didalam folder myproj terdapat folder libao - 1.1.0src dan folder mpg123src yang mana adalah working directory sewaktu mengkompilasi source code kedua library terebut, hasil kompilasi kedua library tersebut adalah libao.dll dan libao.dll.a yang tersimpan didalam folder libao - 1.1.0src / src / .libs dan file header untuk libao terdapat di folder libao - 1.1.0src / include.Sedangkan hasil kompilasi mpg123src menghasilkan folder tmp - mpg123 - 1.17.0 - static - x86 yang didalamnya terdapat folder include dan lib.

Sekarang mari kita buka code::block editor, click pada icon folder create new project, pilih empty project dan click tombol Go.Click tombol next pada dialog berikutnya dan arahkan project folder ke myproj, dan beri nama project dengan testmpgao misalnya.





Click ok pada dialog browse for folder dan click tombol Next pada dialog empty project.Dialog selanjutnya pilih GNU GCC Compiler dan biarkan sisanya sebagai default, click tombol finish.



Nah sekarang kita sudah memiliki project baru yang masih kosong tentunya.


Langkah kedua adalah menyesuaikan environtment compiler dan linker project tersebut agar dapat menggunakan library libao dan libmpg123.Click pada menu project, pilih build option, pada dialog project build option silahkan click sub tree Release pada kolom kanan dan click tab Linker settings.



Click tombol add dan browse kepada :
C : \myproj\mpg123src\tmp - mpg123 - 1.17.0 - static - x86\lib\libmpg123.a
C : \myproj\libao - 1.1.0src\src\.libs\libao.dll.a


Kemudian click tab Search Directory dan pada tab compiler click tombol add dan masukkan folder include kedua library tersebut :


Click pada tab Linker dan masukkan folder lib kedua library tersebut :


Click tombol OK untuk kembali ke main windows code::block.

Nah sekarang environtment code::block sudah siap untuk digunakan oleh kita, mari kita mulai untuk melakukan pengulikan source code.Click pada tombol new file dan pilih empty file.Beri nama argvcl.cpp dan click save dan OK.Maka akan terdapat lembar source code yang masih kosong.



Silahkan copy - paste source code CLPARSER kepada argvcl.cpp tersebut.Dan karena kita hanya membutuhkan class CLParser maka baris int main(){ …. } kita hapus atau diberi block comentar /* sebelum int main(){…} dan */ setelah baris terakhir int main(){ … } tersebut.Simpan argvcl.cpp tersebut.

Harap di ingat bahwa kita bertujuan untuk mencoba memecah file source code menjadi lebih dari satu object file.cpp.jadi jika source code argvcl.cpp tersebut akan dipecah, maka kita pisahkan deklarasi class terhadap definisi class CLParser tersebut.
Dalam hal ini yang merupakan deklarasi CLParser adalah :
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
using namespace std;

    class CLParser
    {
    public:
        CLParser(int argc_, char * argv_[], bool switches_on_ = false);
        ~CLParser(){}
        string get_arg(int i);
        string get_arg(string s);
    private:
        int argc;
        vector<string> argv;
        bool switches_on;
        map<string, string> switch_map;
    };
Sedangkan baris berikut dibawahnya adalah definisi dari fungsi - fungsi didalam class CLParser tersebut.Buat satu new empty file lagi dan beri nama dengan argvcl.hpp dan lakukan cut – paste baris deklarasi tersebut ke file argvcl.hpp. Tambahkan baris #include yang merujuk ke file argvcl.hpp diawal source code argvcl.cpp.sehingga saat ini file argvcl.cpp menjadi:
//----file:argvcl.cpp

#include <argvcl.hpp>
using namespace std;
    CLParser::CLParser(int argc_, char * argv_[], bool switches_on_)
    {
        argc = argc_;
        argv.resize(argc);
        copy(argv_, argv_ + argc, argv.begin());
        switches_on = switches_on_;

        //map the switches to the actual
        //arguments if necessary
        if (switches_on)
        {
            vector<string>::iterator it1, it2;
            it1 = argv.begin();
            it2 = it1 + 1;

            while (true)
            {
                if (it1 == argv.end()) break;
                if (it2 == argv.end()) break;
                if ((*it1)[0] == '-')
                    switch_map[*it1] = *(it2);
                it1++;
                it2++;
            }
        }
    }

    string CLParser::get_arg(int i)
    {
        if (i >= 0 && i<argc)
            return argv[i];
        return "";
    }

    string CLParser::get_arg(string s)
    {
        if (!switches_on) return "";
        if (switch_map.find(s) != switch_map.end())
            return switch_map[s];
        return "";
    }
Sedangkan isi file argvcl.hpp adalah sebagai berikut :
//-----file: argvcl.hpp
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
    using namespace std;

    class CLParser
    {
    public:
        CLParser(int argc_, char * argv_[], bool switches_on_ = false);
        ~CLParser(){}

        string get_arg(int i);
        string get_arg(string s);
    private:
        int argc;
        vector<string> argv;
        bool switches_on;
        map<string, string> switch_map;
    };
Nah, sampai disini kita telah mempunyai dua file dalam code::block project.


Selanjutnya mari kita oprek source code player kita, dalam hal ini source code player akan kita letakkan tidak dalam int main(){ … } lagi melainkan kita jadikan fungsi int fplay() dalam file fplay.cpp, dan kelak fplay akan menjadi object kompilasi tersendiri dan memanggil fungsi fplay dapat dilakukan melalui header file fplay.hpp.

Buat lagi satu new empty file, beri nama fplay.cpp dan copy – paste source code player kepadanya.
//------file: fplay.cpp

#include <mpg123.h>
#include <ao/ao.h>
#include <malloc.h>
#include <stdlib.h>
#include <windows.h>
#include <fplay.hpp>
#define BITS 8

    int fplay(char* filename)
    {
            mpg123_handle *mh;
            unsigned char *buffer;
            size_t buffer_size;
            size_t done;
            int err, driver, channels, encoding;
            ao_device *dev;
            ao_sample_format format;
            long rate;
            ao_initialize();
            driver = ao_default_driver_id();

            mpg123_init();
            mh = mpg123_new(NULL, &err);
            buffer_size = mpg123_outblock(mh);
            buffer = (unsigned char*)malloc(buffer_size * sizeof(unsigned char));
            mpg123_param(mh, MPG123_RESYNC_LIMIT, -1, 0);
            mpg123_open(mh, filename);
            mpg123_getformat(mh, &rate, &channels, &encoding);

            // ************************************

            format.bits = mpg123_encsize(encoding) * BITS;
            format.rate = rate;
            format.channels = channels;
            format.byte_format = AO_FMT_NATIVE;
            format.matrix = 0;

            double secs;
            dev = ao_open_live(driver, &format, NULL);

            while (mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK)
            {
                ao_play(dev, buffer, done);
            }
            free(buffer);
            ao_close(dev);
            mpg123_close(mh);
            mpg123_delete(mh);
            mpg123_exit();
            ao_shutdown();
        }

Fungsi int fplay() akan dapat menerima argument yang akan disimpan ke filename yang merupakan pointer dari char.Variable filename tersebut akan digunakan oleh mpg123_open(mh, filename);.jangan lupa memberi directives #include <fplay.hpp> kedalam source code fplay.cpp.
Nah kelak fungsi dalam file fplay.cpp dapat dipanggil oleh source code lain dengan menggunakan file header fplay.hpp.mari kita buat satu file new epty file lagi, dan beri nama fplay.hpp.
Isi dari file fplay.hpp adalah :
//----file: fplay.hpp

int fplay(char* filename);

itulah bagian deklarasi dari fungsi fplay().Simpan keseluruhan project.
Nah sekarang tinggal membuat file utama yang berisi int main(){ … } untuk menjalankan object CLParser dan fplay.Sekali lagi buat new empty file dan beri nama playermain.cpp misalnya.
Isi dari playermain.cpp adalah :
//----file: playermain.cpp

#include <stdlib.h>
#include <windows.h>
#include <argvcl.hpp>
#include <fplay.hpp>
#include <stdio.h>

#define BITS 8

    int main(int argc, char *argv[])
    {
        CLParser cmd_line(argc, argv, true);
        if (argv[1] != NULL)
        {
            cout << "printing the whole arg list...\n" << endl;
            for (int q = 0; q<argc; q++)
            if (q != 0)
                cout << cmd_line.get_arg(q) << endl << endl;
            cout << "\nhit enter to start play";
            cin.get();

            for (int i = 0; i<argc; i++)
            {
                char *cstr = new char[cmd_line.get_arg(i).length() + 1];
                strcpy(cstr, cmd_line.get_arg(i).c_str());
                char* filename = cstr;//argv[1];
                if (filename != cmd_line.get_arg(0))
                    fplay(filename);
                delete[] cstr;
            }
        }
        else
        {
            char* filename = "The crystal - Sejenak.mp3";
            fprintf(stderr, "nofile input\nplaying default mp3 file:\n %s", filename);
            fplay(filename);
        }

        return 0;
    }

directives  #include <argvcl.hpp>  dan #include <fplay.hpp> akan mereferensikan fungsi-fungsi dari object argvcl dan fplay kepada playermain.cpp.

Jadi saat ini akan terdapat 3 file source code.cpp dan dua file header didalam project testmpgao.



Kelak jika telah dikompilasi project akan menghasilkan 3 file obj dan setelah dilinker akan menghasilkan 1 file executable testmpgao.exe yang tersimpan di folder bin / release.dapat dieksekusi dengan menggunakan wildcard argument.


testmpgao.exe *.mp3

dan jika tidak diberikan argument maka bagian :

else
{
    char* filename = "The crystal - Sejenak.mp3";
    fprintf(stderr, "nofile input\nplaying default mp3 file:\n %s", filename);
    fplay(filename);
}

Akan dijalankan.Nah jika telah dikompilasi tetap akan dibutuhkan shared library - file: libao - 4.dll, libgcc_s_dw2 - 1.dll, dan file libstdc++ - 6.dll sedangkan untuk libmpg123 telah dikompilasi dengan cara static jadi tidak perlu dicopykan libmpg123.dll.




Screenshoot testmpgao.exe *.mp3



thank's if you have any comment and or question on this article please let me know...

Kamis, 02 Januari 2014

Bekerja dengan banyak file cpp...

Bekerja dengan banyak file .cpp (multiple source code)

Bagaimana cara terbaik untuk membuat program yang besar, program yang kecil memudahkan kita untuk memahami cara kerjanya, alurnya, object-object didalamnya, dan lain-lain, sedangkan program yang besar akan lebih sulit untuk memahaminya. Oleh karena itu untuk membuat program yang besar diperlukan teknik agar memudahkan struktur program tersebut dan agar program tersebut mudah di pahami.

1.    Memecah Program menjadi bagian-bagian kecil
Dengan berkembangnya program kita menjadi besar, kita tentu tidak ingin keseluruhan program tersebut ditulis didalam satu file source code, hal itu Akan menyulitkan ketika ada perubahan didalam source kode. Ketika program kita sudah mencapai beberapa ribu baris, sudah selayaknya kita harus memecah program tersebut menjadi beberapa source code.

Pecahan source code tersebut dapat berarti setiap bagian file akan memiliki fungsi-fungsinya masing-masing sesuai peruntukkannya dan dapat saling dihubungkan satu sama lainnya. Hubungan diantara source code yang terpisah tersebut dilakukan hanya melalui file header dari masing-masing source code tersebut. Ini berarti setiap source code pada dasarnya adalah object yang berdiri sendiri dan siap untuk dieksekusi oleh object lainnya, hanya saja untuk mengeksekusi object yang berbeda diperlukan interface mengenai apa saja fungsi-fungsi yang tersedia didalam masing-masing object tersebut, interface tersebut adalah file header dari masing-masing object.

1.1.    Memahami proses Build C++
Sebelum kita memecah source code, ada baiknya kita memahami bagaimana dasar kompilasi didalam C++. Kenyataanya, compiling tidak menghasilkan file executable. Untuk menghasilkan file executable merupakan suatu proses yang bertingkat, tingkat yang penting adalah preprocessing, compilation, dan linking. Secara keseluruhan proses menghasilkan file executable dari source code akan dikatakan sebagai proses build.

1.1.1.    Preprocessing
Langkah awal dari proses build adalah saat compiler menjalankan C preprocessor. Yang berfungsi untuk melakukan perubahan textual terhadap file sebelum langkah kompilasi selanjutnya. Preprocessor ini mengenal tanda-tanda preprocessor directives didalam source code tanda tersebut adalah symbol pound/pagar (#). Dilain pihak compiler sendiri tidak mengenali tanda directives tersebut. Contoh statementnya seperti ini:

#include <iostream>

Perintah diatas akan menyuruh preprocessor untuk mencuplik isi dari file iostream.h dan seolah-olah menempelkannya secara langsung pada posisi #include <iostream> didalam file. Dan selanjutnya compiler akan dapat membaca baris kode tempelan ini.

Preprocessor juga berguna untuk menempelkan macro. Macro adalah string berbentuk text yang di-replace oleh preprocessor. Dengan macro kita dapat membuat banyak constanta didalam satu titik central saja, sehingga akan memudahkan kita untuk mengubah-ubah nilai constanta-constanta tersebut. Contohnya:

#define MY_NAME "Kuda Liar"

Kita cukup menggunakan MY_NAME saja ketimbang menggunakan "Kuda Liar" didalam file source code. Misalnya:

cout << "Hello " << MY_NAME << '\n';

dalam statement diatas, compiler akan melihatnya sebagai:

cout << "Hello " << "Alex" << '\n';

contoh lainnya:

#define VERSION 4

// ...

cout << "The version is " << VERSION

Nah, disebabkan oleh karena preprocessor bekerja sebelum compiler memproses source code, ia juga dapat digunakan untuk melakukan penghapusan baris statement didalam source code. Ini berguna saat kita misalnya perlu mengkompilasi beberapa baris code saja saat melakukan build dalam mode debug. Kita dapat melakukan ini dengan menyatakan kepada preprocessor untuk men-sisipkan baris kode jika macro telah terdefinisi. Contohnya:

#include <iostream>

#define DEBUG             //deklarasi macro 

     using namespace std;

int main ()

{

    int x;

    int y;

    cout << "Enter value for x: ";

    cin >> x;

    cout << "Enter value for y: ";

    cin >> y;

    x *= y;

#ifdef DEBUG        //jika kondisi kompilasi = DEBUG = true maka perintah cout disembunyikan

    cout << "Variable x: " << x << '\n' << "Variable y: " << y;

#endif

//

}

Kita akan bahas lebih lanjut mengenai macro saat kita membahas penggunaan multiple header file.

1.1.2.    Compilation
Compilasi bertujuan merubah source code (file .cpp) menjadi suatu object file (.o atau .obj). Suatu object file berisikan program kita dalam bentuk yang dapat dipahami oleh processor computer – machine language instruction -  untuk setiap fungsi didalam source code kita. Jadi satu file .cpp akan menghasilkan satu file object, nah jika didalam suatu project program terdapat lebih dari satu file .cpp, maka compilasi nya juga akan menghasilkan lebih dari satu file obj.

1.1.3.    Linking
Hasil dari compiler – obj file belum dapat dieksekusi oleh pengguna, tujuan dari melakukan linking adalah membuat satu file yang bisa dieksekusi lepas dari object file dan library-nya.
Linker akan membuat satu file dalam bentuk yang dapat dieksekusi dan men-transfer content dari individual object file menjadi bisa dieksekusi (.exe / .dll). Linker juga mem-perantarai suatu object file yang mempunyai / memanggil fungsi-fungsi yang definisinya me-refferensi dari object lainnya diluar object originalnya. Contohnya: untuk setiap fungsi yang merupakan bagian dari C++ Standar Library, maka berarti kita sedang memanggil fungsi yang tidak terdefinisi didalam source code kita, melainkan fungsi tersebut ada di pustaka C++ yang kita #include (ingat bagian preprocessor) kan file headernya kedalam source code kita. Pustaka standar C++ itu sendiri adalah object file yang sudah jadi dan tersedia dalam bentuk file .dll contohnya libgcc_s_dw2-1.dll.
Ini menunjukkan bahwa jika kita membuat lebih dari satu file .cpp, maka jika source code kita memanggil fungsi-fungsi yang terdapat pada file .cpp lain akan dibutuhkan definisi fungsi tersebut dalam bentuk file header .hpp / .h, dan kelak saat kompilasi setiap file .cpp akan menjadi file .o / .obj sendiri-sendiri. Kesemua file .o / obj tersebut dapat disatukan menjadi satu object tunggal oleh linker.

2.    Mengapa kita butuh kompilasi dan linking yang terpisah-pisah?
Dikarenakan tidak setiap fungsi yang ada harus didefinisikan dalam satu file object, adalah memungkinkan untuk melakukan kompilasi terhadap satu file source code, dan kelak dapat dilakukan link menjadi satu. Jika kita merubah satu file .cpp, tapi tidak merubah file .cpp yang lainnya maka compilasi cukup dilakukan terhadap file .cpp yang dirubah saja, sedang lainnya tidak perlu.

2.1.    Bagaimana memecah program menjadi banyak file
Jadi bagaimana kita men-strukturkan kode kita kedalam kompilasi yang terpisah-pisah? Mari kita pelajari contoh sederhana tentang satu program, asli.cpp, yang mana kita ingin menggunakannya didalam program yang lainnya.
Langkah 1: Pisahkan deklarasi dan definsi (Splitting our declarations and definitions)
Berikut ini contoh source code asli.cpp sebelum dipisahkan.

//===== asli.cpp

#include <iostream>

using namespace std;

struct Node

{

    Node *p_next;

    int value;

};



Node* addNode (Node* p_list, int value)

{

    Node *p_new_node = new Node;

    p_new_node->value = value;

    p_new_node->p_next = p_list;

    return p_new_node;

}

void printList (const Node* p_list)

{

    const Node* p_cur_node = p_list;

    while ( p_cur_node != NULL )

    {

        cout << p_cur_node->value << endl;

        p_cur_node = p_cur_node->p_next;

    }

}

int main ()

{

    Node *p_list = NULL;

    for ( int i = 0; i < 10; ++i )

    {

        int value;

        cout << "Enter value for list node: ";

        cin >> value;

        p_list = addNode( p_list, value );

    }

    printList( p_list );

}

mari kita perhatikan bagian Node* dan printList yang merupakan fungsi dalam source code asli.cpp, Node* dideklarasikan dengan:

Node* addNode (Node* p_list, int value)


Sedangkan definisi Node* adalah:
{

    Node *p_new_node = new Node;

    p_new_node->value = value;

    p_new_node->p_next = p_list;

    return p_new_node;

}

Dan PrintList dideklarasikan dengan:
void printList (const Node* p_list)

Sedangkan definisi printList adalah:
{

    const Node* p_cur_node = p_list;

    while ( p_cur_node != NULL )

    {

        cout << p_cur_node->value << endl;

        p_cur_node = p_cur_node->p_next;

    }

}

Dengan demikian maka yang merupakan bagian deklarasi adalah:

struct Node {Node *p_next; int value;};
Node* addNode (Node* p_list, int value);
void printList (const Node* p_list);

Mari kita letakkan bagian deklarasi tersebut dalam file extobj.h

//========== extobj.h
struct Node {Node *p_next; int value;};
Node* addNode (Node* p_list, int value);
void printList (const Node* p_list);

Sedangkan baik deklarasi dan definisi dari kedua fungsi tersebut kita letakkan didalam file extobj.cpp

//======== extobj.cpp
#include <iostream>
#include "extobj.h"
using namespace std;
Node* addNode (Node* p_list, int value)
{
    Node *p_new_node = new Node;
    p_new_node->value = value;
    p_new_node->p_next = p_list;
    return p_new_node;
}
void printList (const Node* p_list)
{
    const Node* p_cur_node = p_list;
    while ( p_cur_node != NULL )
    {
        cout << p_cur_node->value << endl;
        p_cur_node = p_cur_node->p_next;
    }
}

Nah dengan adanya kedua file tersebut file extobj.h dan extobj.cpp, maka file asli.cpp cukup melakukan directive #include saja kepada file extobj.h dan selanjutnya bagian int main() dapat menggunakan fungsi-fungsi yang ada didalam file extobj.cpp.

//=========asli.cpp
#include <iostream>
#include "extobj.h"
using namespace std;
int main ()
{
    Node *p_list = NULL;
    for ( int i = 0; i < 10; ++i )
    {
        int value;
        cout << "Enter value for list node: ";
        cin >> value;
        p_list = addNode( p_list, value );
    }
    printList( p_list );

}

Senin, 30 Desember 2013

revisi: libao + libmpg123 mingw gcc + code block sample...

Pada artikel sebelumnya saya telah memberikan code sumber untuk memainkan file mp3 dengan menggunakan library dari libmpg123 dan libao. kode sumber tersebut adalah oprekan dari visual studio 2013. disana menggunakan fungsi reinterpret_cast &lt;char*&gt;(buffer) sebagai casting type data yang berbeda antara keluaran libmpg123 (unsigned char) dengan masukan libao (char). Nah ternyata fungsi reinterpret_cast&lt;&gt;() tersebut tidak dapat berjalan di gcc. Jadi ngulik-ngulik terus berlanjut agar ide tersebut dapat berjalan dilingkungan mingw gcc. ulikan dilakukan dengan menggunakan codeblok sebuah ide c++ dari lingkungan open source. Berikut cuplikan kode sumber yang terdahulu.
Code: play.cpp
while (mpg123_read(mh, buffer, buffer_size, &amp;done) == MPG123_OK)
{
ao_play(dev, reinterpret_cast&lt;char*&gt;(buffer), done);
fprintf(stderr, "Frame: %li\n", mpg123_tellframe(mh));
}
//===========reinterpret_cast&lt;char*&gt;(buffer) : digunakan untuk mengkonversikan type buffer unsigned char menjadi char.



cuplikan kode tersebut jika dikompilasi menggunakan mingw gcc akan error, karena gcc tidak mengenal fungsi reinterpret_cast tersebut.

jika diinginkan dapat dicari cara lain untuk melakukan type casting dari unsigned char menjadi char, namun setelah fungsi ao_play() dioprek langsung dari kode sumber libao, maka kita dapat merubah type data char yang digunakan menjadi unsigned char, sehingga tidak perlu melakukan terlalu banyak effort.

berikut ini prosedurnya:
1. extract kode sumber libao (<a href="http://downloads.xiph.org/releases/ao/libao-1.1.0.zip">http://downloads.xiph.org/releases/ao/libao-1.1.0.zip</a>) dan explore kedalam folder src.
2. edit file audio_out.c dengan codeblock dan silahkan cari (ctrl+f) ao_play.
3. didalam fungsi ao_play tersebut lakukan persesuaian type data

int ao_play(ao_device *device, char* output_samples, uint_32 num_bytes)
{
char *playback_buffer;

if (device == NULL)
return 0;

if (device->swap_buffer != NULL) {
int out_bytes = num_bytes*device->output_channels/device->input_channels;
if (_realloc_swap_buffer(device, out_bytes)) {
int i;
int swap = (device->bytewidth>1 &&
device->client_byte_format != device->driver_byte_format);
for(i=0;i<device->output_channels;i++){
int ic = device->inter_permute ? device->inter_permute[i] : i;
if(ic==-1){
_buffer_zero(device->swap_buffer,i,device->bytewidth,device->output_channels,
 out_bytes);
}else if(swap){
_buffer_permute_swap(device->swap_buffer,i,device->bytewidth,device->output_channels,
 out_bytes, output_samples, ic, device->input_channels);
}else{
_buffer_permute(device->swap_buffer,i,device->bytewidth,device->output_channels,
out_bytes, output_samples, ic, device->input_channels);
}
}
playback_buffer = device->swap_buffer;
num_bytes = out_bytes;
} else
return 0; /* Could not expand swap buffer */
} else
playback_buffer = output_samples;

return device->funcs->play(device, playback_buffer, num_bytes);
}


4. lihat argumen output_samples disana didefinisikan sebagai char* rubahlah menjadi unsigned char* output_samples.
5. lihat deklarasi playback_buffer ia juga didefinisikan sebagai char* rubahlah menjadi unsigned char*.

berikut perubahannya:
int ao_play(ao_device *device, unsigned char* output_samples, uint_32 num_bytes)
{
unsigned char *playback_buffer;

if (device == NULL)
return 0;

if (device->swap_buffer != NULL) {
int out_bytes = num_bytes*device->output_channels/device->input_channels;
if (_realloc_swap_buffer(device, out_bytes)) {
int i;
int swap = (device->bytewidth>1 &&
device->client_byte_format != device->driver_byte_format);
for(i=0;i<device->output_channels;i++){
int ic = device->inter_permute ? device->inter_permute[i] : i;
if(ic==-1){
_buffer_zero(device->swap_buffer,i,device->bytewidth,device->output_channels,
 out_bytes);
}else if(swap){
_buffer_permute_swap(device->swap_buffer,i,device->bytewidth,device->output_channels,
 out_bytes, output_samples, ic, device->input_channels);
}else{
_buffer_permute(device->swap_buffer,i,device->bytewidth,device->output_channels,
out_bytes, output_samples, ic, device->input_channels);
}
}
playback_buffer = device->swap_buffer;
num_bytes = out_bytes;
} else
return 0; /* Could not expand swap buffer */
} else
playback_buffer = output_samples;

return device->funcs->play(device, playback_buffer, num_bytes);
}


6. Simpan perubahan tersebut, dan silahkan buka folder include, edit file ao/ao.h, lakukan pencarian (ctrl+f) ao_play juga, dan lakukan persesuaian lagi.
int ao_play(ao_device *device,
char *output_samples,
uint_32 num_bytes);


sesuaikan menjadi:

int ao_play(ao_device *device,
unsigned char *output_samples,
uint_32 num_bytes);


7. Simpan dan kompilasi ulang library libao tersebut (./configure via msys dan mingw32-make).
8. Jadikan library libao hasil kompilasi menjadi opsi linker yang digunakan oleh codeblok / visual studio.

9. Sedangkan source kode player kita akan menjadi sbb:
#include <mpg123.h>
#include <ao/ao.h>
#include <malloc.h>
#include <stdlib.h>
#include <windows.h>

#define BITS 8

int main(int argc, char *argv[])
{
mpg123_handle *mh;
unsigned char *buffer;
size_t buffer_size;
size_t done;
int err, driver, channels, encoding;
ao_device *dev;
ao_sample_format format;
long rate;
ao_initialize();
driver = ao_default_driver_id();

// ========= inisial library =============

mpg123_init();
mh = mpg123_new(NULL, &err);
buffer_size = mpg123_outblock(mh);
buffer = (unsigned char*)malloc(buffer_size * sizeof(unsigned char));
mpg123_param(mh, MPG123_RESYNC_LIMIT, -1, 0);
char* filename=argv[1];
mpg123_open(mh, filename);
mpg123_getformat(mh, &rate, &channels, &encoding);

// ************************************ 

format.bits = mpg123_encsize(encoding) * BITS;
format.rate = rate;
format.channels = channels;
format.byte_format = AO_FMT_NATIVE;
format.matrix = 0;
double secs;
dev = ao_open_live(driver, &format, NULL);

while (mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK)
{
ao_play(dev, buffer, done);
fprintf(stderr, "Frame: %li\n", mpg123_tellframe(mh));
mpg123_position(mh, 0, 0, NULL, NULL, &secs, NULL);
fprintf(stderr,"[%d:%02d] Decoding of %s finished.\n", (int)(secs / 60), ((int)secs) % 60, filename);
}

/* clean up */

free(buffer);
ao_close(dev);
mpg123_close(mh);
mpg123_delete(mh);
mpg123_exit();
ao_shutdown();

return 0;
}
nah kode diatas sudah tidak menggunakan reinterpret_cast&lt;&gt;() lagi, ini dapat dikompilasi oleh mingw gcc. selamat mencoba...

Minggu, 29 Desember 2013

mengexport symbol dari file dll opensource untuk digunakan oleh visual studio

Banyak library yang disediakan oleh opensource untuk digunakan di lingkungan ms-windows, namun kadang kita hanya mendapatkan file dll nya saja.berikut ini adalah cara yang saya gunakan untuk mengexport symbol dari file dll open source dan kemudian digunakan oleh visual studio.

pertama kita membutuhkan:
a. mingw dan msys (msys: optional) : gendef.exe
b. visual studio 2013 (boleh versi sebelumnya) : lib.exe

nah anggaplah kita telah mempunyai file libmpg123-0.dll yang kita peroleh dari suatu tempat opensource, dan tersimpan di c:\myvslib\bin.

prosedurnya:
1. extract symbol atau function definition dari file libmpg123-0.dll tersebut dengan menggunakan gendef.exe.
buka console terminal cmd
c:
cd \myvslib\bin
gendef.exe  libmpg123-0.dll
* [libmpg123-0.dll] Found PE image

sampai disini maka akan tersedia file libmpg123-0.def di folder tersebut. isi dari libmpg123-0.def adalah daftar function yang tersedia didalam file libmpg123-0.dll.
;
; Definition file of libmpg123-0.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "libmpg123-0.dll"
EXPORTS
mpg123_add_string
mpg123_add_substring
mpg123_chomp_string
mpg123_clip
mpg123_close
mpg123_copy_string
mpg123_current_decoder
mpg123_decode
mpg123_decode_frame
mpg123_decode_frame_32
mpg123_decoder
mpg123_decoders
mpg123_delete
mpg123_delete_pars
mpg123_enc_from_id3
mpg123_encodings
mpg123_encsize
mpg123_eq
mpg123_errcode
mpg123_exit
mpg123_feature
mpg123_feed
mpg123_feedseek
mpg123_feedseek_32
mpg123_fmt
mpg123_fmt_all
mpg123_fmt_none
mpg123_fmt_support
mpg123_format
mpg123_format_all
mpg123_format_none
mpg123_format_support
mpg123_framebyframe_decode
mpg123_framebyframe_decode_32
mpg123_framebyframe_next
mpg123_framedata
mpg123_framepos
mpg123_framepos_32
mpg123_free_string
mpg123_geteq
mpg123_getformat
mpg123_getpar
mpg123_getparam
mpg123_getstate
mpg123_getvolume
mpg123_grow_string
mpg123_icy
mpg123_icy2utf8
mpg123_id3
mpg123_index
mpg123_index_32
mpg123_info
mpg123_init
mpg123_init_string
mpg123_length
mpg123_length_32
mpg123_meta_check
mpg123_meta_free
mpg123_new
mpg123_new_pars
mpg123_noise
mpg123_open
mpg123_open_32
mpg123_open_fd
mpg123_open_fd_32
mpg123_open_feed
mpg123_open_handle
mpg123_open_handle_32
mpg123_outblock
mpg123_par
mpg123_param
mpg123_parnew
mpg123_plain_strerror
mpg123_position
mpg123_position_32
mpg123_rates
mpg123_read
mpg123_replace_buffer
mpg123_replace_reader
mpg123_replace_reader_32
mpg123_replace_reader_handle
mpg123_replace_reader_handle_32
mpg123_reset_eq
mpg123_resize_string
mpg123_safe_buffer
mpg123_scan
mpg123_seek
mpg123_seek_32
mpg123_seek_frame
mpg123_seek_frame_32
mpg123_set_filesize
mpg123_set_filesize_32
mpg123_set_index
mpg123_set_index_32
mpg123_set_string
mpg123_set_substring
mpg123_spf
mpg123_store_utf8
mpg123_strerror
mpg123_strlen
mpg123_supported_decoders
mpg123_tell
mpg123_tell_32
mpg123_tell_stream
mpg123_tell_stream_32
mpg123_tellframe
mpg123_tellframe_32
mpg123_timeframe
mpg123_timeframe_32
mpg123_tpf
mpg123_volume
mpg123_volume_change

2. link file libmpg123-0.def menjadi libmpg123-0.lib dengan menggunakan perintah lib.exe dari visual studio. masih didalam directory c:\myvslib\bin, gunakan lib.exe untuk mengkonversikan file libmpg123-0.def tersebut menjadi file .lib yang kelak akan digunakan oleh visual studio.

lib.exe /def:libmpg123-0.def /OUT:libmpg123-0.lib

Microsoft (R) Library Manager Version 12.00.21005.1
Copyright (C) Microsoft Corporation.  All rights reserved.

LINK : warning LNK4068: /MACHINE not specified; defaulting to X86
   Creating library libmpg123-0-d.lib and object libmpg123-0-d.exp

maka didalam folder akan terdapat file libmpg123-0-d.lib dan libmpg123-0-d.exp. kedua  file tersebutlah yang kelak akan digunakan di visual studio sebagai library tambahan dalam suatu program.

oh ya.. sebelum melakukan langkah tersebut silahkan pastikan terlebih dahulu bahwa situs mpg123 tersebut memang tidak menyediakan developer version dari library tersebut. karena bagaimanapun juga kita lebih baik menggunakan versi developer dari pemilik library tersebut. disana masih dibutuhkan header file untuk dapat menggunakan library tersebut dalam visual studio.

Sabtu, 21 Desember 2013

SFML Network dengan Thread untuk client server [bagian 5]

Setelah kita mengetahui bagaimana hubungan antara object server.cpp dengan client.cpp, sekarang perhatikan code berikut yang terdapat didalam kode server.cpp:
if(Listener.accept(Clients[OpenSlot-1]->Socket) != sf::Socket::Done) {…}
fungsi jika dalam baris tersebut memangil fungsi Listener.accept(dengan parameter nilai kembalian dari Client[OpenSlot-1] object member Socket) Listener itu sendiri adalah object turunan dari sfml-network yaitu sf::tcplistener yang dideklarasikan diawal kode server.cpp:
sf::TcpListener Server::Listener = sf::TcpListener();
mari kita anggap kondisi jika adalah false maka proses yang dijalankan adalah bagian:
else
{      {
      std::wstringstream ss; ss << L"{GDClient connected} on port {YD" << OpenSlot+Port << L"}.";
      writeToLog(ss.str());
      }
      Clients[OpenSlot-1]->Dead = false;
      Clients[OpenSlot-1]->listenThread = new sf::Thread(&Client::listen, Clients.at(OpenSlot-1));
      Clients[OpenSlot-1]->listenThread->launch();
}
Proses akan menulis dilayar tentang std::wstringstream ss; ss << L"{GDClient connected} on port {YD" << OpenSlot+Port << L"}."; writeToLog(ss.str()); kemudian memberi nilai false kepada Client[OpenSlot-1] object member:Dead, kemudian membuka lagi thread baru untuk koneksi client berikutnya:
Clients[OpenSlot-1]->listenThread = new sf::Thread(&Client::listen, Clients.at(OpenSlot-1));
Clients[OpenSlot-1]->listenThread->launch();

Nah dengan demikian setiap client akan terhubung kepada server pada port mereka masing-masing dimana setiap koneksi client tersebut akan berada dalam thread yang berbeda-beda.