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 <char*>(buffer) sebagai casting type data yang berbeda antara keluaran libmpg123 (unsigned char) dengan masukan libao (char). Nah ternyata fungsi reinterpret_cast<>() 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, &done) == MPG123_OK)
{
ao_play(dev, reinterpret_cast<char*>(buffer), done);
fprintf(stderr, "Frame: %li\n", mpg123_tellframe(mh));
}
//===========reinterpret_cast<char*>(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...

Tidak ada komentar:

Posting Komentar