This is FluteIns.m in view mode; [Download] [Up]
/* The following files must be imported. */
#import <musickit/musickit.h>
#import <musickit/unitgenerators/unitgenerators.h>
#import "FluteIns.h"
@implementation FluteIns;
/* Statically declare the synthElement indices. */
static int ampAsymp, /* amplitude envelope UG */
inputNoise,
inputMult,
inputAdd, /* adder for envelope and noise */
inputAdd2, /* adder to get exitation */
jetSquarer, /* multiplier to fake reed table */
jetCuber, /* multiplier to fake reed table */
sigAdder, /* adder to approximate sigmoid */
jetAdder, /* adder to get net jet pressure */
reflFilter, /* reflection filter */
delayLine, /* delay UG */
delayLine2, /* delay UG */
gainElement,
stereoOut, /* output UG */
inputNoisePp,
ampPp, /* amplitude patchpoint */
inputMultPp,
inputAddPp,
inputAdd2Pp,
jetSquarerPp,
jetCuberPp,
sigAddPp,
jetAddPp,
filterPp,
delayPp,
delay2Pp,
gainPp; /* output patchpoint */
+patchTemplateFor:aNote
{
/* Step 1: Create (or return) the PatchTemplate. */
static id theTemplate = nil;
if (theTemplate)
return theTemplate;
theTemplate = [PatchTemplate new];
/* Step 2: Add the SynthElement specifications. */
ampAsymp = [theTemplate addUnitGenerator:[AsympUGx class]];
inputNoise = [theTemplate addUnitGenerator:[UnoiseUGy class]];
inputMult = [theTemplate addUnitGenerator:[Mul2UGxyx class]];
inputAdd = [theTemplate addUnitGenerator:[Scl2add2UGyxx class]];
inputAdd2 = [theTemplate addUnitGenerator:[Scl2add2UGxyx class]];
jetSquarer = [theTemplate addUnitGenerator:[Mul2UGxyy class]];
jetCuber = [theTemplate addUnitGenerator:[Mul2UGxyx class]];
sigAdder = [theTemplate addUnitGenerator:[Scl2add2UGxyx class]];
jetAdder = [theTemplate addUnitGenerator:[Scl2add2UGyxx class]];
reflFilter = [theTemplate addUnitGenerator:[OnepoleUGyy class]];
delayLine = [theTemplate addUnitGenerator:[DelayUGxyy class]];
delayLine2 = [theTemplate addUnitGenerator:[DelayUGyxy class]];
gainElement = [theTemplate addUnitGenerator:[ScaleUGyy class]];
stereoOut = [theTemplate addUnitGenerator:[Out2sumUGy class]];
ampPp = [theTemplate addPatchpoint:MK_xPatch];
inputNoisePp = [theTemplate addPatchpoint:MK_yPatch];
inputMultPp = [theTemplate addPatchpoint:MK_xPatch];
inputAddPp = [theTemplate addPatchpoint:MK_yPatch];
inputAdd2Pp = [theTemplate addPatchpoint:MK_xPatch];
jetSquarerPp = [theTemplate addPatchpoint:MK_xPatch];
jetCuberPp = [theTemplate addPatchpoint:MK_xPatch];
sigAddPp = [theTemplate addPatchpoint:MK_xPatch];
jetAddPp = [theTemplate addPatchpoint:MK_yPatch];
filterPp = [theTemplate addPatchpoint:MK_yPatch];
delayPp = [theTemplate addPatchpoint:MK_xPatch];
delay2Pp = [theTemplate addPatchpoint:MK_yPatch];
gainPp = [theTemplate addPatchpoint:MK_yPatch];
/* Step 3: Specify the connections. */
[theTemplate to:ampAsymp sel:@selector(setOutput:) arg:ampPp];
[theTemplate to:inputNoise sel:@selector(setOutput:) arg:inputNoisePp];
[theTemplate to:inputMult sel:@selector(setOutput:) arg:inputMultPp];
[theTemplate to:inputMult sel:@selector(setInput1:) arg:inputNoisePp];
[theTemplate to:inputMult sel:@selector(setInput2:) arg:ampPp];
[theTemplate to:inputAdd sel:@selector(setOutput:) arg:inputAddPp];
[theTemplate to:inputAdd sel:@selector(setInput1:) arg:inputMultPp];
[theTemplate to:inputAdd sel:@selector(setInput2:) arg:ampPp];
[theTemplate to:inputAdd2 sel:@selector(setOutput:) arg:inputAdd2Pp];
[theTemplate to:inputAdd2 sel:@selector(setInput1:) arg:inputAddPp];
[theTemplate to:inputAdd2 sel:@selector(setInput2:) arg:delayPp];
[theTemplate to:jetSquarer sel:@selector(setOutput:) arg:jetSquarerPp];
[theTemplate to:jetSquarer sel:@selector(setInput1:) arg:delay2Pp];
[theTemplate to:jetSquarer sel:@selector(setInput2:) arg:delay2Pp];
[theTemplate to:jetCuber sel:@selector(setOutput:) arg:jetCuberPp];
[theTemplate to:jetCuber sel:@selector(setInput1:) arg:delay2Pp];
[theTemplate to:jetCuber sel:@selector(setInput2:) arg:jetSquarerPp];
[theTemplate to:sigAdder sel:@selector(setOutput:) arg:sigAddPp];
[theTemplate to:sigAdder sel:@selector(setInput1:) arg:delay2Pp];
[theTemplate to:sigAdder sel:@selector(setInput2:) arg:jetCuberPp];
[theTemplate to:jetAdder sel:@selector(setOutput:) arg:jetAddPp];
[theTemplate to:jetAdder sel:@selector(setInput1:) arg:sigAddPp];
[theTemplate to:jetAdder sel:@selector(setInput2:) arg:delayPp];
[theTemplate to:reflFilter sel:@selector(setOutput:) arg:filterPp];
[theTemplate to:reflFilter sel:@selector(setInput:) arg:jetAddPp];
[theTemplate to:delayLine sel:@selector(setOutput:) arg:delayPp];
[theTemplate to:delayLine sel:@selector(setInput:) arg:filterPp];
[theTemplate to:delayLine2 sel:@selector(setOutput:) arg:delay2Pp];
[theTemplate to:delayLine2 sel:@selector(setInput:) arg:inputAdd2Pp];
[theTemplate to:gainElement sel:@selector(setOutput:) arg:gainPp];
[theTemplate to:gainElement sel:@selector(setInput:) arg: jetAddPp];
/* Return the PatchTemplate. */
return theTemplate;
}
- init
{
/* Sent once when the patch is created. */
return self;
}
- setDefaults
{
ampEnv = nil;
amp0 = 0.0;
amp1 = MK_DEFAULTAMP; /* 0.1 */
ampAtt = MK_NODVAL; /* parameter not present */
ampRel = MK_NODVAL; /* parameter not present */
portamento = MK_DEFAULTPORTAMENTO; /* 0.1 */
bearing = MK_DEFAULTBEARING; /* 0.0 (centered) */
return self;
}
- preemptFor:aNote
{
[[self synthElementAt:ampAsymp] preemptEnvelope];
[self setDefaults];
return self;
}
- applyParameters:aNote
/* This is a private method to the InsTwoWaves class. It is used internally only.
*/
{
/* Retrieve and store the parameters. */
id myAmpEnv = [aNote parAsEnvelope:MK_ampEnv];
double myAmp0 = [aNote parAsDouble:MK_amp0];
double myAmp1 = [aNote parAsDouble:MK_amp1];
double myAmpAtt = [aNote parAsDouble:MK_ampAtt];
double myAmpRel = [aNote parAsDouble:MK_ampAtt];
int MY_envelopeSlew = [[Note class] parName: "MY_envelopeSlew"];
double myEnvelopeSlew = [aNote parAsDouble:MY_envelopeSlew];
int MY_noiseVolume = [[Note class] parName: "MY_noiseVolume"];
double myNoiseVolume = [aNote parAsDouble:MY_noiseVolume];
int MY_delay2Length = [[Note class] parName: "MY_delay2Length"];
double myDelay2Length = [aNote parAsDouble:MY_delay2Length];
int MY_outAmp = [[Note class] parName: "MY_outAmp"];
int MY_dLineLength = [[Note class] parName: "MY_dLineLength"];
double myOutAmp = [aNote parAsDouble:MY_outAmp];
double myDLineLength = [aNote parAsDouble:MY_dLineLength];
double myPortamento = [aNote parAsDouble:MK_portamento];
double myBearing = [aNote parAsDouble:MK_bearing];
/* Store the phrase status. */
MKPhraseStatus phraseStatus = [self phraseStatus];
/* Is aNote a noteOn? */
// BOOL isNoteOn = [aNote noteType] == MK_noteOn;
/* Is aNote the beginning of a new phrase? */
BOOL isNewPhrase = (phraseStatus == MK_phraseOn) ||
(phraseStatus == MK_phraseOnPreempt);
/* Used in the parameter checks. */
BOOL shouldApplyAmp = NO;
BOOL shouldApplyBearing = NO;
/* The same portamento is used in both frequency and amplitude. */
if (!MKIsNoDVal(myPortamento)) {
portamento = myPortamento;
shouldApplyAmp = YES;}
/* Check the amplitude parameters and set the instance variables. */
if (myAmpEnv != nil) {
ampEnv = myAmpEnv;
shouldApplyAmp = YES; }
if (!MKIsNoDVal(myAmp0)) {
amp0 = myAmp0;
shouldApplyAmp = YES; }
if (!MKIsNoDVal(myAmp1)) {
amp1 = myAmp1;
// [[self synthElementAt:ampAsymp] abortEnvelope];
// [[self synthElementAt:ampAsymp] setT60: 0.01];
[[self synthElementAt:ampAsymp] setTargetVal:amp1];
}
if (!MKIsNoDVal(myEnvelopeSlew)) {
[[self synthElementAt:ampAsymp] setT60: myEnvelopeSlew];
// Hack this for slew on breath pressure
}
if (!MKIsNoDVal(myAmpAtt)) {
ampAtt = myAmpAtt;
shouldApplyAmp = YES; }
if (!MKIsNoDVal(myAmpRel)) {
ampRel = myAmpRel;
shouldApplyAmp = YES; }
/* Apply the amplitude parameters. */
// if (shouldApplyAmp || isNoteOn) {
// MKUpdateAsymp([self synthElementAt:ampAsymp],
// ampEnv, amp0, amp1, ampAtt, ampRel,
// portamento, phraseStatus);
// }
/* Check and set the bearing. */
if (!MKIsNoDVal(myBearing)) {
bearing = myBearing;
shouldApplyBearing = YES; }
if (shouldApplyBearing || isNewPhrase)
[[self synthElementAt:stereoOut] setBearing:bearing];
[[self synthElementAt:inputAdd2] setScale1: 1.0];
[[self synthElementAt:inputAdd2] setScale2: -0.35];
[[self synthElementAt:sigAdder] setScale1: -1.0];
[[self synthElementAt:sigAdder] setScale2: 1.0];
[[self synthElementAt:jetAdder] setScale1: 0.4];
[[self synthElementAt:jetAdder] setScale2: 0.90];
[[self synthElementAt:reflFilter] setB0: 0.7];
[[self synthElementAt:reflFilter] setA1: -0.3];
/* Check and set the embouchure. */
if (!MKIsNoDVal(myDelay2Length)) {
delay2Length = myDelay2Length;
[[self synthElementAt:delayLine2] adjustLength:delay2Length];
}
/* Check and set the embouchure. */
if (!MKIsNoDVal(myNoiseVolume)) {
noiseVolume = myNoiseVolume;
[[self synthElementAt:inputAdd] setScale1:myNoiseVolume];
[[self synthElementAt:inputAdd] setScale2: 1.0];
}
/* Check and set the fader level. */
if (!MKIsNoDVal(myOutAmp)) {
outAmp = myOutAmp;
[[self synthElementAt:gainElement] setScale:outAmp];
}
if (!MKIsNoDVal(myDLineLength)) {
dLineLength = myDLineLength;
[[self synthElementAt:delayLine] adjustLength:(int) dLineLength];
}
return self;
}
- noteOnSelf:aNote
{
delayMemory = [Orchestra allocSynthData:MK_yData length:100];
[[self synthElementAt: delayLine] setDelayMemory: delayMemory];
[delayMemory setToConstant:0 length:100 offset:0];
delayMemory2 = [Orchestra allocSynthData:MK_yData length:40];
[[self synthElementAt: delayLine2] setDelayMemory: delayMemory2];
[delayMemory2 setToConstant:0 length:40 offset:0];
/* Apply the parameters to the patch. */
[self applyParameters:aNote];
/* Make the final connection to the output sample stream. */
[[self synthElementAt:stereoOut] setInput:[self synthElementAt:gainPp]];
/* Tell the UnitGenerators to begin running. */
[synthElements makeObjectsPerform:@selector(run)];
return self;
}
- noteUpdateSelf:aNote
{
/* Apply the parameters to the patch. */
[self applyParameters: aNote];
return self;
}
- (double)noteOffSelf:aNote
{
/* Apply the parameters. */
[self applyParameters: aNote];
/* Same for amplitude, but also return the release duration. */
return [[self synthElementAt:ampAsymp] finish];
}
- noteEndSelf
{
/* Remove the patch's Out2sum from the output sample stream. */
[[self synthElementAt:stereoOut] idle];
/* Abort the frequency Envelope. */
[[self synthElementAt:ampAsymp] abortEnvelope];
/* Set the instance variables to their default values. */
[self setDefaults];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.