Help on port Alien8 game (FMODex --> SDL_Mixer)


Farox

Certified Guru
Joined
Jan 8, 2009
Messages
2,413
Age
56
Location
Italy
Website
rbnet.it
Hi

it's been some time that i want to port this game, the only thing that have blocked me is that (in)famous FMODex lib that the game use to produce sound/music.

Alien8 is a game programmed by Ignacio Pérez Gil and available at Retrospec site http://retrospec.sgn.net/game/alien8

The game is programmed in C using Allegro 4 and FMODex (for the audio part). I have searched on the web but i didn't have found an ARMv7 version compatible with Pandora.

Now i managed to compile the game using SDL and SDL_Mixer instead of FMODex (with the help of the precious info from Sebt3 FMOD-->SDL previous port)....but... i need some more help as now the soundfx are working good..really good.... instead the music is absent (in part because the code that play music is not converted ).

The game run fine, i have added Pandora buttons control...but i like to add music playing before release..

So here is the Audio.c source

//******************************************************************************
// audio.c
// Funciones genericas de sonido.
// Por Ignacio Pérez Gil 17/03/2008.
//******************************************************************************

//******************************************************************************
// Includes.
//******************************************************************************
#include
#ifdef USE_FMOD
#include
#else
#include
#include
#endif
#include "audio.h"

//******************************************************************************
// Declaracion de estructuras de datos y variables globales.
//******************************************************************************
DATAFILE *f_msc = NULL;
DATAFILE *f_audio = NULL;
#ifdef USE_FMOD
FMOD_SYSTEM *sistema = NULL;
FMOD_SOUND *sm = NULL;
FMOD_CHANNEL *canal_musica = NULL;
#else
Mix_Chunk *sm = NULL;
Mix_Music *canal_musica = NULL;/// a test ..i don't know if right..farox
#endif

char musica_sonando=-1;
const char *msc_fin=NULL;
unsigned int long_msc_fin;
unsigned char vol_son=0;
float vol_mus=0;
char rep_snd_onda(SAMPLE *onda, char sonido, char bucle);
struct _voz // Estructura para almacenar los datos de las voces
{char activa; // Indica si la voz este activa
// 0-desactivada, 1-normal, 2-bucle, 3-no parar
int v; // Voz
} voz[16]={{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}};

//******************************************************************************
// Funcion iniciar_audio()
// Inicializa el sistema de audio y carga los ficheros de sonidos y musica.
//******************************************************************************
void ini_audio(void)
{
reserve_voices(16,0);

install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL);

#ifdef USE_FMOD
FMOD_System_Create(&sistema);
FMOD_System_Init(sistema, 16, FMOD_INIT_NORMAL, NULL);
#else
SDL_InitSubSystem(SDL_INIT_AUDIO);
Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048);
#endif

f_msc = load_datafile("msc.dat");
f_audio = load_datafile("snd.dat");
}

//******************************************************************************
// Funcion finalizar_audio()
// Descarga los ficheros de sonidos y musica.
//******************************************************************************
void fin_audio(void)
{
#ifdef USE_FMOD
if(musica_sonando>=0) FMOD_Sound_Release(sm);
FMOD_System_Close(sistema);
FMOD_System_Release(sistema);
#else
if(musica_sonando>=0) Mix_HaltChannel(-1);
Mix_CloseAudio();
#endif
unload_datafile(f_msc);
unload_datafile(f_audio);
}

