/* * Some mp3 related code for Sega/Mega CD. * Uses the Helix Fixed-point MP3 decoder * (C) notaz, 2007-2009 * * This work is licensed under the terms of MAME license. * See COPYING file in the top-level directory. */ #include #include #include #include #include "helix/pub/mp3dec.h" #include "mp3.h" static HMP3Decoder mp3dec; static unsigned char mp3_input_buffer[2 * 1024]; #ifdef __GP2X__ #define mp3dec_decode _mp3dec_decode #define mp3dec_start _mp3dec_start #endif static void *libhelix; HMP3Decoder (*p_MP3InitDecoder)(void); void (*p_MP3FreeDecoder)(HMP3Decoder); int (*p_MP3Decode)(HMP3Decoder, unsigned char **, int *, short *, int); int mp3dec_decode(FILE *f, int *file_pos, int file_len) { unsigned char *readPtr; int bytesLeft; int offset; // mp3 frame offset from readPtr int had_err; int err = 0; int retry = 3; do { if (*file_pos >= file_len) return 1; /* EOF, nothing to do */ fseek(f, *file_pos, SEEK_SET); bytesLeft = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), f); offset = mp3_find_sync_word(mp3_input_buffer, bytesLeft); if (offset < 0) { lprintf("find_sync_word (%i/%i) err %i\n", *file_pos, file_len, offset); *file_pos = file_len; return 1; // EOF } readPtr = mp3_input_buffer + offset; bytesLeft -= offset; had_err = err; err = p_MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0); if (err) { if (err == ERR_MP3_MAINDATA_UNDERFLOW && !had_err) { // just need another frame *file_pos += readPtr - mp3_input_buffer; continue; } if (err == ERR_MP3_INDATA_UNDERFLOW && !had_err) { if (offset == 0) // something's really wrong here, frame had to fit *file_pos = file_len; else *file_pos += offset; continue; } if (-12 <= err && err <= -6) { // ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_* // just try to skip the offending frame.. *file_pos += offset + 1; continue; } lprintf("MP3Decode err (%i/%i) %i\n", *file_pos, file_len, err); *file_pos = file_len; return 1; } *file_pos += readPtr - mp3_input_buffer; } while (err && --retry > 0); return !!err; } int mp3dec_start(FILE *f, int fpos_start) { if (libhelix == NULL) { libhelix = dlopen("./libhelix.so", RTLD_NOW); if (libhelix == NULL) { lprintf("mp3dec: load libhelix.so: %s\n", dlerror()); return -1; } p_MP3InitDecoder = dlsym(libhelix, "MP3InitDecoder"); p_MP3FreeDecoder = dlsym(libhelix, "MP3FreeDecoder"); p_MP3Decode = dlsym(libhelix, "MP3Decode"); if (p_MP3InitDecoder == NULL || p_MP3FreeDecoder == NULL || p_MP3Decode == NULL) { lprintf("mp3dec: missing symbol(s) in libhelix.so\n"); dlclose(libhelix); libhelix = NULL; return -1; } } // must re-init decoder for new track if (mp3dec) p_MP3FreeDecoder(mp3dec); mp3dec = p_MP3InitDecoder(); return (mp3dec == 0) ? -1 : 0; }