This is SmsInstrument.m in view mode; [Download] [Up]
#import <objc/Storage.h> #import <appkit/nextstd.h> #import <musickit/musickit.h> #import <soundkit/Sound.h> #import "../library/SmsObject.h" #import <sms/sms.h> typedef short HWORD; #import "SmsInstrument.h" @implementation SmsInstrument /* See SmsInstrument.h for instance variables */ static int iFilePar = 0,iTimeOffsetPar = 0, iAmpDetPar = 0, iAmpStocPar = 0, iTimeStretchPar = 0, iTimeStretchHybPar = 0, iFreqStretchPar = 0, iAmpEnvPar = 0, iAmpDetEnvPar = 0, iAmpStocEnvPar = 0, iFreqEnvPar = 0, iTimeStretchEnvPar = 0, iTimeStretchHybEnvPar = 0, iFreqStretchEnvPar = 0, iMaxTrajPar = 0, iAmpPartialsEnvPar = 0, iAmpStocCoeffEnvPar = 0, iFreqPartialsEnvPar = 0, iFileHybPar = 0, iTimeOffsetHybPar = 0, iDurHybPar = 0, iAmpDetHybPar = 0, iAmpStocHybPar = 0, iFreqHybPar = 0, iAmpDetHybEnvPar = 0, iAmpStocHybEnvPar = 0, iFreqHybEnvPar = 0; -init { [super init]; iCurOutSample = -1; idSmsObj = nil; fDur = 0; fTimeOffset = 0; fAmp = 1.0; fAmpDet = 1.0; fAmpStoc = 1.0; fFreq1 = 1.0; fFreq0 = 0.0; fTimeStretch = 1.0; fTimeStretchHyb = 0; fFreqStretch = 1.0; iMaxTraj = 200; idAmpEnv = nil; idAmpDetEnv = nil; idAmpStocEnv = nil; idFreqEnv = nil; idTimeStretchEnv = nil; idTimeStretchHybEnv = nil; idFreqStretchEnv = nil; idAmpPartialsEnv = nil; idAmpStocCoeffEnv = nil; idFreqPartialsEnv = nil; iFirstRecord = 0; iLastRecord = 0; idSmsObjHyb = nil; fTimeOffsetHyb = 0; fDurHyb = 0; fAmpDetHybFactor = 1; fAmpStocHybFactor = 1; fFreqHybFactor = 1; idAmpDetHybEnv = nil; idAmpStocHybEnv = nil; idFreqHybEnv = nil; newSmsRecord.pFFreqTraj = NULL; newSmsRecord.pFMagTraj = NULL; newSmsRecord.pFPhaTraj = NULL; newSmsRecord.pFMagTraj = NULL; newSmsRecord.nTraj = 0; newSmsRecord.nCoeff = 0; newSmsRecord.pFStocCoeff = NULL; newSmsRecord.pFStocGain = NULL; iModification = 0; iOldSample = 0; iNewSample = 0; iFilePar = [Note parName:"smsFile"]; iTimeOffsetPar = [Note parName:"timeOffset"]; iAmpDetPar = [Note parName:"ampDet"]; iAmpStocPar = [Note parName:"ampStoc"]; iTimeStretchPar = [Note parName:"timeStretch"]; iTimeStretchHybPar = [Note parName:"timeStretchHyb"]; iFreqStretchPar = [Note parName:"freqStretch"]; iMaxTrajPar = [Note parName:"maxTraj"]; iAmpEnvPar = [Note parName:"ampEnv"]; iAmpDetEnvPar = [Note parName:"ampDetEnv"]; iAmpStocEnvPar = [Note parName:"ampStocEnv"]; iFreqEnvPar = [Note parName:"freqEnv"]; iTimeStretchEnvPar = [Note parName:"timeStretchEnv"]; iTimeStretchHybEnvPar = [Note parName:"timeStretchHybEnv"]; iFreqStretchEnvPar = [Note parName:"freqStretchEnv"]; iAmpPartialsEnvPar = [Note parName:"ampPartialsEnv"]; iAmpStocCoeffEnvPar = [Note parName:"ampStocCoeffEnv"]; iFreqPartialsEnvPar = [Note parName:"freqPartialsEnv"]; iFileHybPar = [Note parName:"smsFileHyb"]; iTimeOffsetHybPar = [Note parName:"timeOffsetHyb"]; iDurHybPar = [Note parName:"durHyb"]; iAmpDetHybPar = [Note parName:"ampDetHybFactor"]; iAmpStocHybPar = [Note parName:"ampStocHybFactor"]; iFreqHybPar = [Note parName:"freqHybFactor"]; iAmpDetHybEnvPar = [Note parName:"ampDetHybEnv"]; iAmpStocHybEnvPar = [Note parName:"ampStocHybEnv"]; iFreqHybEnvPar = [Note parName:"freqHybEnv"]; FSamplingRate = fSamplingRate = 22050; FHalfSamplingRate = FSamplingRate / 2; /* prepare sinc and sine tables */ if (pFSincTab == NULL) PrepSinc (); if (pFSTab == NULL) PrepSine (2046); [self addNoteReceiver:[[NoteReceiver alloc] init]]; /* Need one NoteReceiver */ return self; } -setSamplingRate:(double)fSRate stream:(NXStream *)aStream /* Invoked once before performance from smssynth.m. */ { if ([self inPerformance]) return nil; FSamplingRate = fSamplingRate = fSRate; FHalfSamplingRate = FSamplingRate / 2; pStream = aStream; return self; } -firstNote:aNote /* This is invoked when first note is received during performance */ { SNDAlloc(&pOutSoundStruct, 0 /* data size (we'll set this later) */, SND_FORMAT_LINEAR_16, (int)fSamplingRate, 1, 0); /* Write header */ NXWrite(pStream,(char *)pOutSoundStruct, sizeof(*pOutSoundStruct)); return self; } -_mixToOutput:(short *)pData length:(int)iLength sample:(int)iFirstSample { int iLastSample = iFirstSample + iLength; int i, iLastCommonSample = 0, iLoc = 0, nSamps = 0; if (iFirstSample > (iCurOutSample + 1)) { short *pBuffer; nSamps = iFirstSample - iCurOutSample; pBuffer = (short *) calloc (nSamps, sizeof(short)); NXSeek(pStream, ((iCurOutSample + 1) * sizeof(short)) + sizeof(*pOutSoundStruct), NX_FROMSTART); NXWrite(pStream,(char *)pBuffer, nSamps * sizeof(short)); iCurOutSample += nSamps; free (pBuffer); } else if (iCurOutSample >= iFirstSample) { short *pBuffer; NXSeek(pStream, (iFirstSample * sizeof (short)) + sizeof(*pOutSoundStruct), NX_FROMSTART); iLastCommonSample = MIN (iLastSample, iCurOutSample); nSamps = MIN (iLength , 1 + iLastCommonSample - iFirstSample); pBuffer = (short *) calloc (nSamps, sizeof(short)); NXRead (pStream, (char *)pBuffer, sizeof(short) * nSamps); for (i = 0; i < nSamps; i++) pBuffer[i] += pData[i]; NXSeek(pStream, (iFirstSample * sizeof (short)) + sizeof(*pOutSoundStruct), NX_FROMSTART); NXWrite (pStream, (char *)pBuffer, sizeof(short) * nSamps); iLoc = nSamps - 1; free (pBuffer); } if (iLastSample > (iCurOutSample + 1)) { nSamps = iLastSample - (iCurOutSample + 1); NXSeek(pStream, ((iCurOutSample + 1) * sizeof (short)) + sizeof(*pOutSoundStruct), NX_FROMSTART); NXWrite(pStream,(char *)(pData+iLoc), nSamps * sizeof(short)); iCurOutSample += nSamps; } NXFlush(pStream); return self; } -_generateArray:(float *)pFArray size:(int)sizeArray envelope:(id)idEnvelope { double xfirst, xlast, y, s, fValT = 1, xval, fVal = 0; float fXinc; int lastPoint = [idEnvelope pointCount] - 1, i; if (idEnvelope) { [idEnvelope getNth:0 x:&xfirst y:&y smoothing:&s]; [idEnvelope getNth:lastPoint x:&xlast y:&y smoothing:&s]; fXinc = (float) ((xlast - xfirst) / sizeArray); xval = xfirst; for (i = 0; i < sizeArray; i++) { pFArray[i] = [idEnvelope lookupYForX:xval]; xval += fXinc; } } else for (i = 0; i < sizeArray; i++) pFArray[i] = 0; return self; } -_changeDetAmp:(double)fLocation weights:(float *)pFWeights { double xfirst, xlast, y, s, fAmpDetT = 1, fAmpT = 1, fScalar, xval; int i, lastPoint = [idAmpDetEnv pointCount] - 1; if (idAmpDetEnv) { [idAmpDetEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idAmpDetEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fAmpDetT = [idAmpDetEnv lookupYForX:xval]; } lastPoint = [idAmpEnv pointCount] - 1; if (idAmpEnv) { [idAmpEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idAmpEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fAmpT = [idAmpEnv lookupYForX:xval]; } fScalar = fAmpDetT * fAmpT * fAmp * fAmpDet; if (!pFWeights) { if (fScalar <= 0) for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFMagTraj[i] = 0; else for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFMagTraj[i] = TO_DB (TO_MAG (newSmsRecord.pFMagTraj[i]) * fScalar); } else for (i = 0; i < iMaxTraj; i++) { if (pFWeights[i] == 0) newSmsRecord.pFMagTraj[i] = TO_DB (TO_MAG (newSmsRecord.pFMagTraj[i]) * fAmpT * fAmp); else newSmsRecord.pFMagTraj[i] = TO_DB (TO_MAG (newSmsRecord.pFMagTraj[i]) * fScalar * pFWeights[i]); } return self; } -_changeStocAmp:(double)fLocation weights:(float *)pFWeights { double xfirst, xlast, y, s, fAmpStocT = 1, fAmpT = 1, fScalar, xval; int i, lastPoint = [idAmpStocEnv pointCount] - 1; if (!newSmsRecord.pFStocGain) return self; if (idAmpStocEnv) { [idAmpStocEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idAmpStocEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fAmpStocT = [idAmpStocEnv lookupYForX:xval]; } lastPoint = [idAmpEnv pointCount] - 1; if (idAmpEnv) { [idAmpEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idAmpEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fAmpT = [idAmpEnv lookupYForX:xval]; } fScalar = fAmpStocT * fAmpT * fAmp * fAmpStoc; if (!pFWeights) { if (fScalar == 0) *(newSmsRecord.pFStocGain) = 0; else if (fScalar > 0) *(newSmsRecord.pFStocGain) = TO_DB (TO_MAG (*(newSmsRecord.pFStocGain)) * fScalar); } else { for (i = 0; i < newSmsRecord.nCoeff; i++) if (pFWeights[i] > 0) newSmsRecord.pFStocCoeff[i] *= (pFWeights[i] * fScalar); } return self; } -_changeFreq:(double)fLocation weights:(float *)pFWeights { double xfirst, xlast, y, s, fFreqT = 1, xval, fVal, fTmp; int i, lastPoint = [idFreqEnv pointCount] - 1; if (idFreqEnv) { [idFreqEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idFreqEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fFreqT = [idFreqEnv lookupYForX:xval]; } fVal = fFreq0 + fFreqT * (fFreq1 - fFreq0); if (fVal > 50) fprintf (stderr, "transposing by %f, are you sure!\n", fVal); if (fVal > 0) { iModification = 1; if (pFWeights) for (i = 0; i < iMaxTraj; i++) { fTmp = (fVal * pFWeights[i]); if (fTmp > 0) newSmsRecord.pFFreqTraj[i] *= fTmp; } else for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFFreqTraj[i] *= fVal; } return self; } -_stretchPartials:(double)fLocation { double xfirst, xlast, y, s, fFreqStretchT = 1, xval, fVal, fIncr; int i, lastPoint = [idFreqStretchEnv pointCount] - 1; if (idFreqStretchEnv) { [idFreqStretchEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idFreqStretchEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fFreqStretchT = [idFreqStretchEnv lookupYForX:xval]; } fFreqStretchT *= fFreqStretch; fVal = 1.0; fIncr = (fFreqStretchT - 1.0) / iMaxTraj; /* assume that the new record has been filled */ if (fIncr != 0) { iModification = 1; for (i = 0; i < iMaxTraj; i++) { newSmsRecord.pFFreqTraj[i] *= fVal; fVal += fIncr; } } return self; } - _hybridizeDetAmp:(SMS_DATA *)pSmsRecordHyb location:(double)fLocation { double xfirst, xlast, y, s, fAmpDetHybT = 1, fVal, xval; int i, lastPoint = 0; /* hybridize deterministic amplitude */ lastPoint = [idAmpDetHybEnv pointCount] - 1; if (idAmpDetHybEnv) { [idAmpDetHybEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idAmpDetHybEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fAmpDetHybT = [idAmpDetHybEnv lookupYForX:xval]; } fVal = fAmpDetHybT * fAmpDetHybFactor; if (fVal < 0) { float fMag = newSmsRecord.pFMagTraj[0]; float fNewVal = fabs ((double) fVal); for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFMagTraj[i] = (pSmsRecordHyb->pFMagTraj[i] - pSmsRecordHyb->pFMagTraj[0]) + (fNewVal * fMag); } if (fVal > 0 && fVal < 1) for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFMagTraj[i] = (pSmsRecordHyb->pFMagTraj[i] - newSmsRecord.pFMagTraj[i]) * fVal + newSmsRecord.pFMagTraj[i]; else if (fVal >= 1) for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFMagTraj[i] = pSmsRecordHyb->pFMagTraj[i]; return self; } - _hybridizeDetFreq:(SMS_DATA *)pSmsRecordHyb location:(double)fLocation { double xfirst, xlast, y, s, fFreqHybT = 1, fVal, xval; int i, lastPoint = 0; /* hybridize deterministic frequency */ lastPoint = [idFreqHybEnv pointCount] - 1; if (idFreqHybEnv) { [idFreqHybEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idFreqHybEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fFreqHybT = [idFreqHybEnv lookupYForX:xval]; } fVal = fFreqHybT * fFreqHybFactor; if (fVal < 0) { float fFund = newSmsRecord.pFFreqTraj[0]; float fNewVal = fabs ((double) fVal); for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFFreqTraj[i] = (pSmsRecordHyb->pFFreqTraj[i] / pSmsRecordHyb->pFFreqTraj[0]) * fNewVal * fFund; } else if (fVal > 0 && fVal < 1) for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFFreqTraj[i] = (pSmsRecordHyb->pFFreqTraj[i] - newSmsRecord.pFFreqTraj[i]) * fVal + newSmsRecord.pFFreqTraj[i]; else if (fVal >= 1) for (i = 0; i < iMaxTraj; i++) newSmsRecord.pFFreqTraj[i] = pSmsRecordHyb->pFFreqTraj[i]; return self; } - _hybridizeStoc:(SMS_DATA *)pSmsRecordHyb location:(double)fLocation { double xfirst, xlast, y, s, fAmpStocHybT = 1, fVal, xval; int i, lastPoint = 0; /* hybridize stochastic amplitude */ lastPoint = [idAmpStocHybEnv pointCount] - 1; if (idAmpStocHybEnv) { [idAmpStocHybEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idAmpStocHybEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fAmpStocHybT = [idAmpStocHybEnv lookupYForX:xval]; } fVal = fAmpStocHybT * fAmpStocHybFactor; if (newSmsRecord.pFStocGain && pSmsRecordHyb->pFStocGain) { if (fVal > 0 && fVal < 1) *(newSmsRecord.pFStocGain) = (*(pSmsRecordHyb->pFStocGain) - *(newSmsRecord.pFStocGain)) * fVal + *(newSmsRecord.pFStocGain); else if (fVal >= 1) *(newSmsRecord.pFStocGain) = *(pSmsRecordHyb->pFStocGain); /* hybridize stochastic coefficients */ if ([idSmsObj getStochasticType] == STOC_FILTER_TYPE) { if (fVal > .5 && (pSmsRecordHyb->nCoeff == newSmsRecord.nCoeff)) for (i = 0; i < newSmsRecord.nCoeff; i++) newSmsRecord.pFStocCoeff[i] = pSmsRecordHyb->pFStocCoeff[i]; } else if ([idSmsObj getStochasticType] == STOC_MAG_ENV_TYPE) InterpolateArrays (newSmsRecord.pFStocCoeff, newSmsRecord.nCoeff, pSmsRecordHyb->pFStocCoeff, pSmsRecordHyb->nCoeff, newSmsRecord.pFStocCoeff, newSmsRecord.nCoeff, fVal); } return self; } - _hybridize:(SMS_DATA *)pSmsRecordHyb location:(double)fLocation { if (idFreqHybEnv || fFreqHybFactor != 0) [self _hybridizeDetFreq:pSmsRecordHyb location:fLocation]; if (idAmpDetHybEnv || fAmpDetHybFactor != 0) [self _hybridizeDetAmp:pSmsRecordHyb location:fLocation]; if (idAmpStocHybEnv || fAmpStocHybFactor != 0) [self _hybridizeStoc:pSmsRecordHyb location:fLocation]; return self; } -(double)_changeTime:(double)fLocation { double xfirst, xlast, y, s, fTimeStretchT = 1, xval, fVal; int lastPoint = [idTimeStretchEnv pointCount] - 1; if (idTimeStretchEnv) { [idTimeStretchEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idTimeStretchEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fTimeStretchT = [idTimeStretchEnv lookupYForX:xval]; } fVal = 1 / (fTimeStretch * fTimeStretchT); return fVal; } -(double)_changeHybTime:(double)fLocation { double xfirst, xlast, y, s, fTimeStretchT = 1, xval, fVal; int lastPoint = [idTimeStretchHybEnv pointCount] - 1; if (idTimeStretchHybEnv) { [idTimeStretchHybEnv getNth:0 x:&xfirst y:&y smoothing:&s]; [idTimeStretchHybEnv getNth:lastPoint x:&xlast y:&y smoothing:&s]; xval = xfirst + fLocation * (xlast - xfirst); fTimeStretchT = [idTimeStretchHybEnv lookupYForX:xval]; } fVal = 1 / (fTimeStretchHyb * fTimeStretchT); return fVal; } /* This is invoked when performance is over. */ -afterPerformance { if (!pOutSoundStruct) /* Did we never received any notes? */ return self; pOutSoundStruct->dataSize = iCurOutSample * sizeof(short); NXSeek(pStream, 0, NX_FROMSTART); NXWrite(pStream,(char *)pOutSoundStruct, sizeof(*pOutSoundStruct)); NXFlush(pStream); pOutSoundStruct->dataSize = 0; SNDFree(pOutSoundStruct); pOutSoundStruct = NULL; NXSeek(pStream,0,NX_FROMEND); NXFlush(pStream); return self; } -_readParams:aNote { char *pChFileT = [aNote parAsStringNoCopy:iFilePar]; char *pChFileHybT = ""; /* get input file */ if (pChFileT && strlen(pChFileT)) pChFile = pChFileT; idSmsObj = (SmsObject *)[[SmsObject alloc] initFromFile:pChFile]; if (!idSmsObj) { fprintf(stderr,"Can't find file %s.\n",pChFile); return self; } /* get other input file */ if ([aNote isParPresent:iFileHybPar]) { pChFileHybT = [aNote parAsStringNoCopy:iFileHybPar]; if (pChFileHybT && strlen(pChFileHybT)) pChFileHyb = pChFileHybT; idSmsObjHyb = (SmsObject *)[[SmsObject alloc] initFromFile:pChFileHyb]; if (!idSmsObjHyb) { fprintf(stderr,"Can't find file %s.\n",pChFileHyb); return self; } } /* get amplitude parameters */ if ([aNote isParPresent:MK_amp]) fAmp = [aNote parAsDouble:MK_amp]; if ([aNote isParPresent:MK_velocity]) fAmp *= MKMidiToAmpAttenuation([aNote parAsInt:MK_velocity]); if ([aNote isParPresent:iAmpDetPar]) fAmpDet = [aNote parAsDouble:iAmpDetPar]; if ([aNote isParPresent:iAmpStocPar]) fAmpStoc = [aNote parAsDouble:iAmpStocPar]; if ([aNote isParPresent:iAmpEnvPar]) idAmpEnv = (Envelope *)[aNote parAsEnvelope:iAmpEnvPar]; if ([aNote isParPresent:iAmpDetEnvPar]) idAmpDetEnv = (Envelope *)[aNote parAsEnvelope:iAmpDetEnvPar]; if ([aNote isParPresent:iAmpPartialsEnvPar]) idAmpPartialsEnv = (Envelope *)[aNote parAsEnvelope:iAmpPartialsEnvPar]; if ([aNote isParPresent:iAmpStocEnvPar]) idAmpStocEnv = (Envelope *)[aNote parAsEnvelope:iAmpStocEnvPar]; if ([aNote isParPresent:iAmpStocCoeffEnvPar]) idAmpStocCoeffEnv = (Envelope *)[aNote parAsEnvelope:iAmpStocCoeffEnvPar]; /* get frequency parameters */ if ([aNote isParPresent:MK_freq]) fFreq1 = [aNote parAsDouble:MK_freq]; if ([aNote isParPresent:MK_freq1]) fFreq1 = [aNote parAsDouble:MK_freq1]; if ([aNote isParPresent:MK_freq0]) fFreq0 = [aNote parAsDouble:MK_freq0]; if ([aNote isParPresent:MK_freqEnv]) idFreqEnv = (Envelope *)[aNote parAsEnvelope:MK_freqEnv]; if ([aNote isParPresent:iFreqPartialsEnvPar]) idFreqPartialsEnv = (Envelope *)[aNote parAsEnvelope:iFreqPartialsEnvPar]; /* get time offset */ if ([aNote isParPresent:iTimeOffsetPar]) fTimeOffset = [aNote parAsDouble:iTimeOffsetPar]; iFirstRecord = MIN ([idSmsObj getFrameRate] * fTimeOffset, [idSmsObj getNRecords] - 1); /* get duration */ fDur = [aNote dur]; if (!MKIsNoDVal(fDur) && fDur != 0) iLastRecord = MIN ([idSmsObj getFrameRate] * fDur + iFirstRecord, [idSmsObj getNRecords] - 1); if (iLastRecord <= iFirstRecord || fDur <= 0) fprintf(stderr,"Warning: no samples to generate for this file.\n"); /* get time stretch parameters */ if ([aNote isParPresent:iTimeStretchPar]) fTimeStretch = [aNote parAsDouble:iTimeStretchPar]; if ([aNote isParPresent:iTimeStretchEnvPar]) idTimeStretchEnv = (Envelope *)[aNote parAsEnvelope:iTimeStretchEnvPar]; /* get time stretch parameters */ if ([aNote isParPresent:iTimeStretchHybPar]) fTimeStretchHyb = [aNote parAsDouble:iTimeStretchHybPar]; if ([aNote isParPresent:iTimeStretchHybEnvPar]) idTimeStretchHybEnv = (Envelope *)[aNote parAsEnvelope:iTimeStretchHybEnvPar]; /* get frequency stretch parameters */ if ([aNote isParPresent:iFreqStretchPar]) fFreqStretch = [aNote parAsDouble:iFreqStretchPar]; if ([aNote isParPresent:iFreqStretchEnvPar]) idFreqStretchEnv = (Envelope *)[aNote parAsEnvelope:iFreqStretchEnvPar]; if ([aNote isParPresent:iMaxTrajPar]) iMaxTraj = [aNote parAsInt:iMaxTrajPar]; /* get parameters for hybridizing process */ if ([aNote isParPresent:iTimeOffsetHybPar]) fTimeOffsetHyb = [aNote parAsDouble:iTimeOffsetHybPar]; if ([aNote isParPresent:iDurHybPar]) fDurHyb = [aNote parAsDouble:iDurHybPar]; if ([aNote isParPresent:iAmpDetHybPar]) fAmpDetHybFactor = [aNote parAsDouble:iAmpDetHybPar]; if ([aNote isParPresent:iAmpDetHybEnvPar]) idAmpDetHybEnv = (Envelope *)[aNote parAsEnvelope:iAmpDetHybEnvPar]; if ([aNote isParPresent:iAmpStocHybPar]) fAmpStocHybFactor = [aNote parAsDouble:iAmpStocHybPar]; if ([aNote isParPresent:iAmpStocHybEnvPar]) idAmpStocHybEnv = (Envelope *)[aNote parAsEnvelope:iAmpStocHybEnvPar]; if ([aNote isParPresent:iFreqHybPar]) fFreqHybFactor = [aNote parAsDouble:iFreqHybPar]; if ([aNote isParPresent:iFreqHybEnvPar]) idFreqHybEnv = (Envelope *)[aNote parAsEnvelope:iFreqHybEnvPar]; return self; } /* This is invoked when a new Note is received during performance */ -realizeNote:aNote fromNoteReceiver:aNoteReceiver { MKNoteType type; if (!aNote) return self; type = [aNote noteType]; if(type == MK_noteDur || type == MK_noteUpdate) [self _readParams:aNote]; else return self; if (type == MK_noteUpdate) fprintf (stderr, "SmsInstrument cannot handle note updates\n"); /* if a real note, synthesize */ if (type == MK_noteDur) { SMS_DATA smsRecord1, smsRecord2, smsRecordHyb1, smsRecordHyb2, smsRecordTmp; SYNTH_PARAMS synthParams; short *pBuffer; int iFirstSample = 0, iRecords, iLeftRecord, iLeftRecordHyb, iFirstRecordHyb, iLastRecordHyb, iSizeFrame, iNCoeff; float *pFAmpArray = NULL, *pFFreqArray = NULL, *pFAmpStocArray = NULL; double fLocation = 0, fLocationHyb = 0, fRecordLoc, fInterpFactor, fRecordLocHyb, fInterpFactorHyb, fSynthesisRateHyb, fCurrentLoc, fCurrentLocHyb; if (!idSmsObj) return self; /* Give user feedback */ fprintf(stderr,"%f ",MKGetTime()); fflush(stderr); iNCoeff = [idSmsObj getNStochasticCoeff]; if (idSmsObjHyb) { if (iMaxTraj >= 0) iMaxTraj = MIN ([idSmsObj getNTrajectories], MIN ([idSmsObjHyb getNTrajectories], iMaxTraj)); else iMaxTraj = MIN ([idSmsObj getNTrajectories], [idSmsObjHyb getNTrajectories]); } else { if (iMaxTraj >= 0) iMaxTraj = MIN ([idSmsObj getNTrajectories], iMaxTraj); else iMaxTraj = [idSmsObj getNTrajectories]; } if (idAmpPartialsEnv) { if ((pFAmpArray = (float *) calloc(iMaxTraj, sizeof(float))) == NULL) return nil; [self _generateArray:pFAmpArray size:iMaxTraj envelope:idAmpPartialsEnv]; } if (idAmpStocCoeffEnv && ([idSmsObj getStochasticType] == STOC_MAG_ENV_TYPE)) { if ((pFAmpStocArray = (float *) calloc(iNCoeff, sizeof(float))) == NULL) return nil; [self _generateArray:pFAmpStocArray size:iNCoeff envelope:idAmpStocCoeffEnv]; } if (idFreqPartialsEnv) { if ((pFFreqArray = (float *) calloc(iMaxTraj, sizeof(float))) == NULL) return nil; [self _generateArray:pFFreqArray size:iMaxTraj envelope:idFreqPartialsEnv]; } synthParams.iStochasticType = [idSmsObj getStochasticType]; synthParams.fOriginalSRate = [idSmsObj getOriginalSRate]; synthParams.fSamplingRate = fSamplingRate; synthParams.sizeHop = iSizeFrame = 128; if ((pBuffer = (short *) calloc (iSizeFrame, sizeof (short))) == NULL) return nil; if ((synthParams.pFStocWindow = (float *) calloc(iSizeFrame * 2, sizeof(float))) == NULL) return nil; Hanning (iSizeFrame * 2, synthParams.pFStocWindow); if ((synthParams.pFDetWindow = (float *) calloc(iSizeFrame * 2, sizeof(float))) == NULL) return nil; IFFTwindow (iSizeFrame * 2, synthParams.pFDetWindow); allocateSmsRecord (&newSmsRecord, iMaxTraj, iNCoeff, 0); /* allocate the stochastic data with one more coefficient */ allocateSmsRecord (&(synthParams.previousFrame), iMaxTraj, 1 + iNCoeff, 1); allocateSmsRecord (&smsRecordTmp, iMaxTraj, [idSmsObjHyb getNStochasticCoeff], 0); iRecords = fDur * synthParams.fSamplingRate / synthParams.sizeHop; if (idSmsObjHyb && fDurHyb > 0) { iFirstRecordHyb = [idSmsObjHyb getFrameRate] * fTimeOffsetHyb; iLastRecordHyb = [idSmsObjHyb getFrameRate] * fDurHyb + iFirstRecordHyb; if (iLastRecordHyb <= iFirstRecordHyb || fDurHyb <= 0) fprintf(stderr,"Warning: no samples to hybridize.\n"); fSynthesisRateHyb = iRecords / fDurHyb; } /* loop through the input file */ iFirstSample = MKGetTime() * fSamplingRate; fCurrentLoc = fCurrentLocHyb = 0; while (fCurrentLoc < fDur) { fRecordLoc = [idSmsObj getFrameRate] * fCurrentLoc; iLeftRecord = iFirstRecord + fRecordLoc; fLocation = fCurrentLoc / fDur; fInterpFactor = fRecordLoc - (int) fRecordLoc; if (iLeftRecord <= iLastRecord) [idSmsObj setSmsRecord:iLeftRecord record:&smsRecord1]; if ((iLeftRecord + 1) <= iLastRecord) [idSmsObj setSmsRecord:(1+ iLeftRecord) record:&smsRecord2]; InterpolateSmsRecords (&smsRecord1, &smsRecord2, &newSmsRecord, fInterpFactor); if (idSmsObjHyb && fDurHyb > 0) { fLocationHyb = fCurrentLocHyb / fDurHyb; fRecordLocHyb = [idSmsObjHyb getFrameRate] * fCurrentLocHyb; iLeftRecordHyb = iFirstRecordHyb + fRecordLocHyb; fInterpFactorHyb = fRecordLocHyb - (int) fRecordLocHyb; if (iLeftRecordHyb <= iLastRecordHyb) [idSmsObjHyb setSmsRecord:iLeftRecordHyb record:&smsRecordHyb1]; if ((iLeftRecordHyb + 1) <= iLastRecordHyb) [idSmsObjHyb setSmsRecord:(1+ iLeftRecordHyb) record:&smsRecordHyb2]; InterpolateSmsRecords (&smsRecordHyb1, &smsRecordHyb2, &smsRecordTmp, fInterpFactorHyb); [self _hybridize:&smsRecordTmp location:fLocation]; } [self _changeDetAmp:fLocation weights:pFAmpArray]; [self _changeStocAmp:fLocation weights:pFAmpStocArray]; [self _changeFreq:fLocation weights:pFFreqArray]; [self _stretchPartials:fLocation]; SmsSynthesis(&newSmsRecord, pBuffer, &synthParams); [self _mixToOutput:pBuffer length:iSizeFrame sample:iFirstSample]; iFirstSample += iSizeFrame; fCurrentLoc += (synthParams.sizeHop / synthParams.fSamplingRate) * [self _changeTime:fLocation]; if (idSmsObjHyb) if (fTimeStretchHyb) fCurrentLocHyb += (1 / fSynthesisRateHyb) * [self _changeHybTime:fLocationHyb]; else fCurrentLocHyb += (1 / fSynthesisRateHyb) * [self _changeTime:fLocation]; } freeSmsRecord (&newSmsRecord); freeSmsRecord (&smsRecordTmp); freeSmsRecord (&(synthParams.previousFrame)); free (synthParams.pFStocWindow); free (synthParams.pFDetWindow); if (idSmsObjHyb) [idSmsObjHyb free]; if (pFAmpArray) free (pFAmpArray); if (pFFreqArray) free (pFFreqArray); if (pFAmpStocArray) free (pFAmpStocArray); [idSmsObj free]; free (pBuffer); } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.