// Given a song pointer, this will attempt to free all memory related to the song: midi // data, instruments, samples, etc. It can fail and will return STILL_PLAYING if // midi data is still being accessed, or samples, or instruments. // // If you pass NULL, then this function will be called recursively will all songs // currently playing. OPErr GM_FreeSong(void *threadContext, GM_Song *pSong) { OPErr err; XPTR midiData; err = NO_ERR; GM_EndSong(threadContext, pSong); if (pSong) { GM_KillSongNotes(pSong); // we must kill the notes because we are about to free // instrument memory if (pSong->processingSlice == FALSE) { GM_PauseSong(pSong); midiData = (XPTR)pSong->midiData; // save midi pointer now pSong->midiData = NULL; // and disable midi decoder now, just // in case the decoder thread comes to life GM_SetCacheSamples(pSong, FALSE); err = GM_UnloadSongInstruments(pSong); if (err == NO_ERR) { if (pSong->disposeSongDataWhenDone) { XDisposePtr(midiData); } XDisposePtr((XPTR)pSong->controllerCallback); #if 0 && USE_CREATION_API == TRUE if (pSong->pPatchInfo) { PV_FreePatchInfo(pSong); // must free before killing pSong pointer } #endif XDisposePtr((XPTR)pSong); } else { //DebugStr("\pGM_FreeSong::GM_UnloadSongInstruments::STILL_PLAYING"); } } else { //DebugStr("\pGM_FreeSong::STILL_PLAYING"); err = STILL_PLAYING; } } return err; }
JNIEXPORT void JNICALL Java_com_sun_media_sound_AbstractPlayer_nClose(JNIEnv* e, jobject thisObj, jlong id) { GM_Song *pSong = (GM_Song *) (INT_PTR) id; OPErr err; int waitTime; TRACE3("Java_com_sun_media_sound_AbstractPlayer_nClose: e: %lu, thisObj: %lu, pSong: %lu.\n", e, thisObj, (UINT32) id); if (pSong) { GM_KillSongNotes(pSong); pSong->disposeSongDataWhenDone = TRUE; // free our midi pointer GM_PauseSong(pSong); /* remove song from list of playing songs */ GM_RemoveFromSongsToPlay(pSong); /* set to impossible scan mode to disable processing */ pSong->AnalyzeMode = (ScanMode) -1; /* fix for 4795377: closing sequencer sometimes crashes the VM */ QGM_ClearSongFromQueue(pSong); /* wait until there was at least one mixer slice * processed so that the song notes are really * not used anymore */ waitTime = HAE_GetSliceTimeInMicroseconds()/1000 + 5; TRACE1("nClose: waiting %d millis to process GM_KillSongNotes...\n", waitTime); SleepMillisInJava(e, waitTime); do { /* this may fail - wait until it was able to kill the song */ err = GM_FreeSong((void *)e, pSong); if (err == STILL_PLAYING) { ERROR0("nClose: STILL_PLAYING! wait 5 millis...\n"); SleepMillisInJava(e, 5); } else if (err != NO_ERR) { ERROR1("nClose: GM_FreeSong returned error code: %d\n", err); } } while (err == STILL_PLAYING); } else { ERROR0("Java_com_sun_media_sound_AbstractPlayer_nClose: pSong is NULL\n"); } TRACE0("Java_com_sun_media_sound_AbstractPlayer_nClose completed.\n"); }
JNIEXPORT void JNICALL Java_com_sun_media_sound_MixerSynth_nDestroySynthesizer(JNIEnv* e, jobject thisObj, jlong id) { GM_Song *pSong = (GM_Song *) (INT_PTR) id; TRACE0("Java_com_sun_media_sound_MixerSynth_nDestroySynthesizer.\n"); if (pSong) { GM_KillSongNotes(pSong); pSong->disposeSongDataWhenDone = TRUE; // free our midi pointer GM_FreeSong((void *)e, pSong); } else { ERROR0("pSong is NULL\n"); } TRACE0("Java_com_sun_media_sound_MixerSynth_nDestroySynthesizer completed.\n"); }