Beispiel #1
0
// Increase the number of key splits. This will not clean the entry's that are added.
// This will add from the end. This will freeup the passed InstrumentResource
InstrumentResource * XAddKeySplit(InstrumentResource *theX, short int howMany)
{
    long				size, moveSize, size2;
    short int			total;
    KeySplit 			*pSplits;
    char				*pSrc, *pDest;
    InstrumentResource	*theNewX;

    theNewX = NULL;
    if (theX)
	{
	    total = (short)XGetShort(&theX->keySplitCount);
	    size = XGetPtrSize(theX);
	    size2 =  (long)(sizeof(KeySplit) * howMany);
	    theNewX = (InstrumentResource *)XNewPtr(size2 + size);
	    if (theNewX)
		{
		    XBlockMove(theX, theNewX, size);	// make copy
		    XPutShort(&theNewX->keySplitCount, (unsigned short)(total + howMany));
		    // must move all zones down
		    pSplits = (KeySplit *) ( ((unsigned char *)&theX->keySplitCount) + sizeof(unsigned short int));
		    pSrc = (char *)&pSplits[total];

		    pSplits = (KeySplit *) ( ((unsigned char *)&theNewX->keySplitCount) + sizeof(unsigned short int));
		    pDest = (char *)&pSplits[total + howMany];
		    moveSize =  size - (pSrc - (char *)theX);
		    // this move must handle overlapping data
		    XBlockMove(pSrc, pDest, moveSize);
		}
	}
    return theNewX;
}
Beispiel #2
0
void XTestCompression(XPTR compressedAndEncryptedData, long size, XPTR originalData, long originalSize)
{
    XPTR	pData, pData2;
    short int	safe;

    if (compressedAndEncryptedData && originalData && size && originalSize)
	{
	    // since this is encrypted, make a new copy and decrypt
	    pData = XNewPtr(size);
	    if (pData)
		{
		    XBlockMove(compressedAndEncryptedData, pData, size);
		    XDecryptData(pData, (unsigned long)size);				// decrypt first
		    pData2 = pData;
		    pData = XDecompressPtr(pData2, (unsigned long)size, TRUE);		// uncompress second
		    if (pData)
			{
			    size = XGetPtrSize(pData);	// get new size
			    if (size == originalSize)
				{
				    safe = XMemCmp(pData, originalData, size);
				    if (safe)
					{
					    DebugStr("\pmemcmp failed");
					}
				    else
					{
					    DebugStr("\pSAFE!");
					}
				}
			    else
				{
Beispiel #3
0
// This will place a sample into the sample cache. Used for eMidi files.
void PV_SetSampleIntoCache(GM_Song *pSong, XLongResourceID theID, XPTR pSndFormatData)
{
    register short int	count;
    register void		*pSample;
    CacheSampleInfo		info;

    GM_SetCacheSamples(pSong, TRUE);	// enable caching
    pSample = NULL;
    // first, find out if there is a sample already for this ID
    pSample = PV_FindSoundFromID(theID);
    if (pSample)
	{	// yes, there is so free it
	    count = PV_FindCacheIndexFromPtr(pSample);
	    MusicGlobals->sampleCaches[count]->referenceCount = 1;
	    PV_FreeCacheEntryFromPtr(pSample);
	}
    info.referenceCount = 1;
    pSample = PV_GetSampleData(theID, pSndFormatData, &info);
    if (pSample)
	{
	    for (count = 0; count < MAX_SAMPLES; count++)
		{
		    if (MusicGlobals->sampleCaches[count] == NULL)
			{
			    MusicGlobals->sampleCaches[count] = (CacheSampleInfo *)XNewPtr((INT32)sizeof(CacheSampleInfo));
			    if (MusicGlobals->sampleCaches[count])
				{
				    *MusicGlobals->sampleCaches[count] = info;
				    MusicGlobals->sampleCaches[count]->theID = theID;
				}
			    break;
			}
		}
	}
}
Beispiel #4
0
static GM_Song * PV_CreateSongFromMidi(XLongResourceID theID, XPTR useThisMidiData, INT32 midiSize)
{
    XPTR		theMidiData;
    GM_Song		*theSong;
    INT32		count;

    theSong = NULL;
    if (useThisMidiData)
	{
	    theMidiData = useThisMidiData;
	}
    else
	{
	    midiSize = 0;
	    theMidiData = XGetMidiData(theID, &midiSize, NULL);
	}
    if (theMidiData)
	{
	    theSong = (GM_Song *)XNewPtr((INT32)sizeof(GM_Song));
	    if (theSong)
		{
		    theSong->midiData = theMidiData;
		    theSong->midiSize = midiSize;
		    theSong->disposeSongDataWhenDone = (useThisMidiData == NULL) ? TRUE : FALSE;
		    // Fill in remap first
		    for (count = 0; count < (MAX_INSTRUMENTS*MAX_BANKS); count++)
			{
			    theSong->instrumentRemap[count] = (XLongResourceID)-1;		// no remap
			}
		}
	}
    return theSong;
}
void * mod_realloc(void* ptr, long size)
{
    XPTR	p;

    p = NULL;
    if (ptr)
    {
        p = XNewPtr(size);
        if (p)
        {
            size = XGetPtrSize((XPTR)ptr);	// get old size
            if (size)
            {
                XBlockMove(ptr, p, size);
            }
            else
            {
                XDisposePtr(p);
                p = NULL;	// can't get size, so fail
            }
            XDisposePtr(ptr);
        }
    }
    return p;
}
JNIEXPORT jlong JNICALL
    Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResourceFromByteArray(JNIEnv* e, jobject thisObj, jbyteArray bankData, jint length) 
{
    XFILE file = NULL;
    void	*pData = NULL;

    TRACE0("Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResourceFromByteArray.\n");

    pData = XNewPtr(length); // can have memory error

    if (!pData)
	{
	    ERROR0("Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResourceFromByteArray failed to allocate memory for soundbank\n");
	    return 0;
	}

    (*e)->GetByteArrayRegion(e, bankData, (jint)0, (jint)length, (jbyte*)pData);

    file = XFileOpenResourceFromMemory(pData, length, TRUE);

    if (!file)
	{
	    ERROR0("Failed to create resource file from data \n");
	    XDisposePtr(pData);
	    return 0;
	}

    TRACE1("Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResourceFromByteArray completed, returning %lu.\n", file);

    return (jlong) (INT_PTR) file;
}
// XProcessMPEGEncoder() seems to prepend some number zero samples to the waveform.
// Scan the first frame buffer for the first nonzero sample and
// set *startFrame to the offset to it.
static unsigned long PV_ScanForAudioDataFromMPEG(XPTR pMPEGStream,
													unsigned long mpegStreamSize,
													unsigned long *pFrameBufferCount,
													OPErr *pErr)
{
unsigned long		firstNonSilentFrame;
XMPEGDecodedData	*stream;
OPErr				err;
char				*tempBuffer;
XBOOL				done;

	if (pErr)
	{
		*pErr = NO_ERR;
	}
	firstNonSilentFrame = 0;
	stream = XOpenMPEGStreamFromMemory(pMPEGStream, mpegStreamSize, &err);
	if (stream)
	{
		if (pFrameBufferCount)
		{
			if (stream->maxFrameBuffers > *pFrameBufferCount)
			{
				*pFrameBufferCount = stream->maxFrameBuffers;
			}
		}
		
		tempBuffer = (char *)XNewPtr(stream->frameBufferSize * sizeof(long));
		if (tempBuffer)
		{
			err = XFillMPEGStreamBuffer(stream, tempBuffer, &done);
			if (err == NO_ERR)
			{
				firstNonSilentFrame = PV_ScanForAudioData((short int*)tempBuffer, 
												stream->frameBufferSize, 
												(unsigned long)stream->channels);
			}
			XDisposePtr(tempBuffer);
		}

		XCloseMPEGStream(stream);
	}
	if (pErr)
	{
		*pErr = err;
	}
#if 0
	if (firstNonSilentFrame < 448)	//481
	{
		return 448;
	}
#endif
	return firstNonSilentFrame;
}
Beispiel #8
0
// Get an empty GM_CaptureAudioStream. Will return 0 if can't allocate stream
static void *PV_GetEmptyCaptureAudioStream(void)
{
    GM_CaptureAudioStream	*pStream;
    void *					ref;

    ref = 0;
    pStream = (GM_CaptureAudioStream *)XNewPtr((INT32)sizeof(GM_CaptureAudioStream));
    if (pStream)
	{
	    pStream->reference = (void *)-1;
	    ref = (void *)pStream;
	}
    return ref;
}
Beispiel #9
0
// Create instrument from 'snd' resource ID
static GM_Instrument * PV_CreateInstrumentFromResource(GM_Instrument *theMaster, XLongResourceID theID)
{
    GM_Instrument	*theI;
    UBYTE			*theSound;
    CacheSampleInfo	sndInfo;

    theI = NULL;
    theSound = (UBYTE *)PV_GetSampleFromID(theID, &sndInfo);
    if (theSound)
	{
	    theI = (GM_Instrument *)XNewPtr((INT32)sizeof(GM_Instrument));
	    if (theI)
		{
		    theI->u.w.theWaveform = (SBYTE *)theSound;

		    if (theMaster)
			{
			    theI->disableSndLooping = theMaster->disableSndLooping;
			    theI->playAtSampledFreq = theMaster->playAtSampledFreq;
			    theI->doKeymapSplit = FALSE;
			    theI->notPolyphonic = theMaster->notPolyphonic;
			    theI->avoidReverb = theMaster->avoidReverb;
			    theI->useSampleRate = theMaster->useSampleRate;
			    theI->sampleAndHold = theMaster->sampleAndHold;
			}
		    else
			{
			    theI->disableSndLooping = FALSE;
			    theI->playAtSampledFreq = FALSE;
			    theI->doKeymapSplit = FALSE;
			    theI->notPolyphonic = FALSE;
			    theI->avoidReverb = FALSE;
			    theI->useSampleRate = FALSE;
			    theI->sampleAndHold = FALSE;
			}
		    theI->u.w.bitSize = sndInfo.bitSize;
		    theI->u.w.channels = sndInfo.channels;
		    theI->u.w.waveformID = sndInfo.theID;
		    theI->u.w.waveSize = sndInfo.waveSize;
		    theI->u.w.waveFrames = sndInfo.waveFrames;
		    theI->u.w.startLoop = sndInfo.loopStart;
		    theI->u.w.endLoop = sndInfo.loopEnd;
		    theI->u.w.baseMidiPitch = (unsigned char)sndInfo.baseKey;
		    theI->u.w.sampledRate = sndInfo.rate;
		}
	}
    return theI;
}
Beispiel #10
0
// allocate and return an list of ID's collected from ID_SND, ID_CSND, ID_ESND. pCount will
// be the number of ID's, and the long array will be the list. use XDisposePtr on the return
// pointer
XLongResourceID * XGetAllSoundID(long *pCount)
{
    long			count, size, totalResourceCount, resourceIndex, sampleCount;
    XResourceType	resType;
    XLongResourceID	theID;
    char			name[256];
    XPTR			data;
    XLongResourceID	*pArray;

    pArray = NULL;
    sampleCount = 0;
    totalResourceCount = XCountTypes(NULL);		// get total number of resource types
    if (totalResourceCount && pCount)
	{
	    pArray = (XLongResourceID *)XNewPtr((long)sizeof(XLongResourceID) * MAX_SAMPLES);
	    if (pArray)
		{
		    for (resourceIndex = 0; resourceIndex < totalResourceCount; resourceIndex++)
			{
			    resType = XGetIndexedType(NULL, resourceIndex);
			    if ( (resType == ID_SND) || (resType == ID_CSND) || (resType == ID_ESND) )
				{
				    for (count = 0; ; count++)
					{
					    data = XGetIndexedResource(resType, &theID, count, name, &size);
					    if (data)
						{
						    XDisposePtr(data);			// free pointer resource
						    pArray[sampleCount++] = theID;
						    if (sampleCount == (MAX_SAMPLES-1))
							{
							    break;
							}
						}
					    else
						{
						    break;
						}
					}
				}
			}
		    *pCount = sampleCount;
		}
	}
    return pArray;
}
XMPEGDecodedData * XOpenMPEGStreamFromMemory(XPTR pBlock, unsigned long blockSize, OPErr *pErr)
{
	XMPEGDecodedData	*pStream;

	if (!pBlock || !blockSize || !pErr)
	{
		BAE_ASSERT(FALSE);
		return NULL;
	}
	
#if WRITE_FILE
	PV_SetupWriteFile();
#endif
	pStream = (XMPEGDecodedData *)XNewPtr(sizeof(XMPEGDecodedData));
	if (pStream)
	{
		pStream->stream = MPG_NewStreamFromMemory(pBlock, blockSize);
		if (pStream->stream)
		{
			pStream->sampleRate = UNSIGNED_LONG_TO_XFIXED(MPG_GetSampleRate(pStream->stream));
			pStream->bitSize = (XBYTE)MPG_GetBitSize(pStream->stream);
			pStream->channels = (XBYTE)MPG_GetChannels(pStream->stream);
			pStream->bitrate = MPG_GetBitrate(pStream->stream);

			pStream->lengthInBytes = MPG_GetSizeInBytes(pStream->stream);
			pStream->lengthInSamples = MPG_GetNumberOfSamples(pStream->stream);

			pStream->frameBufferSize = (unsigned long)MPG_GetBufferSize(pStream->stream);
			pStream->maxFrameBuffers = (unsigned long)MPG_GetMaxBuffers(pStream->stream);
			*pErr = NO_ERR;
		}
		else
		{
			BAE_ASSERT(FALSE);
			XDisposePtr((XPTR)pStream);
			pStream = NULL;
			*pErr = BAD_FILE;
		}
	}
	else
	{
		BAE_ASSERT(FALSE);
		*pErr = MEMORY_ERR;
	}
	return pStream;
}
Beispiel #12
0
void GM_AddSongSynth(GM_Song *pSong, GM_Synth *pSynth)
{
    GM_Synth *currentSynth = pSong->pSynths;

    // $$kk: 07.12.99: i am going to interpret
    // "pSynth == NULL" as meaning "use the software synth."
    // we should revisit this later.
    if (pSynth == NULL)
	{
	    pSynth = (GM_Synth *)XNewPtr((INT32)sizeof(GM_Synth));

	    if (!pSynth)
		{
		    // $$kk: 07.12.99: this is a memory err.  should report it!
		    // but for now this is a void method....
		    return;
		}

	    pSynth->deviceHandle = NULL;
	    pSynth->pProgramChangeProcPtr = PV_ProcessProgramChange;
	    pSynth->pNoteOffProcPtr = PV_ProcessNoteOff;
	    pSynth->pNoteOnProcPtr = PV_ProcessNoteOn;
	    pSynth->pPitchBendProcPtr = PV_ProcessPitchBend;
	    pSynth->pProcessControllerProcPtr = PV_ProcessController;
	    pSynth->pProcessSongSoundOffProcPtr = GM_EndSongNotes;
	    pSynth->pNext = NULL;
	}


    if (!currentSynth)
	{
	    pSong->pSynths = pSynth;
	    return;
	}

    while (currentSynth->pNext != NULL)
	{
	    currentSynth = currentSynth->pNext;
	}

    currentSynth->pNext = pSynth;
    return;
}
Beispiel #13
0
// This will return a pointer to a sound. If the sound is already loaded, then just the pointer is returned.
static void * PV_GetSampleFromID(XLongResourceID theID, CacheSampleInfo *pInfo)
{
    register short int	count;
    register void		*pSample;
    CacheSampleInfo		*pCache;
    CacheSampleInfo		*pNewCache;

    pSample = NULL;
    pCache = NULL;
    if (MusicGlobals->cacheSamples)
	{
	    pCache = PV_FindCacheFromID(theID);
	}
    if (pCache == NULL)
	{	// not loaded, so load it
	    pSample = PV_GetSampleData(theID, NULL, pInfo);
	    pInfo->referenceCount = 1;
	    if (pSample)
		{
		    for (count = 0; count < MAX_SAMPLES; count++)
			{
			    if (MusicGlobals->sampleCaches[count] == NULL)
				{
				    pNewCache = (CacheSampleInfo *)XNewPtr((INT32)sizeof(CacheSampleInfo));
				    if (pNewCache)
					{
					    pNewCache->theID = theID;
					    *pNewCache = *pInfo;
					    MusicGlobals->sampleCaches[count] = pNewCache;
					}
				    break;
				}
			}
		}
	}
    else
	{
	    pCache->referenceCount++;
	    *pInfo = *pCache;
	    pSample = pInfo->pSampleData;
	}
    return pSample;
}
Beispiel #14
0
static void PV_TrackNameCallback(void *threadContext, GM_Song *pSong, char markerType, void *pMetaText, INT32 metaTextLength, short currentTrack)
{
    XBYTE **tnArray,*str;

    threadContext;
    if (markerType == 0x03) 
	{	// track name
	    if (currentTrack != -1)
		{
		    str = (XBYTE *)XNewPtr(metaTextLength+1);
		    if (str)
			{
			    XBlockMove(pMetaText,str+1,metaTextLength);
			    str[0] = (XBYTE)metaTextLength;
			    tnArray = (XBYTE **)pSong->metaEventCallbackReference;
			    tnArray[currentTrack] = str;
			}
		}
	}
}
Beispiel #15
0
// Given an array of instruments, this will return an array of SND resources that are required to load
// these instruments
short int XGetTotalKeysplits(XShortResourceID *instArray, short int totalInstruments, 
			     XShortResourceID *sndArray, short int totalSnds)
{
    register short int	count, count2, count3, count4, keyCount;
    KeySplit			theSplit;
    InstrumentResource	*theInstrument;
    char				*pLoaded;
    long				size;

    keyCount = 0;
    if (instArray && totalInstruments && sndArray && totalSnds)
	{
	    pLoaded = (char *)XNewPtr((long)sizeof(char) * totalSnds);
	    if (pLoaded)
		{
		    for (count = 0; count < totalInstruments; count++)
			{
			    theInstrument = (InstrumentResource *)XGetAndDetachResource(ID_INST, instArray[count], &size);
			    if (theInstrument)
				{
				    count3 = (short)XGetShort(&theInstrument->keySplitCount);
				    for (count2 = 0; count2 < count3; count2++)
					{
					    XGetKeySplitFromPtr(theInstrument, count2, &theSplit);
					    count4 = PV_ConvertResourceID2Index(sndArray, totalSnds, theSplit.sndResourceID);
					    if (count4)
						{
						    if (pLoaded[count4] == 0)
							{
							    pLoaded[count4] = 1;
							    keyCount++;
							}
						}
					}
				}
			}
		    XDisposePtr((XPTR)pLoaded);
		}
	}
    return keyCount;
}
Beispiel #16
0
static OPErr MixerSourceLineCallbackProc(void* context, GM_StreamMessage message, GM_StreamData* pAS)
{
    JNIEnv* e = (JNIEnv*)context;														    
    VTRACE2("MixerSourceLineCallbackProc, context: %lx, message: %d\n", context, message);

    // for STREAM_CREATE, we just need to allocate the buffer.
    // we need to convert from gmData->dataLength (number of frames) to number of bytes.
    // $$kk: 03.15.98: this is the same calculation done by PV_GetSampleSizeInBytes.  however, this
    // method is not available outside GenAudioStreams.c right now.

    if (message == STREAM_CREATE)
	{
	    jint    const byteCount = pAS->dataLength * pAS->channelSize * (pAS->dataBitSize / 8);

	    VTRACE1("STREAM_CREATE: %lx\n", pAS->userReference);
	    VTRACE3("STREAM_CREATE: byteCount = %d, dataLength = %lu, frameSize = %d.\n", byteCount, pAS->dataLength, (pAS->channelSize * (pAS->dataBitSize / 8)) );

	    pAS->pData = XNewPtr(byteCount);
	    if (!pAS->pData)
		{
		    ERROR1("MixerSourceLineCallbackProc: STREAM_CREATE: Failed to allocate %d bytes\n", byteCount);
		    return MEMORY_ERR;
		}

	    VTRACE1("STREAM_CREATE: %lx completed\n", pAS->userReference);
	}
    else if (message == STREAM_DESTROY)
	{
	    VTRACE1("STREAM_DESTROY: %lx\n", pAS->userReference);

	    CallToJavaStreamDestroy(e, (jobject)pAS->userReference);

	    // $$kk: 12.21.98: for some reason, this causes the vm to crash some
	    // random time later.  so we have a memory leak here.  i don't know
	    // why we can't release the memory here....
		
	    // $$kk: 03.22.00: i am putting this code back in.  the memory leak is
	    // causing problems, and so far i have not been able to reproduce the
	    // crash.  the memory leak is reported in bug #4319431: "Memory leaks
	    // on opening and closing source DataLines."

	    if (pAS->pData)
		{
		    XDisposePtr(pAS->pData);
		}

	    VTRACE1("STREAM_DESTROY: %lx completed\n", pAS->userReference);
	}
    else if (message == STREAM_GET_DATA)
	{		
	    int length;
	    int frameLengthInBytes = pAS->channelSize * (pAS->dataBitSize / 8);
	    jbyteArray array = (jbyteArray)(*e)->GetObjectField(e, (jobject)pAS->userReference, g_dataArrayFieldID);

	    if (array == NULL) 
		{
		    ERROR0("STREAM_GET_DATA: failed to get array\n");
		    return GENERAL_BAD;
		}

	    // make the callback.
	    // pAS->dataLength is the length in FRAMES.
	    // length returned is length in FRAMES.
	    length = (int)CallToJavaStreamGetData(e, (jobject)pAS->userReference, array, (jint)pAS->dataLength);

	    // length will be -1 when the stream finishes
		
	    if (length < 0)
		{
		    VTRACE0("STREAM_GET_DATA: got negative length; stopping stream\n");
		    return STREAM_STOP_PLAY;
		}
													   
	    // get the relevant array elements

	    // $$kk: 03.15.98: can we avoid this copy??
	    (*e)->GetByteArrayRegion(e, array, (jint)0, (jint)(length * frameLengthInBytes), (jbyte*)(pAS->pData));
		
	    // $$kk: 04.21.00: fix for bug #4332327: "JNI leaks local references on 
	    // keeping a SourceLine open for long."
	    (*e)->DeleteLocalRef(e, array);		
		
	    // set dataLength to the number of frames read
	    pAS->dataLength = length;

	    VTRACE2("STREAM_GET_DATA: length: %d, pAS->dataLength: %lu\n", length, pAS->dataLength);
	    VTRACE1("STREAM_GET_DATA: %lx completed\n", pAS->userReference);
	}
    else if (message == STREAM_START)
	{
	    TRACE2("STREAM_START: stream: %lx,  framePosition: %lu\n", pAS->userReference, pAS->startSample);
	    CallToJavaStreamStart(e, (jobject)pAS->userReference);
	    TRACE1("STREAM_START: %lx completed\n", pAS->userReference);
	}
    else if (message == STREAM_STOP)
	{
	    TRACE2("STREAM_STOP: %lx,  framePosition: %lu\n", pAS->userReference, pAS->startSample);
	    CallToJavaStreamStop(e, (jobject)pAS->userReference);
	    TRACE1("STREAM_STOP: %lx completed\n", pAS->userReference);
	}
    else if (message == STREAM_EOM)
	{
	    TRACE2("STREAM_EOM: %lx,  framePosition: %lu\n", pAS->userReference, pAS->startSample);
	    CallToJavaStreamEOM(e, (jobject)pAS->userReference);
	    TRACE1("STREAM_EOM: %lx completed\n", pAS->userReference);
	}
    else if (message == STREAM_ACTIVE)
	{
	    TRACE2("STREAM_ACTIVE: %lx,  framePosition: %lu\n", pAS->userReference, pAS->startSample);
	    CallToJavaStreamActive(e, (jobject)pAS->userReference);
	    TRACE1("STREAM_ACTIVE: %lx completed\n", pAS->userReference);
	}
    else if (message == STREAM_INACTIVE)
	{
	    TRACE2("STREAM_INACTIVE: %lx,  framePosition: %lu\n", pAS->userReference, pAS->startSample);
	    CallToJavaStreamInactive(e, (jobject)pAS->userReference);
	    TRACE1("STREAM_INACTIVE: %lx completed\n", pAS->userReference);
	}

    else
	{
	    ERROR1("Bad message code in MixerSourceLineCallbackProc() : %d\n", message);
	    return GENERAL_BAD;
	}

    return NO_ERR;
}
XMPEGEncodeData *	XOpenMPEGEncodeStreamFromMemory(GM_Waveform *pAudio, 
														XMPEGEncodeRate encodeRate,
														OPErr *pErr)
{
	XMPEGEncodeData		*encode;
	OPErr				theErr;
	MPEGEncoderPrivate	*pPrivate;

	theErr = NO_ERR;
	encode = NULL;
	if (pAudio && pErr)
	{
		if ((pAudio->bitSize == 16) && (pAudio->channels <= 2))
		{
			encode = (XMPEGEncodeData *)XNewPtr((long)sizeof(XMPEGEncodeData));
			if (encode)
			{
				encode->pAudio = pAudio;
				encode->encodeRate = encodeRate;
				encode->pPrivateData = XNewPtr((long)sizeof(MPEGEncoderPrivate));
				if (encode->pPrivateData)
				{
					pPrivate = MPEG_ENCODE_PRIVATE(encode);

					// create new mpeg stream to prepare for encoding. Returns NULL if failed.
					pPrivate->encoder = MPG_EncodeNewStream(encodeRate,
											XFIXED_TO_UNSIGNED_LONG(pAudio->sampledRate), pAudio->channels,
											pAudio->theWaveform, pAudio->waveFrames);

					if (pPrivate->encoder)
					{
						encode->maxFrameBuffers = MPG_EncodeMaxFrames(pPrivate->encoder);
						encode->frameBufferSizeInBytes = MPG_EncodeMaxFrameSize(pPrivate->encoder);
						encode->frameBufferSize = 0;
						encode->currentFrameBuffer = 0;
						pPrivate->compressedAudioPosition = 0;
						pPrivate->compressedAudioSizeInBytes = encode->maxFrameBuffers * encode->frameBufferSizeInBytes;
						pPrivate->pCompressedAudio = XNewPtr(pPrivate->compressedAudioSizeInBytes);
						if (pPrivate->pCompressedAudio == NULL)
						{
							BAE_ASSERT(FALSE);
							theErr = MEMORY_ERR;
						}
					}
					else
					{
						BAE_ASSERT(FALSE);
						theErr = PARAM_ERR;
					}
				}
				else
				{
					BAE_ASSERT(FALSE);
					theErr = MEMORY_ERR;
				}
				if (theErr)
				{
					XDisposePtr((XPTR)encode);
					encode = NULL;
				}
			}
			else
			{
				BAE_ASSERT(FALSE);
				theErr = MEMORY_ERR;
			}
		}
		else
		{
			BAE_ASSERT(FALSE);
			theErr = BAD_SAMPLE;
		}
	}
	else
	{
		BAE_ASSERT(FALSE);
		theErr = PARAM_ERR;
	}
	if (pErr)
	{
		*pErr = theErr;
	}
	return encode;
}
// Given an mpeg bit encode rate, and a sample rate, this will return TRUE if
// this encoder can encode, or FALSE if it will not work.
XBOOL XIsValidMPEGSampleRateAndEncodeRate(XMPEGEncodeRate encodeRate, XFIXED sampleRate, 
		SndCompressionSubType subType, short int numChannels)
{
	XBOOL				safe;
	int					count;
	const int			TEMP_BUFFER_FRAMES = 2500;
	const int			TEMP_BUFFER_SIZE = TEMP_BUFFER_FRAMES * 2;
	XPTR				tempBuffer;
	GM_Waveform			*test;
	OPErr				err;
	XMPEGDecodedData	*stream;
	XFIXED				newSampleRate;

	numChannels; // we igore stereo samples for now.
	
	safe = FALSE;
	if (subType == CS_MPEG1)
	{
		newSampleRate = XGetClosestMPEGSampleRate(sampleRate, subType);
		if (sampleRate < newSampleRate)
		{
			return safe;
		}
	}

	tempBuffer = XNewPtr(TEMP_BUFFER_SIZE);
	if (tempBuffer)
	{
		for (count = 0; count < TEMP_BUFFER_SIZE; count++)
		{
			((XBYTE *)tempBuffer)[count] = (XBYTE)(127.0 * cos(count));
		}

		test = GM_NewWaveform();
		if (test)
		{
			XPTR			encodedData;
			UINT32			encodedBytes;

			test->theWaveform = tempBuffer;
			test->bitSize = 16;
			test->channels = 1;
			test->compressionType = C_NONE;
			test->sampledRate = sampleRate;
			test->waveSize = TEMP_BUFFER_SIZE;
			test->waveFrames = TEMP_BUFFER_FRAMES;

			err = XCompressMPEG(test, 
					XGetMPEGCompressionType(encodeRate),
					subType,
					NULL, NULL,
					&encodedData, &encodedBytes,
					NULL, NULL, NULL);

			if (err == NO_ERR)
			{
				// Have to open the stream simply to find out if the stream we just built is
				// valid.
				stream = XOpenMPEGStreamFromMemory(encodedData, encodedBytes, &err);
				if (stream && (err == NO_ERR))
				{
					safe = TRUE;
				}
				XCloseMPEGStream(stream);
			}
			XDisposePtr(encodedData);
			test->theWaveform = NULL;
			GM_FreeWaveform(test);
		}
		XDisposePtr(tempBuffer);
	}
	return safe;
}
Beispiel #19
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;
}
Beispiel #20
0
OPErr GM_GetSongInstrumentChanges(void *theSongResource, GM_Song **outSong, XBYTE **outTrackNames)
{
    OPErr		err;
    ScanMode 	saveScan;
    XBOOL		saveLoop,saveAlive;
    GM_Song		*theSong;
    void		*newMidiData;
	
    err = NO_ERR;
    // don't need a thread context here because we don't callback
    theSong = GM_LoadSong(NULL, NULL, 0, theSongResource, NULL, 0L, NULL, FALSE, TRUE, &err);
    if (!theSong)
	{
	    return err;
	}	
    err = PV_ConfigureMusic(theSong);
    // first pass: count the program changes, so we know how big to make our
    if (err == NO_ERR)
	{
	    theSong->pPatchInfo = (PatchInfo *)XNewPtr((INT32)sizeof(PatchInfo));
	    if (theSong->pPatchInfo)
		{
		    saveScan = theSong->AnalyzeMode;
		    theSong->AnalyzeMode = SCAN_COUNT_PATCHES;
		    saveLoop = theSong->loopSong;
		    theSong->loopSong = FALSE;
		    saveAlive = theSong->SomeTrackIsAlive;
		    theSong->SomeTrackIsAlive = TRUE;
		    while (theSong->SomeTrackIsAlive)
			{
			    // don't need a thread context here because we don't callback
			    err = PV_ProcessMidiSequencerSlice(NULL, theSong);
			    if (err)
				{
				    break;
				}
			}
		}
	    else
		{
		    err = MEMORY_ERR;
		}
	}
    // now theSong->pPatchInfo->pgmCount points to the number of program
    // changes without immediately preceding bank changes, and rsCount
    // is the number of program changes that were discovered to have been
    // written into the file in running status mode (implement this later)
    // done in two passes because we can't keep changing the midi data
    // pointer, so we have figure out how big it needs to be first and
    // move it in place

    if (err == NO_ERR)
	{
	    // expand the ptr enough to accomodate bank messages (4 bytes each)
	    newMidiData = XNewPtr(XGetPtrSize(theSong->midiData) + theSong->pPatchInfo->instrCount * 4);
	    XBlockMove(theSong->midiData,newMidiData,XGetPtrSize(theSong->midiData));
	    XDisposePtr(theSong->midiData);
	    theSong->midiData = newMidiData;

	    // start over
	    err = PV_ConfigureMusic(theSong);

	    // second pass: get the program changes, add bank events before each one
	    if (err == NO_ERR)
		{
		    GM_SetSongMetaEventCallback(theSong, PV_TrackNameCallback, (INT32)outTrackNames);
		    saveScan = theSong->AnalyzeMode;
		    theSong->AnalyzeMode = SCAN_FIND_PATCHES;
		    saveLoop = theSong->loopSong;
		    theSong->loopSong = FALSE;
		    saveAlive = theSong->SomeTrackIsAlive;
		    theSong->SomeTrackIsAlive = TRUE;
		    while (theSong->SomeTrackIsAlive)
			{
				// don't need a thread context here because we don't callback
			    err = PV_ProcessMidiSequencerSlice(NULL, theSong);
			    if (err)
				{
				    break;
				}
			}
		}
	}
    // since there was an error, caller won't be using the song
    if (err)
	{
	    if (theSong->pPatchInfo)
		{
		    XDisposePtr(theSong->pPatchInfo);
		}
	    // 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
	}
    else
	{
	    *outSong = theSong;
	}
    return err;
}
Beispiel #21
0
//	pSong	GM_Song structure. Data will be cloned for this function.
//	pErr		OPErr error type
UINT32 GM_GetSongTickLength(GM_Song *pSong, OPErr *pErr)
{
    GM_Song		*theSong;
    UFLOAT		tickLength;

    *pErr = NO_ERR;
    tickLength = 0;
    if (pSong->songMidiTickLength == 0)
	{
	    theSong = (GM_Song *)XNewPtr((INT32)sizeof(GM_Song));
	    if (theSong)
		{
		    *theSong = *pSong;
		    theSong->controllerCallback = NULL;		// ignore callbacks
		    theSong->songEndCallbackPtr = NULL;
		    theSong->songTimeCallbackPtr = NULL;
		    theSong->metaEventCallbackPtr = NULL;
		    theSong->disposeSongDataWhenDone = FALSE;
		    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;
			    theSong->songLoopCount = 0;
			    theSong->songMaxLoopCount = 0;
			    while (theSong->SomeTrackIsAlive)
				{
				    // don't need a thread context here because we don't callback
				    *pErr = PV_ProcessMidiSequencerSlice(NULL, theSong);
				    if (*pErr)
					{
					    break;
					}
				}
			    theSong->AnalyzeMode = SCAN_NORMAL;
			    pSong->songMidiTickLength = (UINT32)theSong->CurrentMidiClock;
			    tickLength = theSong->CurrentMidiClock;
			    pSong->songMicrosecondLength = (UINT32)theSong->songMicroseconds;
			    theSong->midiData = NULL;
			    theSong->songEndCallbackPtr = NULL;
			    theSong->disposeSongDataWhenDone = FALSE;

			    if (*pErr)
				{
				    tickLength = 0;
				}
			}
		    // 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
		}
	}
    else
	{
	    tickLength = (UFLOAT)pSong->songMidiTickLength;
	}
    return (UINT32)tickLength;
}
Beispiel #22
0
// GM_CreateLiveSong is used to create an active midi object that can be
// controled directly. ie via midi commands without loading midi data
//
//	context				context of song creation. C++ 'this' pointer, thread, etc.
//						Its just stored in the GM_Song->context variable
//	songID				unique ID for song structure
GM_Song * GM_CreateLiveSong(void *context, XShortResourceID songID)
{
    GM_Song			*pSong;
    short int		count;

    pSong = NULL;

    pSong = (GM_Song *)XNewPtr((INT32)sizeof(GM_Song));
    if (pSong)
	{

	    /*
	      // $$kk: 05.04.99
	      GM_Synth *pSynth = NULL;

	      // $$kk: 06.21.99
	      #if USE_EXTERNAL_SYNTH == TRUE

	      pSynth = PV_OpenExternalSynth(pSong);

	      #endif // USE_EXTERNAL_SYNTH == TRUE

	      if (pSynth == NULL)
	      {
	      pSynth = (GM_Synth *)XNewPtr((long)sizeof(GM_Synth));

	      pSynth->pProgramChangeProcPtr = PV_ProcessProgramChange;
	      pSynth->pNoteOffProcPtr = PV_ProcessNoteOff;
	      pSynth->pNoteOnProcPtr = PV_ProcessNoteOn;
	      pSynth->pPitchBendProcPtr = PV_ProcessPitchBend;
	      pSynth->pProcessControllerProcPtr = PV_ProcessController;
	      }

	      pSong->pSynth = pSynth;
	    */
	    pSong->pSynths = NULL;

	    // TEMP
	    /*
	      {
	      GM_Synth *pSynth1 = (GM_Synth *)XNewPtr((long)sizeof(GM_Synth));
	      if (!pSynth1)
	      {
	      // *pErr = MEMORY_ERR;
	      }
	      else
	      {
	      pSynth1->pProgramChangeProcPtr = PV_ProcessProgramChange;
	      pSynth1->pNoteOffProcPtr = PV_ProcessNoteOff;
	      pSynth1->pNoteOnProcPtr = PV_ProcessNoteOn;
	      pSynth1->pPitchBendProcPtr = PV_ProcessPitchBend;
	      pSynth1->pProcessControllerProcPtr = PV_ProcessController;
			
	      GM_AddSongSynth(pSong, pSynth1);
	      }
	      #if USE_EXTERNAL_SYNTH == TRUE
	      {
	      GM_Synth *pSynth2 = PV_OpenExternalSynth(pSong);
	      if (pSynth2)
	      {
	      GM_AddSongSynth(pSong, pSynth2);
	      }
	      }
	      #endif // USE_EXTERNAL_SYNTH == TRUE
	      }
	    */
	    // END TEMP

	    pSong->context = context;

	    // Fill in remap first
	    for (count = 0; count < (MAX_INSTRUMENTS*MAX_BANKS); count++)
		{
		    pSong->instrumentRemap[count] = (XLongResourceID)-1;		// no remap
		}

	    for (count = 0; count < MAX_CHANNELS; count++)
		{
		    pSong->firstChannelBank[count] = 0;
		    pSong->firstChannelProgram[count] = -1;
		}
	    PV_ConfigureInstruments(pSong);

	    pSong->defaultReverbType = GM_GetReverbType();
	    pSong->songID = songID;
	    pSong->songPitchShift = 0;
	    pSong->allowProgramChanges = TRUE;
	    pSong->defaultPercusionProgram = -1;

	    pSong->maxSongVoices = MusicGlobals->MaxNotes;
	    pSong->mixLevel = MusicGlobals->mixLevel;
	    pSong->maxEffectVoices = MusicGlobals->MaxEffects;

	    PV_SetTempo(pSong, 0L);
	    pSong->songVolume = MAX_SONG_VOLUME;
	}
    return pSong;
}
Beispiel #23
0
// Scan the midi file and determine which instrument that need to be loaded and load them.
OPErr GM_LoadSongInstruments(GM_Song *theSong, XShortResourceID *pArray, XBOOL loadInstruments)
{
    register INT32	count, loadCount, instCount, newCount;
    XBOOL			loopSongSave;
    OPErr			theErr;
    SBYTE			remapUsedSaved[MAX_INSTRUMENTS];
    SBYTE			remapUsed[MAX_INSTRUMENTS];

#if DISPLAY_INSTRUMENTS
    {
	char text[256];

	drawDebug = DNew((char *)"\pInstruments to load");
	sprintf(text, "SONG %ld debug file", (INT32)theSong->songID);
#if DISPLAY_INSTRUMENTS_FILE
	DAttachFile(drawDebug, ctop(text));
	DPrint(drawDebug, "Writing output to file: Ô%pÕ\r", text);
#endif
    }
#endif
    // Set the sequencer to mark instruments only
    theErr = NO_ERR;

    theSong->pUsedPatchList = (SBYTE *)XNewPtr((MAX_INSTRUMENTS*MAX_BANKS*128L) / 8);
    if (theSong->pUsedPatchList)
	{
	    for (count = 0; count < MAX_INSTRUMENTS*MAX_BANKS; count++)
		{
		    theSong->remapArray[count] = count;
		    if (pArray)
			{
			    pArray[count] = (XShortResourceID)-1;
			}
		}
	    for (count = 0; count < MAX_CHANNELS; count++)
		{
		    theSong->firstChannelBank[count] = 0;
		    theSong->firstChannelProgram[count] = -1;
		}
	    theErr = PV_ConfigureMusic(theSong);
	    if (theErr == NO_ERR)
		{
		    if (theSong->defaultPercusionProgram == -1)
			{
			    theSong->channelBank[PERCUSSION_CHANNEL] = 0;
			    theSong->firstChannelBank[PERCUSSION_CHANNEL] = 0;
			}
		    else
			{
			    if (theSong->defaultPercusionProgram)
				{
				    theSong->firstChannelProgram[PERCUSSION_CHANNEL] = theSong->defaultPercusionProgram;
				    GM_SetUsedInstrument(theSong, (XLongResourceID)theSong->defaultPercusionProgram, 60, TRUE);
				}
			}

		    theSong->AnalyzeMode = SCAN_SAVE_PATCHES;
		    theSong->SomeTrackIsAlive = TRUE;

		    loopSongSave = theSong->loopSong;
		    theSong->loopSong = FALSE;
		    while (theSong->SomeTrackIsAlive)
			{
			    theErr = PV_ProcessMidiSequencerSlice(NULL, theSong);
			    if (theErr)
				{
				    break;
				}
			}
		    theSong->AnalyzeMode = SCAN_NORMAL;
		    theSong->loopSong = loopSongSave;

		    if (theErr == NO_ERR)
			{
				// are we trying to load any instruments? This is for the case were there are no program changes. We must do something
			    newCount = FALSE;
			    for (count = 0; count < MAX_CHANNELS; count++)
				{
				    if (count != PERCUSSION_CHANNEL)	// only look at non percussion channels
					{
					    if (theSong->firstChannelProgram[count] != -1)
						{
						    newCount = TRUE;
						    break;
						}
					}
				}
			    if (newCount == FALSE)
				{	// there have been no program changes. So set up just the piano in all channels
				    for (count = 0; count < MAX_CHANNELS; count++)
					{
					    theSong->firstChannelProgram[count] = 0;
					    theSong->channelProgram[count] = 0;
					}
				    GM_SetUsedInstrument(theSong, 0, -1, TRUE);		// load the entire piano
				}
#if DISPLAY_INSTRUMENTS
			    DPrint(drawDebug, "Loading instruments:\r");
#endif
			    instCount = 0;
			    for (count = 0; count < MAX_INSTRUMENTS*MAX_BANKS; count++)
				{
				    // instrument needs to be loaded
				    if (GM_IsInstrumentUsed(theSong, count, -1))
					{
#if DISPLAY_INSTRUMENTS
					    DPrint(drawDebug, "Instrument %ld: ", (INT32)count);
#endif
					    loadCount = theSong->instrumentRemap[count];
					    if (loadCount == -1)
						{
						    loadCount = count;
						}
#if DISPLAY_INSTRUMENTS
					    else
						{
						    DPrint(drawDebug, "remapped to %ld ", (INT32)loadCount);
						}
#endif
#if DISPLAY_INSTRUMENTS
					    DPrint(drawDebug, "loading instrument %ld\r", loadCount);
#endif
					    if (pArray)
						{
						    pArray[instCount++] = (short)loadCount;
						}

					    if (loadInstruments)
						{
						    if (loadCount != count)
							{
							    GM_GetInstrumentUsedRange(theSong, loadCount, remapUsedSaved);		// save
							    GM_GetInstrumentUsedRange(theSong, count, remapUsed);
							    GM_SetInstrumentUsedRange(theSong, loadCount, remapUsed);
							}
						    theErr = GM_LoadInstrument(theSong, loadCount);
						    if (theErr != NO_ERR)
							{	// if the instrument is some other bank, then go back to the standard GM bank before failing
							    if (loadCount > MAX_INSTRUMENTS)
								{
#if DISPLAY_INSTRUMENTS
								    DPrint(drawDebug, "Failed loading extra bank instrument %ld, falling back to GM.\r", loadCount);
#endif
								    newCount = (loadCount % MAX_INSTRUMENTS);
								    newCount += ((loadCount / MAX_INSTRUMENTS) & 1) * MAX_INSTRUMENTS;
								    loadCount = newCount;

#if DISPLAY_INSTRUMENTS
								    DPrint(drawDebug, "Loading instrument %ld\r", loadCount);
#endif
								    theErr = GM_LoadInstrument(theSong, loadCount);
								    if (theSong->ignoreBadInstruments)
									{
									    theErr = NO_ERR;
									}
								}
							    else
								{	// we are in GM, so check our ignore flag
								    if (theSong->ignoreBadInstruments)
									{
									    theErr = NO_ERR;
									}
								}
							}
						    if (loadCount != count)
							{
							    GM_SetInstrumentUsedRange(theSong, loadCount, remapUsedSaved);		// save
							}
						    if (theErr)
							{
#if DISPLAY_INSTRUMENTS
							    DPrint(drawDebug, "Failed to load instrument %ld (%ld)\r", (INT32)loadCount, (INT32)theErr);
#endif
							    break;
							}
						    theErr = GM_RemapInstrument(theSong, loadCount, count);	// remap from: to
						    // we are in GM, so check our ignore flag
						    if (theSong->ignoreBadInstruments)
							{
							    theErr = NO_ERR;
							}
						}
					}
				}
			}
		}

	    if (theErr != NO_ERR)
		{
		    GM_UnloadSongInstruments(theSong);		// ignore error
		}
	    XDisposePtr(theSong->pUsedPatchList);
	    theSong->pUsedPatchList = NULL;
	}
    else
	{
	    theErr = MEMORY_ERR;
	}
#if DISPLAY_INSTRUMENTS
    DPrint(drawDebug, "\rClick to exit");
    while (Button() == FALSE) {};
    while (Button()) {};
    FlushEvents(mDownMask, 0);
    DCopy(drawDebug);
    DDispose(drawDebug);
#endif

    return theErr;
}
Beispiel #24
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;
}
Beispiel #25
0
// Instruments 0 to MAX_INSTRUMENTS*MAX_BANKS are the standard MIDI instrument placements.
// This will create an internal instrument from and external instrument. If theX is non-null then it
// will use that data to create the GM_Instrument
GM_Instrument * PV_GetInstrument(XLongResourceID theID, void *theExternalX, INT32 patchSize)
{
    GM_Instrument		*theI, *theS;
    InstrumentResource	*theX;
    INT32				size;
    short int 			count;
    UBYTE				*theSound;
    KeySplit			theXSplit;
    CacheSampleInfo		sndInfo;
    LOOPCOUNT			i;
    INT32				theSampleID;

    theI = NULL;
    theX = (InstrumentResource *)theExternalX;
    if (theExternalX == NULL)
	{
	    theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, theID, &patchSize);
	}
    if (theX)
	{
	    if (XGetShort(&theX->keySplitCount) < 2)	// if its 1, then it has no splits
		{
		    // get the sample ID from a short, values can be negative
		    // then allow conversion to take place.

		    // NOTE:	I know this is awfull, but if you change it things will break. The
		    //			internal ID values are all 32 bit signed, and some of the external
		    //			file structures are 16 bit signed.
		    theSampleID = (INT32)((short)XGetShort(&theX->sndResourceID));

		    theSound = (UBYTE *)PV_GetSampleFromID((INT32)theSampleID, &sndInfo);
		    if (theSound)
			{
			    theI = (GM_Instrument *)XNewPtr((INT32)sizeof(GM_Instrument));
			    if (theI)
				{
				    theI->u.w.theWaveform = (SBYTE *)theSound;

				    theI->disableSndLooping = TEST_FLAG_VALUE(theX->flags1, ZBF_disableSndLooping);
				    theI->playAtSampledFreq = TEST_FLAG_VALUE(theX->flags2, ZBF_playAtSampledFreq);
				    theI->doKeymapSplit = FALSE;
				    theI->notPolyphonic = TEST_FLAG_VALUE(theX->flags2, ZBF_notPolyphonic);
				    theI->avoidReverb = TEST_FLAG_VALUE(theX->flags1, ZBF_avoidReverb);
				    theI->useSampleRate = TEST_FLAG_VALUE(theX->flags1, ZBF_useSampleRate);
				    theI->sampleAndHold = TEST_FLAG_VALUE(theX->flags1, ZBF_sampleAndHold);
				    theI->useSoundModifierAsRootKey = TEST_FLAG_VALUE(theX->flags2, ZBF_useSoundModifierAsRootKey);
				    PV_GetEnvelopeData(theX, theI, patchSize);		// get envelope

				    theI->u.w.bitSize = sndInfo.bitSize;
				    theI->u.w.channels = sndInfo.channels;
				    theI->u.w.waveformID = XGetShort(&theX->sndResourceID);
				    theI->u.w.waveSize = sndInfo.waveSize;
				    theI->u.w.waveFrames = sndInfo.waveFrames;
				    theI->u.w.startLoop = sndInfo.loopStart;
				    theI->u.w.endLoop = sndInfo.loopEnd;

				    theI->masterRootKey = XGetShort(&theX->midiRootKey);
				    theI->panPlacement = theX->panPlacement;
				    theI->u.w.baseMidiPitch = (unsigned char)sndInfo.baseKey;
				    theI->u.w.sampledRate = sndInfo.rate;

				    // NOTE!! If ZBF_useSoundModifierAsRootKey is TRUE, then we are using
				    // the Sound Modifier data blocks as a root key replacement for samples in
				    // the particular split
				    theI->miscParameter1 = XGetShort(&theX->miscParameter1);
				    theI->miscParameter2 = XGetShort(&theX->miscParameter2);
				    if (theI->useSoundModifierAsRootKey)
					{
					    theI->enableSoundModifier = FALSE;
					    if (theI->miscParameter2 == 0)		// Forces a default value of 0 to 100
						{
						    theI->miscParameter2 = 100;
						}
					}
				    else
					{
					    theI->enableSoundModifier = TEST_FLAG_VALUE(theX->flags2, ZBF_enableSoundModifier);
					    theI->smodResourceID = theX->smodResourceID;

					    // Process sample in place
					    if ( (theI->enableSoundModifier) && (theI->u.w.bitSize == 8) && (theI->u.w.channels == 1) )
						{
#if DISPLAY_INSTRUMENTS
						    DPrint(drawDebug, "---->Processing instrument %ld with SMOD %ld\r", (INT32)theID, (INT32)theI->smodResourceID);
#endif
						    PV_ProcessSampleWithSMOD(theI->u.w.theWaveform,
									     theI->u.w.waveSize,
									     theI->u.w.waveformID,
									     theI->smodResourceID,
									     theI->miscParameter1,
									     theI->miscParameter2);
						}
					}
				}
			}
		}
	    else
		{	// Keysplits
#if DISPLAY_INSTRUMENTS
		    DPrint(drawDebug, "----->Processing %ld keysplits\r", (INT32)XGetShort(&theX->keySplitCount));
#endif
		    size = XGetShort(&theX->keySplitCount) * (INT32)sizeof(GM_KeymapSplit);
		    size += (INT32)sizeof(GM_KeymapSplitInfo);

		    theI = (GM_Instrument *)XNewPtr(size + (INT32)sizeof(GM_Instrument));
		    if (theI)
			{
			    theI->disableSndLooping = TEST_FLAG_VALUE(theX->flags1, ZBF_disableSndLooping);
			    theI->doKeymapSplit = TRUE;
			    theI->notPolyphonic = TEST_FLAG_VALUE(theX->flags2, ZBF_notPolyphonic);
			    theI->avoidReverb = TEST_FLAG_VALUE(theX->flags1, ZBF_avoidReverb);
			    theI->useSampleRate = TEST_FLAG_VALUE(theX->flags1, ZBF_useSampleRate);
			    theI->sampleAndHold = TEST_FLAG_VALUE(theX->flags1, ZBF_sampleAndHold);
			    theI->playAtSampledFreq = TEST_FLAG_VALUE(theX->flags2, ZBF_playAtSampledFreq);
			    theI->useSoundModifierAsRootKey = TEST_FLAG_VALUE(theX->flags2, ZBF_useSoundModifierAsRootKey);
			    PV_GetEnvelopeData(theX, theI, patchSize);		// get envelope

			    theI->u.k.KeymapSplitCount = XGetShort(&theX->keySplitCount);
			    theI->u.k.defaultInstrumentID = (XShortResourceID)XGetShort(&theX->sndResourceID);

			    theI->masterRootKey = XGetShort(&theX->midiRootKey);
			    theI->panPlacement = theX->panPlacement;

				// NOTE!! If ZBF_useSoundModifierAsRootKey is TRUE, then we are using
				// the Sound Modifier data blocks as a root key replacement for samples in
				// the particular split
			    theI->miscParameter1 = XGetShort(&theX->miscParameter1);
			    theI->miscParameter2 = XGetShort(&theX->miscParameter2);
			    if (theI->useSoundModifierAsRootKey)
				{
				    theI->enableSoundModifier = FALSE;
				    if (theI->miscParameter2 == 0)		// Forces a default value of 0 to 100
					{
					    theI->miscParameter2 = 100;
					}
				}
			    else
				{
				    theI->enableSoundModifier = TEST_FLAG_VALUE(theX->flags2, ZBF_enableSoundModifier);
				    theI->smodResourceID = theX->smodResourceID;
				}

			    for (count = 0; count < theI->u.k.KeymapSplitCount; count++)
				{
				    XGetKeySplitFromPtr(theX, count, &theXSplit);
				    theI->u.k.keySplits[count].lowMidi = theXSplit.lowMidi;
				    theI->u.k.keySplits[count].highMidi = theXSplit.highMidi;
				    theI->u.k.keySplits[count].miscParameter1 = theXSplit.miscParameter1;
				    if (theI->useSoundModifierAsRootKey && (theXSplit.miscParameter2 == 0))		// Forces a default value of 0 to 100
					{
					    theXSplit.miscParameter2 = 100;
					}
				    theI->u.k.keySplits[count].miscParameter2 = theXSplit.miscParameter2;

				    //					if (GM_IsInstrumentRangeUsed(theID, (INT16)theXSplit.lowMidi, (INT16)theXSplit.highMidi))
				    {
#if DISPLAY_INSTRUMENTS
					DPrint(drawDebug, "------->Keysplit %ld low %ld high %ld\r", (INT32)count,
					       (INT32)theXSplit.lowMidi,
					       (INT32)theXSplit.highMidi);
#endif
					theS =  PV_CreateInstrumentFromResource(theI, (XLongResourceID)theXSplit.sndResourceID);
					theI->u.k.keySplits[count].pSplitInstrument = theS;
					if (theS)
					    {
						theS->useSoundModifierAsRootKey = theI->useSoundModifierAsRootKey;
						theS->miscParameter1 = theXSplit.miscParameter1;
						if (theS->useSoundModifierAsRootKey && (theXSplit.miscParameter2 == 0))		// Forces a default value of 0 to 100
						    {
							theXSplit.miscParameter2 = 100;
						    }
						theS->miscParameter2 = theXSplit.miscParameter2;

						theS->masterRootKey = theI->masterRootKey;
						theS->avoidReverb = theI->avoidReverb;
						theS->volumeADSRRecord = theI->volumeADSRRecord;
						for (i = 0; i < theI->LFORecordCount; i++)
						    {
							theS->LFORecords[i] = theI->LFORecords[i];
						    }
						theS->LFORecordCount = theI->LFORecordCount;
						for (i = 0; i < theI->curveRecordCount; i++)
						    {
							theS->curve[i] = theI->curve[i];
						    }
						theS->curveRecordCount = theI->curveRecordCount;
						theS->LPF_frequency = theI->LPF_frequency;
						theS->LPF_resonance = theI->LPF_resonance;
						theS->LPF_lowpassAmount = theI->LPF_lowpassAmount;

						if (theS->useSoundModifierAsRootKey == FALSE)
						    {
							// Process sample in place
							if ( (theS->enableSoundModifier) && (theS->u.w.bitSize == 8) && (theS->u.w.channels == 1) )
							    {
#if DISPLAY_INSTRUMENTS
								DPrint(drawDebug, "----->Processing instrument %ld with SMOD %ld\r", (INT32)theID, (INT32)theI->smodResourceID);
#endif
								PV_ProcessSampleWithSMOD(	theS->u.w.theWaveform,
												theS->u.w.waveSize,
												theXSplit.sndResourceID,
												theS->smodResourceID,
												theS->miscParameter1,
												theS->miscParameter2);
							    }
						    }
					    }
				    }
				}
			}
		}
	    if (theExternalX == NULL)
		{
		    XDisposePtr((XPTR)theX);
		}
	}
#if DISPLAY_INSTRUMENTS
    if (theI)
	{
	    DPrint(drawDebug, "-------->INST info: masterRootKey %ld\r", (INT32)theI->masterRootKey);
	}
#endif
    return theI;
}
Beispiel #26
0
/*
**	This will walk through all Instrument resources and collect all snd resources
**	that are used.
*/
short int XGatherAllSoundsFromAllInstruments(XShortResourceID *pSndArray, short int maxArraySize)
{
    short int			count, icount, sndCount, jcount;
    XShortResourceID	soundID;
    XBOOL				goodSound;
    XShortResourceID	instArray[MAX_INSTRUMENTS * MAX_BANKS];
    short int			totalInstruments;
    XShortResourceID	sndArray[MAX_SAMPLES];
    short int			totalSnds;
    XShortResourceID	*completeSndArray;
    short int			completeSndCount;
    InstrumentResource	*theX;
    long				size;

    completeSndCount = 0;
    sndCount = 0;
    completeSndArray = (XShortResourceID *)XNewPtr(MAX_INSTRUMENTS * MAX_BANKS * 128L * sizeof(XShortResourceID));
    if (completeSndArray)
	{
	    sndCount = 0;
	    totalInstruments = XGetInstrumentArray(instArray, MAX_INSTRUMENTS * MAX_BANKS);
	    if (totalInstruments)
		{
		    for (count = 0; count < totalInstruments; count++)
			{
			    theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, instArray[count], &size);
			    if (theX)
				{
				    totalSnds = XCollectSoundsFromInstrument(theX, sndArray, MAX_SAMPLES);
				    XDisposePtr((XPTR)theX);

				    for (icount = 0; icount < totalSnds; icount++)
					{
					    completeSndArray[completeSndCount++] = sndArray[icount];
					}
				}
			}
		    XBubbleSortArray((short *)completeSndArray, (short)completeSndCount);

		    // Remove duplicates
		    for (jcount = 0; jcount < completeSndCount; jcount++)
			{
			    goodSound = TRUE;
			    soundID = completeSndArray[jcount];
			    for (count = 0; count < sndCount; count++)
				{
				    if (soundID == pSndArray[count])
					{
					    goodSound = FALSE;
					    break;
					}
				}
			    if (goodSound)
				{
				    if (sndCount < maxArraySize)
					{
					    pSndArray[sndCount++] = soundID;
					}
				}
			}
		}
	    XDisposePtr((XPTR)completeSndArray);
	}
    return sndCount;
}
// given a MPEG stream and an offset, decode the mpeg stream into memory
OPErr XExpandMPEG(GM_Waveform const* src, UINT32 startFrame, GM_Waveform* dst)
{
OPErr				err;
XMPEGDecodedData*	stream;

	BAE_ASSERT(dst);
	BAE_ASSERT(src);
	*dst = *src;
	dst->theWaveform = NULL;
	dst->compressionType = C_NONE;
	
	stream = XOpenMPEGStreamFromMemory(src->theWaveform, src->waveSize, &err);
	if (stream)
	{
	UINT32		decodingBytes;
	XPTR		decodingData;

		decodingBytes = stream->maxFrameBuffers * stream->frameBufferSize;
		decodingData = XNewPtr(decodingBytes);
		if (decodingData)
		{
		UINT32			const bytesPerFrame = dst->channels * sizeof(short);
		XBYTE*			data;
		UINT32			startByte;
		UINT32			count;

			data = (XBYTE*)decodingData;
			startByte = startFrame * bytesPerFrame;
			count = 0;
			while (count < stream->maxFrameBuffers)
			{
			XBOOL		done;
				
				err = XFillMPEGStreamBuffer(stream, data, &done);

				if (startByte == 0)
				{
					data += stream->frameBufferSize;
				}
				else if (startByte < stream->frameBufferSize)
				{
					XBlockMove(data + startByte, data,
								stream->frameBufferSize - startByte);
					data += stream->frameBufferSize - startByte;
					startByte = 0;
				}
				else
				{
					// don't increment "data", skip the buffer
					startByte -= stream->frameBufferSize;
				}
				if ((err != NO_ERR) || done)
				{
					break;
				}
				count++;
			}
			
			if (err == NO_ERR)
			{
			UINT32			decodedBytes;
			UINT32			definedBytes;

				decodedBytes = data - (XBYTE*)decodingData;
				definedBytes = dst->waveFrames * bytesPerFrame;
				if (decodedBytes < definedBytes)
				{
					//MOE: This is a little weird that the number of frames decoded is less
					//     When ascertaining the true number of frames is better (with a
					//	   better MPEG decoder), we shouldn't see this happening.
					definedBytes = decodedBytes;
					dst->waveFrames = decodedBytes / bytesPerFrame;
				}
				
				if (definedBytes < decodingBytes)
				{
				XPTR			trimmedData;
				
					trimmedData = XResizePtr(decodingData, definedBytes);
					BAE_ASSERT(trimmedData);	// making memory block smaller shouldn't fail
					if (trimmedData)
					{
						decodingData = trimmedData;
					}
				}
				
				dst->theWaveform = (XSBYTE *)decodingData;
				dst->waveSize = definedBytes;
			}
			else
			{
				BAE_ASSERT(FALSE);	// check "err"
				XDisposePtr(decodingData);
				decodingData = NULL;
			}
		}
		else
		{
			err = MEMORY_ERR;
		}
		XCloseMPEGStream(stream);
	}
	return err;
}
Beispiel #28
0
// Given a list of instruments, this will return the sample ID's that are required to load
// all of these instruments
short int XGetSamplesFromInstruments(XShortResourceID *pInstArray, short int maxInstArraySize, 
				     XShortResourceID *pSndArray, short int maxSndArraySize)
{
    register long		count, instCount, sndCount, newCount, completeSndCount;
    XShortResourceID	soundID;
    XShortResourceID	*completeSndArray;
    XBOOL				goodSound;
    InstrumentResource	*theX;
    long				size;

    sndCount = 0;
    completeSndArray = (XShortResourceID *)XNewPtr(sizeof(XShortResourceID) * MAX_INSTRUMENTS * 128L);
    if (completeSndArray)
	{
	    if ( (pInstArray) && (pSndArray) )
		{
		    instCount = 0;
		    for (count = 0; count < maxInstArraySize; count++)
			{
			    if (pInstArray[count] != (XShortResourceID)-1)
				{
				    instCount++;
				}
			    else
				{
				    break;
				}
			}
		    for (count = 0; count < maxSndArraySize; count++)
			{
			    pSndArray[count] = (XShortResourceID)-1;
			    completeSndArray[count] = (XShortResourceID)-1;
			}


		    completeSndCount = 0;
		    for (count = 0; count < instCount; count++)
			{
			    theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, pInstArray[count], &size);
			    if (theX)
				{
				    newCount = XCollectSoundsFromInstrument(theX, &completeSndArray[completeSndCount], 128);
				    XDisposePtr((XPTR)theX);
				    completeSndCount += newCount;
				}
			}
			
		    // remove duplicates in snds
		    for (newCount = 0; newCount < completeSndCount; newCount++)
			{
			    goodSound = TRUE;
			    soundID = completeSndArray[newCount];
			    for (count = 0; count < sndCount; count++)
				{
				    if (soundID == pSndArray[count])
					{
					    goodSound = FALSE;
					    break;
					}
				}
			    if (goodSound)
				{
				    pSndArray[sndCount++] = (XShortResourceID)soundID;
				}
			}
		    XBubbleSortArray((short *)pSndArray, (short)sndCount);
		}
	    XDisposePtr(completeSndArray);
	}
    return (short)sndCount;
}