GmeDecoder::GmeDecoder(Data *data, const std::string &ext, int bufferSize) : Decoder(data, ext, bufferSize) , emu(0) , num_tracks(0) , cur_track(0) { void *d = data->getData(); int s = data->getSize(); if (gme_open_data(d, s, &emu, sampleRate) != 0) throw love::Exception("Could not open game music file"); num_tracks = gme_track_count(emu); try { if (num_tracks <= 0) throw love::Exception("Game music file has no tracks"); if (gme_start_track(emu, cur_track) != 0) throw love::Exception("Could not start game music playback"); } catch (love::Exception &) { gme_delete(emu); throw; } }
jint Java_de_illogical_modo_SpcDecoder_spcPlayRSN(JNIEnv* env, jclass clazz, jint track) { if (track < 0 || track >= rsnCount) return 0; if (rsnEntries[track] == NULL) return 0; if (rsnSize[track] <= 0) return 0; gme_err_t err = gme_open_data(rsnEntries[track], rsnSize[track], &emu, 44100); if (err != NULL) { emu = NULL; } else { gme_start_track(emu, 0); } return emu != NULL; }
static int read_header_gme(AVFormatContext *s) { AVStream *st; AVIOContext *pb = s->pb; GMEContext *gme = s->priv_data; int64_t sz = avio_size(pb); char *buf; char dummy; if (sz < 0) { av_log(s, AV_LOG_WARNING, "Could not determine file size\n"); sz = gme->max_size; } else if (gme->max_size && sz > gme->max_size) { sz = gme->max_size; } buf = av_malloc(sz); if (!buf) return AVERROR(ENOMEM); sz = avio_read(pb, buf, sz); // Data left means our buffer (the max_size option) is too small if (avio_read(pb, &dummy, 1) == 1) { av_log(s, AV_LOG_ERROR, "File size is larger than max_size option " "value %"PRIi64", consider increasing the max_size option\n", gme->max_size); return AVERROR_BUFFER_TOO_SMALL; } if (gme_open_data(buf, sz, &gme->music_emu, gme->sample_rate)) { av_freep(&buf); return AVERROR_INVALIDDATA; } av_freep(&buf); if (gme_track_info(gme->music_emu, &gme->info, gme->track_index)) return AVERROR_STREAM_NOT_FOUND; if (gme_start_track(gme->music_emu, gme->track_index)) return AVERROR_UNKNOWN; load_metadata(s); st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); if (st->duration > 0) st->duration = gme->info->length; st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE); st->codecpar->channels = 2; st->codecpar->sample_rate = gme->sample_rate; return 0; }
jint Java_de_illogical_modo_SpcDecoder_spcLoadFromZip(JNIEnv* env, jclass clazz, jstring zipfile, jstring entry) { char* data = NULL; int size = 0; char czipfile[1024]; char centry[1024]; memset(czipfile, 0, 1024); int clen = (*env)->GetStringLength(env, zipfile); if (clen > 1023) return 0; (*env)->GetStringUTFRegion(env, zipfile, 0, clen, czipfile); memset(centry, 0, 1024); clen = (*env)->GetStringLength(env, entry); if (clen > 1023) return 0; (*env)->GetStringUTFRegion(env, entry, 0, clen, centry); data = getUncompressedData(czipfile, centry, &size); if (data == NULL) return 0; // GME copies memory gme_err_t err = gme_open_data(data, size, &emu, 44100); free(data); if (err != NULL) { emu = NULL; } else { gme_start_track(emu, 0); } if (emu != NULL) return size; return 0; }
JNIEXPORT jlong JNICALL Java_com_ssb_droidsound_plugins_GMEPlugin_N_1load(JNIEnv *env, jobject obj, jbyteArray bArray, int size) { jbyte *ptr = env->GetByteArrayElements(bArray, NULL); Music_Emu *emu = NULL; jlong rc = 0; __android_log_print(ANDROID_LOG_VERBOSE, "GMEPlugin", "open %p %d", ptr, size); gme_err_t err = gme_open_data(ptr, size, &emu, 44100); __android_log_print(ANDROID_LOG_VERBOSE, "GMEPlugin", "Done ERR '%s'", err); if(!err) { rc = setUp(emu); } env->ReleaseByteArrayElements(bArray, ptr, 0); return rc; }
static int gme_probe(metadata_t *md, const char *url, fa_handle_t *fh) { uint8_t b4[4], *buf; gme_err_t err; Music_Emu *emu; gme_info_t *info; int tracks; size_t size; const char *type; if(fa_read(fh, b4, 4) != 4) return 0; type = gme_identify_header(b4); if(*type == 0) return 0; size = fa_fsize(fh); if(size == -1) return -1; buf = malloc(size); fa_seek(fh, 0, SEEK_SET); if(fa_read(fh, buf, size) != size) { free(buf); return 0; } err = gme_open_data(buf, size, &emu, gme_info_only); free(buf); if(err != NULL) return 0; err = gme_track_info(emu, &info, 0); if(err != NULL) { gme_delete(emu); return 0; } tracks = gme_track_count(emu); #if 0 printf("tracks : %d\n", tracks); printf("system : %s\n", info->system); printf("game : %s\n", info->game); printf("song : %s\n", info->song); printf("author : %s\n", info->author); printf("copyright: %s\n", info->copyright); printf("comment : %s\n", info->comment); printf("dumper : %s\n", info->dumper); #endif if(tracks == 1) { md->md_title = info->song[0] ? rstr_alloc(info->song) : NULL; md->md_album = info->game[0] ? rstr_alloc(info->game) : NULL; md->md_artist = info->author[0] ? rstr_alloc(info->author) : NULL; md->md_duration = info->play_length / 1000.0; md->md_contenttype = CONTENT_AUDIO; } else { md->md_title = info->game[0] ? rstr_alloc(info->game) : NULL; md->md_artist = info->author[0] ? rstr_alloc(info->author) : NULL; md->md_contenttype = CONTENT_ALBUM; metdata_set_redirect(md, "gmefile://%s/", url); } gme_free_info(info); gme_delete(emu); return 1; }
boolean I_StartDigSong(const char *musicname, boolean looping) { char *data; size_t len; FMOD_CREATESOUNDEXINFO fmt; lumpnum_t lumpnum = W_CheckNumForName(va("O_%s",musicname)); if (lumpnum == LUMPERROR) { lumpnum = W_CheckNumForName(va("D_%s",musicname)); if (lumpnum == LUMPERROR) return false; midimode = true; } else midimode = false; data = (char *)W_CacheLumpNum(lumpnum, PU_MUSIC); len = W_LumpLength(lumpnum); memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO)); fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); #ifdef HAVE_LIBGME if ((UINT8)data[0] == 0x1F && (UINT8)data[1] == 0x8B) { #ifdef HAVE_ZLIB UINT8 *inflatedData; size_t inflatedLen; z_stream stream; int zErr; // Somewhere to handle any error messages zlib tosses out memset(&stream, 0x00, sizeof (z_stream)); // Init zlib stream // Begin the inflation process inflatedLen = *(UINT32 *)(data + (len-4)); // Last 4 bytes are the decompressed size, typically inflatedData = (UINT8 *)Z_Calloc(inflatedLen, PU_MUSIC, NULL); // Make room for the decompressed data stream.total_in = stream.avail_in = len; stream.total_out = stream.avail_out = inflatedLen; stream.next_in = (UINT8 *)data; stream.next_out = inflatedData; zErr = inflateInit2(&stream, 32 + MAX_WBITS); if (zErr == Z_OK) // We're good to go { zErr = inflate(&stream, Z_FINISH); if (zErr == Z_STREAM_END) { // Run GME on new data if (!gme_open_data(inflatedData, inflatedLen, &gme, 44100)) { gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around Z_Free(data); // We don't need this, either. gme_start_track(gme, 0); current_track = 0; gme_set_equalizer(gme,&gmeq); fmt.format = FMOD_SOUND_FORMAT_PCM16; fmt.defaultfrequency = 44100; fmt.numchannels = 2; fmt.length = -1; fmt.decodebuffersize = (44100 * 2) / 35; fmt.pcmreadcallback = GMEReadCallback; fmt.userdata = gme; FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER | (looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream)); FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); FMR(FMOD_Channel_SetPriority(music_channel, 0)); return true; } } else { const char *errorType; switch (zErr) { case Z_ERRNO: errorType = "Z_ERRNO"; break; case Z_STREAM_ERROR: errorType = "Z_STREAM_ERROR"; break; case Z_DATA_ERROR: errorType = "Z_DATA_ERROR"; break; case Z_MEM_ERROR: errorType = "Z_MEM_ERROR"; break; case Z_BUF_ERROR: errorType = "Z_BUF_ERROR"; break; case Z_VERSION_ERROR: errorType = "Z_VERSION_ERROR"; break; default: errorType = "unknown error"; } CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg); } (void)inflateEnd(&stream); } else // Hold up, zlib's got a problem { const char *errorType; switch (zErr) { case Z_ERRNO: errorType = "Z_ERRNO"; break; case Z_STREAM_ERROR: errorType = "Z_STREAM_ERROR"; break; case Z_DATA_ERROR: errorType = "Z_DATA_ERROR"; break; case Z_MEM_ERROR: errorType = "Z_MEM_ERROR"; break; case Z_BUF_ERROR: errorType = "Z_BUF_ERROR"; break; case Z_VERSION_ERROR: errorType = "Z_VERSION_ERROR"; break; default: errorType = "unknown error"; } CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg); } Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up #else //CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); #endif } else if (!gme_open_data(data, len, &gme, 44100)) { gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; Z_Free(data); // We don't need this anymore. gme_start_track(gme, 0); current_track = 0; gme_set_equalizer(gme,&gmeq); fmt.format = FMOD_SOUND_FORMAT_PCM16; fmt.defaultfrequency = 44100; fmt.numchannels = 2; fmt.length = -1; fmt.decodebuffersize = (44100 * 2) / 35; fmt.pcmreadcallback = GMEReadCallback; fmt.userdata = gme; FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER | (looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream)); FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); FMR(FMOD_Channel_SetPriority(music_channel, 0)); return true; } #endif fmt.length = len; { FMOD_RESULT e = FMOD_System_CreateStream(fsys, data, FMOD_OPENMEMORY_POINT|(looping ? FMOD_LOOP_NORMAL : 0), &fmt, &music_stream); if (e != FMOD_OK) { if (e == FMOD_ERR_FORMAT) CONS_Alert(CONS_WARNING, "Failed to play music lump %s due to invalid format.\n", W_CheckNameForNum(lumpnum)); else FMR(e); return false; } } FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); if (midimode) FMR(FMOD_Channel_SetVolume(music_channel, midi_volume / 31.0)); else FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); FMR(FMOD_Channel_SetPriority(music_channel, 0)); current_track = 0; // Try to find a loop point in streaming music formats (ogg, mp3) if (looping) { FMOD_RESULT e; FMOD_TAG tag; unsigned int loopstart, loopend; // A proper LOOPPOINT is its own tag, stupid. e = FMOD_Sound_GetTag(music_stream, "LOOPPOINT", 0, &tag); if (e != FMOD_ERR_TAGNOTFOUND) { FMR(e); loopstart = atoi((char *)tag.data); // assumed to be a string data tag. FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); if (loopstart > 0) FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); return true; } // Use LOOPMS for time in miliseconds. e = FMOD_Sound_GetTag(music_stream, "LOOPMS", 0, &tag); if (e != FMOD_ERR_TAGNOTFOUND) { FMR(e); loopstart = atoi((char *)tag.data); // assumed to be a string data tag. FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_MS, &loopend, FMOD_TIMEUNIT_PCM)); if (loopstart > 0) FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_MS, loopend, FMOD_TIMEUNIT_PCM)); return true; } // Try to fetch it from the COMMENT tag, like A.J. Freda e = FMOD_Sound_GetTag(music_stream, "COMMENT", 0, &tag); if (e != FMOD_ERR_TAGNOTFOUND) { char *loopText; // Handle any errors that arose, first FMR(e); // Figure out where the number starts loopText = strstr((char *)tag.data,"LOOPPOINT="); if (loopText != NULL) { // Skip the "LOOPPOINT=" part. loopText += 10; // Convert it to our looppoint // FMOD seems to ensure the tag is properly NULL-terminated. // atoi will stop when it reaches anything that's not a number. loopstart = atoi(loopText); // Now do the rest like above FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); if (loopstart > 0) FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); } return true; } } // No special loop point, but we're playing so it's all good. return true; }
void *I_GetSfx(sfxinfo_t *sfx) { FMOD_SOUND *sound; char *lump; FMOD_CREATESOUNDEXINFO fmt; #ifdef HAVE_LIBGME Music_Emu *emu; gme_info_t *info; #endif if (sfx->lumpnum == LUMPERROR) sfx->lumpnum = S_GetSfxLumpNum(sfx); sfx->length = W_LumpLength(sfx->lumpnum); lump = W_CacheLumpNum(sfx->lumpnum, PU_SOUND); sound = ds2fmod(lump); if (sound) { Z_Free(lump); return sound; } // It's not a doom sound. // Try to read it as an FMOD sound? memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO)); fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); fmt.length = sfx->length; #ifdef HAVE_LIBGME // VGZ format if ((UINT8)lump[0] == 0x1F && (UINT8)lump[1] == 0x8B) { #ifdef HAVE_ZLIB UINT8 *inflatedData; size_t inflatedLen; z_stream stream; int zErr; // Somewhere to handle any error messages zlib tosses out memset(&stream, 0x00, sizeof (z_stream)); // Init zlib stream // Begin the inflation process inflatedLen = *(UINT32 *)(lump + (sfx->length-4)); // Last 4 bytes are the decompressed size, typically inflatedData = (UINT8 *)Z_Malloc(inflatedLen, PU_SOUND, NULL); // Make room for the decompressed data stream.total_in = stream.avail_in = sfx->length; stream.total_out = stream.avail_out = inflatedLen; stream.next_in = (UINT8 *)lump; stream.next_out = inflatedData; zErr = inflateInit2(&stream, 32 + MAX_WBITS); if (zErr == Z_OK) // We're good to go { zErr = inflate(&stream, Z_FINISH); if (zErr == Z_STREAM_END) { // Run GME on new data if (!gme_open_data(inflatedData, inflatedLen, &emu, 44100)) { Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around Z_Free(lump); // We're done with the uninflated lump now, too. gme_start_track(emu, 0); gme_track_info(emu, &info, 0); fmt.format = FMOD_SOUND_FORMAT_PCM16; fmt.defaultfrequency = 44100; fmt.numchannels = 2; fmt.length = ((UINT32)info->play_length * 441 / 10) * 4; fmt.decodebuffersize = (44100 * 2) / 35; fmt.pcmreadcallback = GMEReadCallback; fmt.userdata = emu; FMR(FMOD_System_CreateSound(fsys, NULL, FMOD_CREATESAMPLE|FMOD_OPENUSER|FMOD_SOFTWARE|FMOD_LOWMEM, &fmt, &sound)); return sound; } } else { const char *errorType; switch (zErr) { case Z_ERRNO: errorType = "Z_ERRNO"; break; case Z_STREAM_ERROR: errorType = "Z_STREAM_ERROR"; break; case Z_DATA_ERROR: errorType = "Z_DATA_ERROR"; break; case Z_MEM_ERROR: errorType = "Z_MEM_ERROR"; break; case Z_BUF_ERROR: errorType = "Z_BUF_ERROR"; break; case Z_VERSION_ERROR: errorType = "Z_VERSION_ERROR"; break; default: errorType = "unknown error"; } CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg); } (void)inflateEnd(&stream); } else // Hold up, zlib's got a problem { const char *errorType; switch (zErr) { case Z_ERRNO: errorType = "Z_ERRNO"; break; case Z_STREAM_ERROR: errorType = "Z_STREAM_ERROR"; break; case Z_DATA_ERROR: errorType = "Z_DATA_ERROR"; break; case Z_MEM_ERROR: errorType = "Z_MEM_ERROR"; break; case Z_BUF_ERROR: errorType = "Z_BUF_ERROR"; break; case Z_VERSION_ERROR: errorType = "Z_VERSION_ERROR"; break; default: errorType = "unknown error"; } CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg); } Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up #else //CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); #endif } // Try to read it as a GME sound else if (!gme_open_data(lump, sfx->length, &emu, 44100)) { Z_Free(lump); gme_start_track(emu, 0); gme_track_info(emu, &info, 0); fmt.format = FMOD_SOUND_FORMAT_PCM16; fmt.defaultfrequency = 44100; fmt.numchannels = 2; fmt.length = ((UINT32)info->play_length * 441 / 10) * 4; fmt.decodebuffersize = (44100 * 2) / 35; fmt.pcmreadcallback = GMEReadCallback; fmt.userdata = emu; gme_free_info(info); FMR(FMOD_System_CreateSound(fsys, NULL, FMOD_CREATESAMPLE|FMOD_OPENUSER|FMOD_SOFTWARE|FMOD_LOWMEM, &fmt, &sound)); return sound; } #endif // Ogg, Mod, Midi, etc. FMR(FMOD_System_CreateSound(fsys, lump, FMOD_CREATESAMPLE|FMOD_OPENMEMORY|FMOD_SOFTWARE|FMOD_LOWMEM, &fmt, &sound)); Z_Free(lump); // We're done with the lump now, at least. return sound; }
static event_t * fa_gme_playfile_internal(media_pipe_t *mp, const void *buf, size_t size, char *errbuf, size_t errlen, int hold, int track, const char *url) { media_queue_t *mq = &mp->mp_audio; Music_Emu *emu; gme_err_t err; int sample_rate = 48000; media_buf_t *mb = NULL; event_t *e; int registered_play = 0; err = gme_open_data(buf, size, &emu, sample_rate); if(err != NULL) { snprintf(errbuf, errlen, "Unable to load file -- %s", err); return NULL; } gme_start_track(emu, track); mp->mp_audio.mq_stream = 0; mp_configure(mp, MP_PLAY_CAPS_PAUSE | MP_PLAY_CAPS_SEEK, MP_BUFFER_SHALLOW, 0); mp_become_primary(mp); while(1) { if(gme_track_ended(emu)) { e = event_create_type(EVENT_EOF); break; } if(mb == NULL) { mb = media_buf_alloc_unlocked(mp, sizeof(int16_t) * CHUNK_SIZE * 2); mb->mb_data_type = MB_AUDIO; mb->mb_channels = 2; mb->mb_rate = sample_rate; mb->mb_pts = gme_tell(emu) * 1000; mb->mb_drive_clock = 1; if(!registered_play && mb->mb_pts > METADB_AUDIO_PLAY_THRESHOLD) { registered_play = 1; metadb_register_play(url, 1, CONTENT_AUDIO); } gme_play(emu, CHUNK_SIZE * mb->mb_channels, mb->mb_data); } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_type(e, EVENT_SEEK)) { event_ts_t *ets = (event_ts_t *)e; gme_seek(emu, ets->ts / 1000); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SKIP_BACKWARD) || event_is_action(e, ACTION_SKIP_FORWARD) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } gme_delete(emu); if(mb != NULL) media_buf_free_unlocked(mp, mb); return e; }
static gboolean gme_setup (GstGmeDec * gme) { gme_info_t *info; gme_err_t gme_err = NULL; GstTagList *taglist; guint64 total_duration; guint64 fade_time; GstBuffer *buffer; GstSegment seg; GstMapInfo map; if (!gst_adapter_available (gme->adapter) || !gme_negotiate (gme)) { return FALSE; } buffer = gst_adapter_take_buffer (gme->adapter, gst_adapter_available (gme->adapter)); gst_buffer_map (buffer, &map, GST_MAP_READ); gme_err = gme_open_data (map.data, map.size, &gme->player, 32000); gst_buffer_unmap (buffer, &map); gst_buffer_unref (buffer); if (gme_err || !gme->player) { if (gme->player) { gme_delete (gme->player); gme->player = NULL; } GST_ELEMENT_ERROR (gme, STREAM, DEMUX, (NULL), ("%s", gme_err)); return FALSE; } gme_err = gme_track_info (gme->player, &info, 0); taglist = gst_tag_list_new_empty (); if (info->song && *info->song) gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, info->song, NULL); if (info->author && *info->author) gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ARTIST, info->author, NULL); /* Prefer the name of the official soundtrack over the name of the game (since this is * how track numbers are derived) */ if (info->game && *info->game) gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ALBUM, info->game, NULL); if (info->comment && *info->comment) gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_COMMENT, info->comment, NULL); if (info->dumper && *info->dumper) gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_CONTACT, info->dumper, NULL); if (info->copyright && *info->copyright) gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_COPYRIGHT, info->copyright, NULL); if (info->system && *info->system) gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, info->system, NULL); gme->total_duration = total_duration = gst_util_uint64_scale_int (info->play_length + (info->loop_length > 0 ? 8000 : 0), GST_MSECOND, 1); fade_time = info->loop_length > 0 ? info->play_length : 0; gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DURATION, total_duration, NULL); gst_pad_push_event (gme->srcpad, gst_event_new_tag (taglist)); g_free (info); #ifdef HAVE_LIBGME_ACCURACY /* TODO: Is it worth it to make this optional? */ gme_enable_accuracy (gme->player, 1); #endif gme_start_track (gme->player, 0); if (fade_time) gme_set_fade (gme->player, fade_time); gst_segment_init (&seg, GST_FORMAT_TIME); gst_pad_push_event (gme->srcpad, gst_event_new_segment (&seg)); gst_pad_start_task (gme->srcpad, (GstTaskFunction) gst_gme_play, gme->srcpad, NULL); gme->initialized = TRUE; gme->seeking = FALSE; gme->seekpoint = 0; return gme->initialized; }
static event_t * fa_gme_playfile_internal(media_pipe_t *mp, void *fh, char *errbuf, size_t errlen, int hold, int track) { media_queue_t *mq = &mp->mp_audio; Music_Emu *emu; gme_err_t err; char *buf; int lost_focus = 0; size_t size, r; int sample_rate = 48000; media_buf_t *mb = NULL; event_t *e; size = fa_fsize(fh); buf = malloc(size); r = fa_read(fh, buf, size); if(r != size) { snprintf(errbuf, errlen, "Unable to read file"); free(buf); return NULL; } err = gme_open_data(buf, size, &emu, sample_rate); free(buf); if(err != NULL) { snprintf(errbuf, errlen, "Unable to load file -- %s", err); return NULL; } gme_start_track(emu, track); mp_set_playstatus_by_hold(mp, hold, NULL); mp->mp_audio.mq_stream = 0; mp_set_play_caps(mp, MP_PLAY_CAPS_PAUSE | MP_PLAY_CAPS_SEEK); mp_become_primary(mp); while(1) { if(gme_track_ended(emu)) { e = event_create_type(EVENT_EOF); break; } if(mb == NULL) { mb = media_buf_alloc(); mb->mb_data_type = MB_AUDIO; mb->mb_channels = 2; mb->mb_size = sizeof(int16_t) * CHUNK_SIZE * mb->mb_channels; mb->mb_data = malloc(mb->mb_size); mb->mb_rate = sample_rate; mb->mb_time = gme_tell(emu) * 1000; gme_play(emu, CHUNK_SIZE * mb->mb_channels, mb->mb_data); } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_type(e, EVENT_SEEK)) { event_ts_t *ets = (event_ts_t *)e; gme_seek(emu, ets->pts / 1000); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FAST_BACKWARD)) { deltaseek(mp, &mb, emu, -60000); } else if(event_is_action(e, ACTION_SEEK_BACKWARD)) { deltaseek(mp, &mb, emu, -15000); } else if(event_is_action(e, ACTION_SEEK_FAST_FORWARD)) { deltaseek(mp, &mb, emu, 60000); } else if(event_is_action(e, ACTION_SEEK_FORWARD)) { deltaseek(mp, &mb, emu, 15000); } else if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { hold = action_update_hold_by_event(hold, e); mp_send_cmd_head(mp, mq, hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); lost_focus = 0; mp_set_playstatus_by_hold(mp, hold, NULL); } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { hold = 1; lost_focus = 1; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(lost_focus) { hold = 0; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { hold = 1; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } gme_delete(emu); if(mb != NULL) media_buf_free(mb); if(hold) { // If we were paused, release playback again. mp_send_cmd(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, 0, NULL); } return e; }
static DB_playItem_t * cgme_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { Music_Emu *emu; trace ("gme_open_file %s\n", fname); gme_err_t res = "gme uninitialized"; const char *ext = strrchr (fname, '.'); char *buffer; int sz; if (!read_gzfile (fname, &buffer, &sz)) { res = gme_open_data (fname, buffer, sz, &emu, gme_info_only); free (buffer); } if (res) { DB_FILE *f = deadbeef->fopen (fname); if (!f) { return NULL; } int64_t sz = deadbeef->fgetlength (f); if (sz <= 0) { deadbeef->fclose (f); return NULL; } char *buf = malloc (sz); if (!buf) { deadbeef->fclose (f); return NULL; } int64_t rb = deadbeef->fread (buf, 1, sz, f); deadbeef->fclose(f); if (rb != sz) { free (buf); return NULL; } res = gme_open_data (fname, buf, sz, &emu, gme_info_only); free (buf); } if (!res) { int cnt = gme_track_count (emu); trace ("track cnt %d\n", cnt); for (int i = 0; i < cnt; i++) { #ifdef GME_VERSION_055 gme_info_t *inf; const char *ret = gme_track_info (emu, &inf, i); #else track_info_t _inf; const char *ret = gme_track_info (emu, &inf, i); track_info_t *inf = &_inf; #endif if (!ret) { DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id); char str[1024]; if (inf->song[0]) { snprintf (str, sizeof(str), "%d %s - %s", i, inf->game, inf->song); } else { snprintf (str, sizeof(str), "%d %s - ?", i, inf->game); } trace ("track subtune %d %s, length=%d\n", i, str, inf->length); deadbeef->pl_set_meta_int (it, ":TRACKNUM", i); // add metadata cgme_add_meta (it, "system", inf->system); cgme_add_meta (it, "album", inf->game); int tl = sizeof (inf->song); int n; for (n = 0; i < tl && inf->song[n] && inf->song[n] == ' '; n++); if (n == tl || !inf->song[n]) { deadbeef->pl_add_meta (it, "title", NULL); } else { cgme_add_meta (it, "title", inf->song); } cgme_add_meta (it, "artist", inf->author); cgme_add_meta (it, "copyright", inf->copyright); cgme_add_meta (it, "comment", inf->comment); cgme_add_meta (it, "dumper", inf->dumper); char trk[10]; snprintf (trk, 10, "%d", i+1); cgme_add_meta (it, "track", trk); snprintf (str, sizeof(str), "%d", inf->length); deadbeef->pl_add_meta (it, ":GME_LENGTH", str); snprintf (str, sizeof(str), "%d", inf->intro_length); deadbeef->pl_add_meta (it, ":GME_INTRO_LENGTH", str); snprintf (str, sizeof(str), "%d", inf->loop_length); deadbeef->pl_add_meta (it, ":GME_LOOP_LENGTH", str); if (inf->length == -1 || inf->length == 0) { float songlength; if (inf->loop_length > 0 && conf_loopcount > 0) { songlength = inf->intro_length / 1000.f; if (songlength < 0) { songlength = 0; } songlength += (inf->loop_length * conf_loopcount) / 1000.f; } else { songlength = deadbeef->conf_get_float ("gme.songlength", 3) * 60.f; } deadbeef->plt_set_item_duration (plt, it, songlength); } else { deadbeef->plt_set_item_duration (plt, it, (float)inf->length/1000.f); } const char *ext = fname + strlen (fname) - 1; while (ext >= fname && *ext != '.') { ext--; } if (*ext == '.') { ext++; for (int i = 0; plugin.exts[i]; i++) { if (!strcasecmp (ext, plugin.exts[i])) { deadbeef->pl_add_meta (it, ":FILETYPE", plugin.exts[i]); break; } } } if (cnt > 1) { deadbeef->pl_set_item_flags (it, deadbeef->pl_get_item_flags (it) | DDB_IS_SUBTRACK); } after = deadbeef->plt_insert_item (plt, after, it); deadbeef->pl_item_unref (it); } else { trace ("gme error: %s\n", ret); } } if (emu) { gme_delete (emu); } } else { trace ("gme_open_file/data failed with error %s\n", res); } return after; }
static int cgme_init (DB_fileinfo_t *_info, DB_playItem_t *it) { gme_fileinfo_t *info = (gme_fileinfo_t*)_info; int samplerate = deadbeef->conf_get_int ("synth.samplerate", 44100); gme_err_t res = "gme uninitialized"; deadbeef->pl_lock (); { const char *fname = deadbeef->pl_find_meta (it, ":URI"); const char *ext = strrchr (fname, '.'); char *buffer; int sz; if (!read_gzfile (fname, &buffer, &sz)) { res = gme_open_data (fname, buffer, sz, &info->emu, samplerate); free (buffer); } if (res) { DB_FILE *f = deadbeef->fopen (fname); if (!f) { deadbeef->pl_unlock (); return -1; } int64_t sz = deadbeef->fgetlength (f); if (sz <= 0) { deadbeef->fclose (f); deadbeef->pl_unlock (); return -1; } char *buf = malloc (sz); if (!buf) { deadbeef->fclose (f); deadbeef->pl_unlock (); return -1; } int64_t rb = deadbeef->fread (buf, 1, sz, f); deadbeef->fclose(f); if (rb != sz) { free (buf); deadbeef->pl_unlock (); return -1; } res = gme_open_data (fname, buf, sz, &info->emu, samplerate); free (buf); } } deadbeef->pl_unlock (); if (res) { trace ("failed with error %d\n", res); return -1; } chip_voices = deadbeef->conf_get_int ("chip.voices", 0xff); gme_mute_voices (info->emu, chip_voices^0xff); gme_start_track (info->emu, deadbeef->pl_find_meta_int (it, ":TRACKNUM", 0)); gme_info_t *inf; gme_track_info (info->emu, &inf, deadbeef->pl_find_meta_int (it, ":TRACKNUM", 0)); _info->plugin = &plugin; _info->fmt.bps = 16; _info->fmt.channels = 2; _info->fmt.samplerate = samplerate; _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT); info->duration = deadbeef->pl_get_item_duration (it); info->reallength = inf->length; _info->readpos = 0; return 0; }
BBString * bmx_gme_open_data( MaxMusicEmu * emu, const void * data, long size, long sample_rate) { return bbStringFromCString(gme_open_data(data, size, &emu->emu, sample_rate)); }
bool GME::open(const QString &_url, bool tracksOnly) { QString prefix, url, param; const bool hasPluginPrefix = Functions::splitPrefixAndUrlIfHasPluginPrefix(_url, &prefix, &url, ¶m); if (tracksOnly == hasPluginPrefix) return false; int track = 0; if (!hasPluginPrefix) { if (url.startsWith(GMEName "://")) return false; url = _url; } else { if (prefix != GMEName) return false; bool ok; track = param.toInt(&ok); if (track < 0 || !ok) return false; } if (Reader::create(url, m_reader)) { const QByteArray data = m_reader->read(m_reader->size()); m_reader.clear(); gme_open_data(data.data(), data.size(), &m_gme, m_srate); if (!m_gme) return false; if (!hasPluginPrefix) { m_aborted = true; m_url = url; return true; } if (track >= gme_track_count(m_gme)) return false; gme_info_t *info = NULL; if (!gme_track_info(m_gme, &info, track) && info) { m_title = getTitle(info, track); m_length = getLength(info); if (*info->game) m_tags << qMakePair(QString::number(QMPLAY2_TAG_TITLE), QString(info->game)); if (*info->author) m_tags << qMakePair(QString::number(QMPLAY2_TAG_ARTIST), QString(info->author)); if (*info->system) m_tags << qMakePair(tr("System"), QString(info->system)); if (*info->copyright) m_tags << qMakePair(tr("Copyright"), QString(info->copyright)); if (*info->comment) m_tags << qMakePair(tr("Comment"), QString(info->comment)); gme_free_info(info); } QString voices; const int numVoices = gme_voice_count(m_gme); for (int i = 0; i < numVoices; ++i) { voices += gme_voice_name(m_gme, i); voices += ", "; } voices.chop(2); m_tags << qMakePair(tr("Voices"), voices); m_tags << qMakePair(tr("Track"), QString::number(track + 1)); streams_info += new StreamInfo(m_srate, 2); gme_set_stereo_depth(m_gme, 0.5); return !gme_start_track(m_gme, track); } return false; }
jint Java_de_illogical_modo_GmeDecoder_gmeLoadFromZip(JNIEnv* env, jclass clazz, jstring zipfile, jstring entry, int vgzfile) { char* data = NULL; int size = 0; char czipfile[1024]; char centry[1024]; memset(czipfile, 0, 1024); int clen = (*env)->GetStringLength(env, zipfile); if (clen > 1023) return 0; (*env)->GetStringUTFRegion(env, zipfile, 0, clen, czipfile); memset(centry, 0, 1024); clen = (*env)->GetStringLength(env, entry); if (clen > 1023) return 0; (*env)->GetStringUTFRegion(env, entry, 0, clen, centry); data = getUncompressedData(czipfile, centry, &size); if (data == NULL) return 0; // If its a .vgz file inflate it. Problem is, can go up to 10MB. GME copies data = 20MB. // kss can also be gzip if (size > 10 && data[0] == 0x1F && data[1] == 0x8B) { unsigned long uncompressed_size = data[size-1] << 24 | data[size-2] << 16 | data[size-3] << 8 | data[size-4]; char* inflatebuffer = malloc(uncompressed_size); if (inflatebuffer != NULL) { int err; z_stream zs; zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.opaque = Z_NULL; zs.next_in = data; zs.avail_in = size; zs.next_out = inflatebuffer; zs.avail_out = uncompressed_size; inflateInit2(&zs, 16 + MAX_WBITS); err = inflate(&zs, Z_FINISH); if (err == Z_STREAM_END) { //__android_log_print(ANDROID_LOG_VERBOSE, "gme", "-> ZLIB STREAM END - extracted Bytes %ld", zs.total_out); size = zs.total_out; free(data); data = inflatebuffer; } else { free(inflatebuffer); } inflateEnd(&zs); } } // GME copies memory gme_err_t err = gme_open_data(data, size, &emu, 44100); free(data); if (err != NULL) { emu = NULL; } else { gme_start_track(emu, 0); gme_set_stereo_depth(emu, depth); } if (emu != NULL) return size; return 0; }
static gboolean xmms_gme_init (xmms_xform_t *xform) { xmms_gme_data_t *data; gme_err_t init_error; GString *file_contents; /* The raw data from the file. */ gme_info_t *metadata = NULL; xmms_config_property_t *val; int loops; int maxlength; const char *subtune_str; int subtune = 0; long fadelen = -1; int samplerate; double stereodepth; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_gme_data_t, 1); xmms_xform_private_data_set (xform, data); val = xmms_xform_config_lookup (xform, "samplerate"); samplerate = xmms_config_property_get_int (val); if (samplerate < 1) samplerate = GME_DEFAULT_SAMPLE_RATE; data->samplerate = samplerate; xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", /* PCM samples */ XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, /* 16-bit signed */ XMMS_STREAM_TYPE_FMT_CHANNELS, 2, /* stereo */ XMMS_STREAM_TYPE_FMT_SAMPLERATE, samplerate, XMMS_STREAM_TYPE_END); file_contents = g_string_new (""); for (;;) { xmms_error_t error; gchar buf[4096]; gint ret; ret = xmms_xform_read (xform, buf, sizeof (buf), &error); if (ret == -1) { XMMS_DBG ("Error reading emulated music data"); return FALSE; } if (ret == 0) { break; } g_string_append_len (file_contents, buf, ret); } init_error = gme_open_data (file_contents->str, file_contents->len, &data->emu, samplerate); g_string_free (file_contents, TRUE); if (init_error) { XMMS_DBG ("gme_open_data returned an error: %s", init_error); return FALSE; } if (xmms_xform_metadata_get_str (xform, "subtune", &subtune_str)) { subtune = strtol (subtune_str, NULL, 10); XMMS_DBG ("Setting subtune to %d", subtune); if ((subtune < 0 || subtune > gme_track_count (data->emu))) { XMMS_DBG ("Invalid subtune index"); return FALSE; } } else { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SUBTUNES, gme_track_count (data->emu)); } /* * Get metadata here */ init_error = gme_track_info (data->emu, &metadata, subtune); if (init_error) { XMMS_DBG ("Couldn't get GME track info: %s", init_error); init_error = ""; } else { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, metadata->song); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, metadata->author); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM, metadata->game); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT, metadata->comment); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR, metadata->copyright); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE, metadata->system); /* I mapped genre to the system type */ val = xmms_xform_config_lookup (xform, "loops"); loops = xmms_config_property_get_int (val); XMMS_DBG ("intro_length = %d, loops = %d, loop_length = %d", metadata->intro_length, loops, metadata->loop_length); if (metadata->intro_length > 0) { if ((loops > 0) && (metadata->loop_length > 0)) { fadelen = metadata->intro_length + loops * metadata->loop_length; XMMS_DBG ("fadelen now = %ld", fadelen); } else { fadelen = metadata->length; XMMS_DBG ("fadelen now = %ld", fadelen); } } } val = xmms_xform_config_lookup (xform, "maxlength"); maxlength = xmms_config_property_get_int (val); XMMS_DBG ("maxlength = %d seconds", maxlength); if (maxlength > 0 && (fadelen < 0 || (maxlength * 1000L < fadelen))) { fadelen = maxlength * 1000L; XMMS_DBG ("fadelen now = %ld", fadelen); } XMMS_DBG ("gme.fadelen = %ld", fadelen); val = xmms_xform_config_lookup (xform, "stereodepth"); stereodepth = xmms_config_property_get_float (val); if (stereodepth >= 0.0 && stereodepth <= 1.0) { XMMS_DBG ("Setting stereo depth to %f.", stereodepth); gme_set_stereo_depth (data->emu, stereodepth); } else { XMMS_DBG ("gme.stereodepth = %f out of range 0.0 - 1.0; not setting.", stereodepth); } init_error = gme_start_track (data->emu, subtune); if (init_error) { XMMS_DBG ("gme_start_track returned an error: %s", init_error); gme_free_info (metadata); return FALSE; } if (fadelen > 0) { XMMS_DBG ("Setting song length and fade length..."); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, fadelen); gme_set_fade (data->emu, fadelen); } gme_free_info (metadata); return TRUE; }
int crPlayerSetTrack(void *context, int track) { gmeContext *gme = (gmeContext*)context; gme_err_t status = NULL; int trueTrack; fileEntry *entry; /* initialize the engine */ if (gme->isGameMusicArchive) { /* when it's time to start a track, it's always going to be * track 0 (first and only) of a single-song file */ trueTrack = 0; /* if a file is already being played, free it first */ if (gme->emu) { gme_delete(gme->emu); gme->emu = NULL; } entry = &gme->entries[track]; status = gme_open_data(gme->dataBuffer + entry->offset, entry->size, &gme->emu, gme->sampleRate); if (status) return 0; } else { trueTrack = track; /* if the player isn't already open, do the initialization */ if (!gme->emu) { status = gme_open_data(gme->dataBuffer, gme->dataBufferSize, &gme->emu, gme->sampleRate); if (status) return 0; } } /* set the track */ status = gme_start_track(gme->emu, trueTrack); if (!status) { gme_type_t type = gme_type(gme->emu); gme->voiceCount = gme_voice_count(gme->emu); /* return either mono or stereo depending on the file type */ if ((type == gme_gbs_type) || (type == gme_spc_type) || (type == gme_vgm_type)) return 2; /* stereo */ else return 1; /* mono */ } else { gme_delete(gme->emu); gme->emu = NULL; return 0; } }
static int gmefile_scandir(fa_dir_t *fd, const char *url, char *errbuf, size_t errlen) { char *p, *fpath = mystrdupa(url); char name[32]; char turl[URL_MAX]; int tracks, i; fa_dir_entry_t *fde; const char *title; Music_Emu *emu; gme_info_t *info; gme_err_t err; if((p = strrchr(fpath, '/')) == NULL) { snprintf(errbuf, errlen, "Invalid filename"); return -1; } *p = 0; buf_t *b; if((b = fa_load(fpath, NULL, errbuf, errlen, NULL, 0, NULL, NULL)) == NULL) return -1; err = gme_open_data(b->b_ptr, b->b_size, &emu, gme_info_only); buf_release(b); if(err != NULL) return 0; tracks = gme_track_count(emu); for(i = 0; i < tracks; i++) { snprintf(turl, sizeof(turl), "gmeplayer:%s/%d", fpath, i + 1); err = gme_track_info(emu, &info, i); if(err == NULL && info->song[0]) { title = info->song; } else { snprintf(name, sizeof(name), "Track %02d", i + 1); title = name; } fde = fa_dir_add(fd, turl, title, CONTENT_AUDIO); fde->fde_probestatus = FDE_PROBE_DEEP; fde->fde_metadata = prop_create_root("metadata"); prop_set_string(prop_create(fde->fde_metadata, "title"), title); if(err == NULL) { if(info->game[0]) prop_set_string(prop_create(fde->fde_metadata, "album"), info->game); if(info->author[0]) prop_set_string(prop_create(fde->fde_metadata, "artist"), info->author); prop_set_float(prop_create(fde->fde_metadata, "duration"), info->play_length / 1000.0); gme_free_info(info); } } gme_delete(emu); return 0; }
struct MUSIC_GME *GME_LoadSongRW(SDL_RWops *src, int trackNum) { if(src != NULL) { void *bytes=0; long spcsize; Sint64 length=0; length = SDL_RWseek(src, 0, RW_SEEK_END); if (length < 0) { Mix_SetError("GAME-EMU: wrong file\n"); return NULL; } SDL_RWseek(src, 0, RW_SEEK_SET); bytes = malloc(length); long bytes_l; unsigned char byte[1]; spcsize=0; while( (bytes_l=SDL_RWread(src, &byte, sizeof(unsigned char), 1))!=0) { ((unsigned char*)bytes)[spcsize] = byte[0]; spcsize++; } if (spcsize == 0) { Mix_SetError("GAME-EMU: wrong file\n"); return NULL; } Music_Emu* game_emu; char *err = (char*)gme_open_data( bytes, spcsize, &game_emu, gme_t_sample_rate ); //spc_load_spc( snes_spc, bytes, spcsize ); free(bytes); if(err!=0) { Mix_SetError("GAME-EMU: %s", err); return NULL; } if((trackNum<0)||(trackNum >= gme_track_count(game_emu))) trackNum = gme_track_count(game_emu)-1; err = (char*)gme_start_track( game_emu, trackNum ); if(err!=0) { Mix_SetError("GAME-EMU: %s", err); return NULL; } struct MUSIC_GME *spcSpec = (struct MUSIC_GME*)malloc(sizeof(struct MUSIC_GME)); spcSpec->game_emu=game_emu; spcSpec->playing=0; spcSpec->gme_t_sample_rate=mixer.freq; spcSpec->volume=MIX_MAX_VOLUME; spcSpec->mus_title=NULL; spcSpec->mus_artist=NULL; spcSpec->mus_album=NULL; spcSpec->mus_copyright=NULL; gme_info_t *musInfo; err = (char*)gme_track_info(spcSpec->game_emu, &musInfo, trackNum); if(err!=0) { gme_delete(spcSpec->game_emu); free(spcSpec); Mix_SetError("GAME-EMU: %s", err); return NULL; } spcSpec->mus_title = (char *)SDL_malloc(sizeof(char)*strlen(musInfo->song)+1); strcpy(spcSpec->mus_title, musInfo->song); spcSpec->mus_artist = (char *)SDL_malloc(sizeof(char)*strlen(musInfo->author)+1); strcpy(spcSpec->mus_artist, musInfo->author); spcSpec->mus_album = (char *)SDL_malloc(sizeof(char)*strlen(musInfo->game)+1); strcpy(spcSpec->mus_album, musInfo->game); spcSpec->mus_copyright = (char *)SDL_malloc(sizeof(char)*strlen(musInfo->copyright)+1); strcpy(spcSpec->mus_copyright, musInfo->copyright); gme_free_info( musInfo ); SDL_BuildAudioCVT(&spcSpec->cvt, AUDIO_S16, 2, mixer.freq, mixer.format, mixer.channels, mixer.freq); return spcSpec; } return NULL; }