//******************************************************************************
// Funcion reproducir_musica(...)
// Inicia la reproduccion del fichero de musica n.
//******************************************************************************
void reproducir_musica(char n)
{
if(vol_mus)
{
#ifdef USE_FMOD
FMOD_System_Update(sistema);
#endif
if(musica_sonando!=n && n>=0)
{
#ifdef USE_FMOD
FMOD_CREATESOUNDEXINFO inf_tm;
if(musica_sonando>=0) FMOD_Sound_Release(sm);
#else
if(musica_sonando>=0) Mix_HaltChannel(-1);
#endif
musica_sonando=n;
#ifdef USE_FMOD
memset(&inf_tm, 0, sizeof(FMOD_CREATESOUNDEXINFO));
inf_tm.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
#endif
if(msc_fin)
{
#ifdef USE_FMOD
inf_tm.length=long_msc_fin;
FMOD_System_CreateStream(sistema, msc_fin, FMOD_HARDWARE | FMOD_LOOP_OFF | FMOD_OPENMEMORY, &inf_tm, &sm);
#else
//Mix_PlayMusic(n,-1);
#endif
}
else
{
#ifdef USE_FMOD
inf_tm.length=f_msc[n].size;
FMOD_System_CreateStream(sistema, (const char *)(f_msc[n].dat), FMOD_HARDWARE | FMOD_LOOP_NORMAL | FMOD_OPENMEMORY, &inf_tm, &sm);
#else
Mix_PlayMusic(f_msc[n].dat,-1);
#endif
}
#ifdef USE_FMOD
FMOD_System_PlaySound(sistema, FMOD_CHANNEL_FREE, sm, 1, &canal_musica);
FMOD_Channel_SetVolume(canal_musica,vol_mus);
FMOD_Channel_SetPaused(canal_musica,0);
#else
//
Mix_VolumeMusic(vol_mus);
#endif
}
}
}

//******************************************************************************
// Funcion modificar_volmus(...)
// Modifica el volumen de la musica.
//******************************************************************************
void modificar_volmus(unsigned char vol)
{
if(vol<=100)
{
vol_mus=vol;
vol_mus/=100;
if(musica_sonando>=0)
{
if(!vol_mus)
#ifdef USE_FMOD
{
FMOD_Channel_Stop(canal_musica);
musica_sonando=-1;
}
else
FMOD_Channel_SetVolume(canal_musica,vol_mus);
#else
{
Mix_HaltChannel(-1);
musica_sonando=-1;
}
else
Mix_VolumeMusic(vol_mus);
#endif
}
}
}

//******************************************************************************
// Funcion parar_musica()
// Detiene la musica que se este reproduciendo.
//******************************************************************************
void parar_musica(void)
{
#ifdef USE_FMOD
if(musica_sonando>=0)
{
FMOD_Sound_Release(sm);
musica_sonando=-1;
}
#else
if(musica_sonando>=0)
{
Mix_HaltChannel(-1);
musica_sonando=-1;
}
#endif
msc_fin=NULL;
}

//******************************************************************************
// Funcion musica_fin(...)
// Obtiene un puntero a la musica del fin del juego, que hay que reproducir
// una sola vez.
//******************************************************************************
void musica_fin(void *msc_fin_void, unsigned int long_msc_fin_void)
{
msc_fin=(const char *)msc_fin_void;
long_msc_fin=long_msc_fin_void;
}

//******************************************************************************
// Funcion reproducir_sonido(...)
// Reproduce el sonido indicado, con la opcion de buclearlo.
//******************************************************************************
char reproducir_sonido(char sonido, char bucle)
{
return rep_snd_onda(NULL,sonido,bucle);
}

//******************************************************************************
// Funcion reproducir_onda(...)
// Reproduce el sample indicado, con la opcion de buclearlo.
//******************************************************************************
char reproducir_onda(SAMPLE *onda, char bucle)
{
return rep_snd_onda(onda,0,bucle);
}

//******************************************************************************
// Funcion rep_snd_onda(...)
// Reproduce el sample o el sonido indicado, con el modo indicado.
//******************************************************************************
char rep_snd_onda(SAMPLE *onda, char sonido, char modo)
{
char f = -1;

if(!vol_son) return -1;

do // Busco la primera voz que no se este usando
{
f++;
if(voz[f].activa==1 || voz[f].activa==3)
if(voice_get_position(voz[f].v) == -1)
{
deallocate_voice(voz[f].v);
voz[f].activa = 0;
}
}while(voz[f].activa && f<15);

if(voz[f].activa) return -1; // Las 16 voces estan siendo usadas.

// Ahora f apunta a la voz que vamos a usar para el sonido.
voz[f].v = allocate_voice(onda?onda:(SAMPLE *)f_audio[sonido].dat);
if(voz[f].v == -1) return -1;
voice_set_volume(voz[f].v, vol_son);
voice_set_playmode(voz[f].v, modo<0?PLAYMODE_PLAY:modo);
voice_start(voz[f].v);
if(modo<0)
voz[f].activa = 3;
else
voz[f].activa = (modo==PLAYMODE_PLAY?1:2);

return f;
}

