#include #include #include #include #include /* Written circa 2014 by grepwood@sucs.org */ /* This program will utilize libacm and some string logic * in order to absolutely correctly decode an ACM at all times, * without user hints. */ /* prototype for our audio callback * see the implementation for more information */ /* variable declarations */ static uint8_t *audio_pos; /* global pointer to the audio buffer to be played */ static uint32_t audio_len; /* remaining length of the sample we have to play */ /* audio callback function * here you have to copy the data of your audio buffer into the * requesting audio buffer (stream) * you should only copy as much as the requested length (len) */ void my_audio_callback(void * userdata, Uint8 *stream, int len) { if (audio_len ==0) return; len = ( (unsigned)len > audio_len ? audio_len : (unsigned)len ); SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME); /* mix from one buffer into another */ audio_pos += len; audio_len -= len; } /* Some sounds in Fallout have spoofed channel amount. * Known suspects are from the Speech directory. * Hence the strstr call */ uint8_t DetectFakeStereo(const char *fn) { uint8_t result = 0; char * pointer; pointer = strstr(fn,"Speech"); if(pointer != NULL) { result = 1; } return result; } int main(int argc, char* argv[]){ static uint32_t wav_length; static uint8_t *wav_buffer; static SDL_AudioSpec wav_spec; uint32_t wavsize; char * fn2 = NULL; uint8_t cf_force_chans; SDL_RWops * WavFromACM = NULL; if ( argc != 2 ) { fputs("Need a path to ACM file\n",stderr); return 2; } if (SDL_Init(SDL_INIT_AUDIO) < 0) { fputs("Could not SDL_Init\n",stderr); return 1; } /* Detect spoofed stereo by known strings */ cf_force_chans = DetectFakeStereo(argv[1]); /* FSF.ACM is unfortunately spoofed too */ cf_force_chans = 1; /* Convert the ACM to WAV */ fn2 = libacm_decode_file_to_mem(argv[1],cf_force_chans,&wavsize); /* Load the WAV the specs, length and buffer of our wav are filled */ WavFromACM = SDL_RWFromConstMem(fn2,wavsize); if(SDL_LoadWAV_RW(WavFromACM,1,&wav_spec,&wav_buffer, &wav_length) == NULL) { free(fn2); fputs("Loading the ACM didn't succeed\n",stderr); return 2; } /* set the callback function */ wav_spec.callback = my_audio_callback; wav_spec.userdata = NULL; /* set our global static variables */ audio_pos = wav_buffer; /* copy sound buffer */ audio_len = wav_length; /* copy file length */ /* Open the audio device */ if ( SDL_OpenAudio(&wav_spec, NULL) < 0 ){ fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); free(fn2); exit(-1); } /* Start playing */ SDL_PauseAudio(0); /* wait until we're don't playing */ while ( audio_len > 0 ) { SDL_Delay(100); } /* shut everything down */ SDL_CloseAudio(); SDL_FreeWAV(wav_buffer); free(fn2); return 0; }