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.