//******************************************************************************
// Funcion pausar_sonidos()
// Pone los sonidos bucleados en pausa, y para los demas.
//******************************************************************************
void pausar_sonidos(void)
{
char f;

for(f=0;f<16;f++)
if(voz[f].activa)
{
if(voz[f].activa==1 || voz[f].activa==3)
{// Si la voz este parada o no este bucleada, aprovecho para liberarla.
deallocate_voice(voz[f].v);
voz[f].activa = 0;
}
else
voice_stop(voz[f].v);
}
}

//******************************************************************************
// Funcion reanudar_sonidos()
// Reanuda la reproduccion de los sonidos pausados.
//******************************************************************************
void reanudar_sonidos(void)
{
char f;

for(f=0;f<16;f++)
if(voz[f].activa)
voice_start(voz[f].v);
}

//******************************************************************************
// Funcion reiniciar_sonido(...)
// Vuelve a colocar un sonido al principio.
//******************************************************************************
void reiniciar_sonido(char vz)
{
if(vz>=0)
if(voz[vz].activa)
voice_set_position(voz[vz].v, 0);
}

//******************************************************************************
// Funcion modificar_volson(...)
// Modifica el volumen maximo de los sonidos.
//******************************************************************************
void modificar_volson(unsigned char vol, char vz)
{
float fvol=vol*2.55;
vol_son=(unsigned char)fvol;
if(vz>=0) voice_set_volume(voz[vz].v, vol_son);
}

//******************************************************************************
// Funcion detener_sonido(...)
// Detiene un sonido determinado.
//******************************************************************************
void detener_sonido(char vz)
{
if(vz>=0)
if(voz[vz].activa)
{
deallocate_voice(voz[vz].v);
voz[vz].activa = 0;
}
}

//******************************************************************************
// Funcion detener_sonidos(char todos)
// Detiene todos los sonidos que se estan reproduciendo.
//******************************************************************************
void detener_sonidos(char todos)
{
char f;
for(f=0;f<16;f++)
if(voz[f].activa>0 && (voz[f].activa<3 || todos))
{
deallocate_voice(voz[f].v);
voz[f].activa = 0;
}
}

Thanks
 
Not easy to debug with just a piece of the code but a few remark already:

For music, donc use Mix_HaltChannel(-1) that will stop all sound just to stop the music but Mix_HaltMusic()

The parar_musica() function should be more like


if(musica_sonando>0) {
Mix_HaltMusic();
if (music_sdlmix) Mix_FreeMusic(music_sdlmix);
musica_sonando = -1;
music_sdlmix = NULL;
}

(don't forget to use -fsigned-char to compile this one, as it looks like musica_sonando is char that can be negative)

With a new variable


Music_Mix* music_sdlmix = NULL;

and for reproducir_musica(char n)

the second part should be

Code:
if(msc_fin)
{
 #ifdef USE_FMOD
 inf_tm.length=long_msc_fin;
 FMOD_System_CreateStream(sistema, msc_fin, FMOD_HARDWARE | FMOD_LOOP_OFF | FMOD_OPENMEMORY, &inf_tm, &sm);
 #else
 music_sdlmix = Mix_LoadMUS(msc_fin);
 if (music_sdlmix) Mix_Play(music_sdlmix, 1);
#endif
}
else
{
 #ifdef USE_FMOD
 inf_tm.length=f_msc[n].size;
 FMOD_System_CreateStream(sistema, (const char *)(f_msc[n].dat), FMOD_HARDWARE | FMOD_LOOP_NORMAL | FMOD_OPENMEMORY, &inf_tm, &sm);
 #else
 music_sdlmix = Mix_LoadMUS((const char *)(f_msc[n].dat));
 if (music_sdlmix) Mix_Play(music_sdlmix, -1);
 #endif
}
 

Also, there is some function to set the lenght of the music played (musica_fin) that is not handled here. But I guess that a start...
 
Thanks seb :)

