Example #1
0
// 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;
}
Example #2
0
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");
}
Example #3
0
// Set the song position in midi ticks
OPErr GM_SetSongTickPosition(GM_Song *pSong, UINT32 songTickPosition)
{
    GM_Song		*theSong;
    OPErr		theErr;
    XBOOL	foundPosition;
    INT32		count;

    theErr = NO_ERR;
    theSong = (GM_Song *)XNewPtr((INT32)sizeof(GM_Song));
    if (theSong)
	{
	    *theSong = *pSong;
	    PV_ClearSongInstruments(theSong);		// don't free the instruments

	    if (PV_ConfigureMusic(theSong) == NO_ERR)
		{
		    theSong->AnalyzeMode = SCAN_DETERMINE_LENGTH;
		    theSong->SomeTrackIsAlive = TRUE;

		    theSong->loopSong = FALSE;
		    foundPosition = FALSE;
		    GM_PauseSong(pSong);
		    while (theSong->SomeTrackIsAlive)
			{
				// don't need a thread context here because we don't callback
			    theErr = PV_ProcessMidiSequencerSlice(NULL, theSong);
			    if (theErr)
				{
				    break;
				}
			    if (theSong->CurrentMidiClock > (UFLOAT)songTickPosition)
				{
				    foundPosition = TRUE;
				    break;
				}
			}
		    theSong->AnalyzeMode = SCAN_NORMAL;
		    theSong->loopSong = pSong->loopSong;
		    if (foundPosition)
			{
			    for (count = 0; count < (MAX_INSTRUMENTS*MAX_BANKS); count++)
				{
				    theSong->instrumentData[count] = pSong->instrumentData[count];
				}

				// $$kk: 07.20.99: this should be called through the synth function pointer.
				// but i don't think it needs to be called at all 'cause the song gets paused...?
				// GM_EndSongNotes(pSong);

			    *pSong = *theSong;		// copy over all song information at the new position
			    PV_ClearSongInstruments(theSong);		// don't free the instruments

			    GM_ResumeSong(pSong);
			}
		    // free duplicate song
		    theSong->midiData = NULL;
		    theSong->disposeSongDataWhenDone = FALSE;
		    theSong->songEndCallbackPtr = NULL;
		    theSong->songTimeCallbackPtr = NULL;
		    theSong->metaEventCallbackPtr = NULL;
		    theSong->controllerCallback = NULL;
		}
	    // don't need a thread context here because we don't callback
	    GM_FreeSong(NULL, theSong);	// we ignore the error codes, because it should be ok to dispose
	    // since this song was never engaged
	}
    return theErr;
}
Example #4
0
// Set the song position in microseconds
// $$kk: 08.12.98 merge: changed this method
OPErr GM_SetSongMicrosecondPosition(GM_Song *pSong, UINT32 songMicrosecondPosition)
{
    GM_Song		*theSong;
    OPErr		theErr;
    XBOOL	foundPosition;
    INT32		count;
    XBOOL	songPaused = FALSE;

    // $$kk: 02.10.98
    // the way this was, it paused the song, changed the position, and resumed.
    // if this is applied to a paused song, it suddenly starts playing again!
    // i am adding a mechanism to record whether the song was paused and only
    // resume it in that case.

    theErr = NO_ERR;
    theSong = (GM_Song *)XNewPtr((INT32)sizeof(GM_Song));
    if (theSong)
	{
	    *theSong = *pSong;
	    PV_ClearSongInstruments(theSong);		// don't free the instruments

	    if (PV_ConfigureMusic(theSong) == NO_ERR)
		{
		    theSong->AnalyzeMode = SCAN_DETERMINE_LENGTH;
		    theSong->SomeTrackIsAlive = TRUE;

		    theSong->loopSong = FALSE;
		    foundPosition = FALSE;

		    // $$kk: 02.10.98: keep track of whether song is paused
		    if (pSong->songPaused)
			songPaused = TRUE;

		    GM_PauseSong(pSong);
		    while (theSong->SomeTrackIsAlive)
			{
				// don't need a thread context here because we don't callback
			    theErr = PV_ProcessMidiSequencerSlice(NULL, theSong);
			    if (theErr)
				{
				    break;
				}
			    if (theSong->songMicroseconds > (UFLOAT)songMicrosecondPosition)
				{
				    foundPosition = TRUE;
				    break;
				}
			}
		    theSong->AnalyzeMode = SCAN_NORMAL;
		    theSong->loopSong = pSong->loopSong;
		    if (foundPosition)
			{
			    for (count = 0; count < (MAX_INSTRUMENTS*MAX_BANKS); count++)
				{
				    theSong->instrumentData[count] = pSong->instrumentData[count];
				}

				// $$kk: 07.20.99: this should be called through the synth function pointer.
				// but i don't think it needs to be called at all 'cause the song gets paused...?
				// GM_EndSongNotes(pSong);

			    *pSong = *theSong;		// copy over all song information at the new position
			    PV_ClearSongInstruments(theSong);		// don't free the instruments

				// $$kk: 02.10.98: do not resume if song was paused before
			    if (!songPaused)
				{
				    GM_ResumeSong(pSong);
				}
			}
		    // free duplicate song
		    theSong->midiData = NULL;
		    theSong->songEndCallbackPtr = NULL;
		    theSong->disposeSongDataWhenDone = FALSE;
		}
	    // don't need a thread context here because we don't callback
	    GM_FreeSong(NULL, theSong);	// we ignore the error codes, because it should be ok to dispose
	    // since this song was never engaged
	}
    return theErr;
}