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...

Tidak ada komentar:

Posting Komentar