I applied your suggested code...but music is not played :(

If you have time and want to take a look i could upload the complete sources.
 
You should also make sure SDL Mixer is initialized with the correct music loader, with something like


Mix_Init(MIX_INIT_FLAC|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG);

 
Also, when Mix_LoadMUS(...), it would be intersting to check if new music_sdlmix is NULL or not, and printf the Mix_GetError() of the error.
 
Last edited by a moderator:
Ok i added the Mix_init ( MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG) (i don't think i have FLAC music files) and nothing changed.

Plus i added :

if (!music_sdlmix) {

printf ("PlayMusic error SDL_Mixer error: %s\n", Mix_GetError());

};

and i have

PlayMusic error SDL_Mixer error: Couldn't open 'ID3
 
Ok i added the Mix_init ( MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG) (i don't think i have FLAC music files) and nothing changed.

Plus i added :

if (!music_sdlmix) {

printf ("PlayMusic error SDL_Mixer error: %s\n", Mix_GetError());

};

and i have

PlayMusic error SDL_Mixer error: Couldn't open 'ID3
Ok, so the issue is "just" that "f_msc[n].dat" or "msc_fin" is not the name of the file but something else. For the LoadMUS function, you need the filename. You have to dig out in the source code to find out how to get the correct name..
 
I searched on the entire sources and the 95% of time reproducir_musica is called like this
 

reproducir_musica(0);

...................................................

or

for(contador=0;contador<10;contador++) {reproducir_musica(0);fm_volcar();}
a few times like:

// Comienza la música, y esperamos tres segundos en negro.
 musica_fin(f_fin[8].dat,f_fin[8].size);
 for(f=0;f<TICKS*3;f++) {reproducir_musica(100);fm_volcar();}
or

// Esperamos dos segundos.
 for(f=0;f<TICKS*2;f++) {reproducir_musica(100);fm_volcar();}

 // Dibujamos el primer mensaje.
 for(f=10;f<251;f+=4)
  {
   blit(buffer2,buffer,0,0,0,0,RES_X,RES_Y);
   set_trans_blender(0,0,0,f);
   draw_trans_sprite(buffer,(BITMAP *)(f_fin[2+idioma*3].dat),80,120);
   reproducir_musica(100);
   fm_volcar();
  }
 draw_sprite(buffer,(BITMAP *)(f_fin[2+idioma*3].dat),80,120);


For me we need to concentrate on FMOD_System_CreateStream

I found an interesting blog article about it

https://katyscode.wordpress.com/2012/10/05/cutting-your-teeth-on-fmod-part-1-build-environment-initialization-and-playing-sounds/

where it says:

Playing sounds and songs
There are two main ways to get audio into FMOD – createSound and createStream. createSound loads a sound file into memory in its entirety, and decompresses it if necessary, whereas createStream opens a file and just buffers it a piece at a time, decompressing each buffered segment on the fly during playback. Each option has its advantages and disadvantages, but in general music should be streamed since decompressing an MP3 or Vorbis file of some minutes length in memory will consume some 10s of megabytes, whereas sound effects that will be used repeatedly and are relatively short can be loaded into memory for quick access.

To load a sound into memory:




FMOD::Sound *audio;

system->createSound("Audio.mp3", FMOD_DEFAULT, 0, &audio);




To open a stream:




FMOD::Sound *audioStream;

system->createStream("Audio.mp3", FMOD_DEFAULT, 0, &audioStream);




The first parameter is the relative pathname of the file to open and the 4th parameter is a pointer to an FMOD::Sound pointer that receives the resource handle of the audio. Under normal circumstances the 2nd and 3rd parameters should be left as FMOD_DEFAULT and 0 (the 2nd is the mode in which to open the audio, the 3rd is an extended information structure used in special cases – we will come to this in Part 3 of the series).
and the 3th part where it says: https://katyscode.wordpress.com/2013/01/15/cutting-your-teeth-on-fmod-part-3-embedding-sounds-in-your-application-as-resources/

Loading embedded resources into FMOD
You would be surprised how complicated this is, so to save you the trouble, I have provided the code below. First, we’ll set a couple of variables to the resource we want to locate:




int resourceId = IDMP3_Song1;

LPCTSTR resourceType = "MP3";




The above lines correspond to one of the resources shown in Figure 1. You will need to change these to match your own project settings.

To actually find and load the resource into FMOD:




HRSRC rsrc = FindResource(NULL, MAKEINTRESOURCE(resourceId), resourceType);

HGLOBAL handle = LoadResource(NULL, rsrc);

 

DWORD audioSize = SizeofResource(NULL, rsrc);

LPVOID audioData = LockResource(handle);

 

FMOD_CREATESOUNDEXINFO audioInfo;

memset(&audioInfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));

audioInfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);

audioInfo.length = static_cast<unsigned int>(audioSize);

 

// system is a pointer to FMOD::System set in your application's initialization phase

FMOD::Sound *sound;

FMODErrorCheck(system->createSound(static_cast<const char *>(audioData), FMOD_OPENMEMORY, &audioInfo, &sound));




At this point, the audio resource will be loaded into sound just as if it had been loaded from file. Note that this code opens the sound directly. If you want to open it as a stream, simply change createSound to createStream and add a line of code to set the stream buffer size right before calling createStream:




system->setStreamBufferSize(65536, FMOD_TIMEUNIT_RAWBYTES);




for a buffer size of 64K. You may wish to experiment with this value to get the best performance if your application suffers from stuttering or broken up audio when streaming.
We need to implement this in SDL/SDL_Mixer but i don't know how to do it.
 
Last edited by a moderator:
Ahhh, it's an FMOD_OPENMEMORY, I didn't checked that. We should probably use Mix_LoadMUS_RW instead then.
 
with something like


if(msc_fin)
{
#ifdef USE_FMOD
inf_tm.length=long_msc_fin;
FMOD_System_CreateStream(sistema, msc_fin, FMOD_HARDWARE | FMOD_LOOP_OFF | FMOD_OPENMEMORY, &inf_tm, &sm);
#else
SDL_RWops *rw = SDL_RWFromMem(msc_fin, long_msc_fin);
music_sdlmix = Mix_LoadMUS_RW(rw);
Mix_PlayMusic(music_sdlmix, 1);
#endif
}
else
{
#ifdef USE_FMOD
inf_tm.length=f_msc[n].size;
FMOD_System_CreateStream(sistema, (const char *)(f_msc[n].dat), FMOD_HARDWARE | FMOD_LOOP_NORMAL | FMOD_OPENMEMORY, &inf_tm, &sm);
#else
SDL_RWops *rw = SDL_RWFromMem(f_msc[n].dat, f_msc[n].size);
music_sdlmix = Mix_LoadMUS_RW(rw);
Mix_PlayMusic(music_sdlmix, -1);
#endif
}
(that rw thingy should probably be global and free properly when stopping music...)
 
Last edited by a moderator:
Uhmm just added and tested but no music....and no error reported.
 
Last edited by a moderator:
Uhmm just added and tested but no music....and no error reported.
Did you move the rw variable global, just in case?

Also, you should test if music_sdlmix is NULL or not after the Mix_LoadMUS_RW
 
Last edited by a moderator:
rw moved global but nothing changed and no error.

and now the function is


if(msc_fin)
{
#ifdef USE_FMOD
inf_tm.length=long_msc_fin;
FMOD_System_CreateStream(sistema, msc_fin, FMOD_HARDWARE | FMOD_LOOP_OFF | FMOD_OPENMEMORY, &inf_tm, &sm);
#else
rw = SDL_RWFromMem(msc_fin, long_msc_fin);
music_sdlmix = Mix_LoadMUS_RW(rw);

if (!music_sdlmix) { printf ("PlayMusic error SDL_Mixer error: %s\n", Mix_GetError());}

Mix_PlayMusic(music_sdlmix, 1);

#endif
}
else
{
#ifdef USE_FMOD
inf_tm.length=f_msc[n].size;
FMOD_System_CreateStream(sistema, (const char *)(f_msc[n].dat), FMOD_HARDWARE | FMOD_LOOP_NORMAL | FMOD_OPENMEMORY, &inf_tm, &sm);
#else
rw = SDL_RWFromMem(f_msc[n].dat, f_msc[n].size);
music_sdlmix = Mix_LoadMUS_RW(rw);

if (!music_sdlmix) { printf ("PlayMusic error SDL_Mixer error: %s\n", Mix_GetError());}

Mix_PlayMusic(music_sdlmix, -1);

#endif
}

Thanks for your patience :)

i tried to use Mix_LoadWAV_RW (rw,1) instead of Mix_LoadMUS_RW

result..... i have no music and a message:

"Unrecognised sound file tipe"
 
Last edited by a moderator:
@Farox: on last thing: I think it's working, but just the volume is too low!
 
You should put


Mix_VolumeMusic(MIX_MAX_VOLUME*vol_mus);

Because vol_mus is probably a float [0.0 ; 1.0f] where Mix_VolumeMusic needs an int [0 ; 128]. If it still doesn't work after that, I'll grab the source to try locally.
 
Last edited by a moderator:
This gives me the sudden yearning to convert from BASS to SDL_Mixer for PandaBAS. What's the CPU usage like in SDL_Mixer if it's not actually playing anything? Does it run any extra threads waiting for sound to play?

D.
 
Ok i build a pnd of this game...but is happening a odd thing...the game run, soundfx are playing good...but no music...again? :( (tested on fat sdcard)

I rerun Codeblocks cli and try to run the game (not the pnd) and all is fine... :mellow:

Shut down Codeblock and Pandora (just in case) Restart and open a new shell i set the LD_LIBRARY_PATH and run the game i have

ALSA lib pcm.dmix.c: 1089:(snd_dmix_open) unable to play slave

warning: incorrect audio format
Now what is the cause??

This gives me the sudden yearning to convert from BASS to SDL_Mixer for PandaBAS. What's the CPU usage like in SDL_Mixer if it's not actually playing anything? Does it run any extra threads waiting for sound to play?
Sorry i can't help you on this subject.
 
Last edited by a moderator:
Ok i build a pnd of this game...but is happening a odd thing...the game run, soundfx are playing good...but no music...again? :( (tested on fat sdcard)

I rerun Codeblocks cli and try to run the game (not the pnd) and all is fine... :mellow:

Shut down Codeblock and Pandora (just in case) Restart and open a new shell i set the LD_LIBRARY_PATH and run the game i have

ALSA lib pcm.dmix.c: 1089:(snd_dmix_open) unable to play slave

warning: incorrect audio format
Now what is the cause??
Probably a missing dependency for mp3 playback, that is probably dynamicaly loaded (so copy_libs.sh or ldd doesn't see it). If you have ssh, just do some lsof to see what are the loaded libs once the game is launched.
 
Last edited by a moderator:
The only libs that are missing (used ldd alien8) are

libpulse.so.0

and

libpulsecommon-0.9.15.so

that i added taken from your easyrpgplayer.pnd

No ssh here...
 
I compared the libs copied to the pnd lib folder with the one required by ldd.(excluding the one presents in nand)

The only suspicious are: libasound.so.2

the rest are:

libdl

librt

libts

libncurses

libresolv
 
Back
Top