This is Envy.m in view mode; [Download] [Up]
#import <musickit/unitgenerators/unitgenerators.h> #import "Envy.h" /* We call our simple SynthPatch with Envelopes 'Envy'. */ @implementation Envy; /* Statically declare the synthElement indices. */ static int ampAsymp, /* amplitude envelope UG */ freqAsymp, /* frequency envelope UG */ osc, /* oscillator UG */ stereoOut, /* output UG */ ampPp, /* amplitude patchpoint */ freqPp, /* frequency patchpoint */ outPp; /* output patchpoint */ +patchTemplateFor:aNote { /* Step 1: Create (or return) the PatchTemplate. */ static PatchTemplate *theTemplate = nil; if (theTemplate) return theTemplate; theTemplate = [[PatchTemplate alloc] init]; /* Step 2: Add the SynthElement specifications. */ ampAsymp = [theTemplate addUnitGenerator:[AsympUGx class]]; freqAsymp = [theTemplate addUnitGenerator:[AsympUGy class]]; osc = [theTemplate addUnitGenerator:[OscgafiUGxxyy class]]; stereoOut = [theTemplate addUnitGenerator:[Out2sumUGx class]]; ampPp = [theTemplate addPatchpoint:MK_xPatch]; freqPp = [theTemplate addPatchpoint:MK_yPatch]; outPp = ampPp; /* Step 3: Specify the connections. */ [theTemplate to:ampAsymp sel:@selector(setOutput:) arg:ampPp]; [theTemplate to:freqAsymp sel:@selector(setOutput:) arg:freqPp]; [theTemplate to:osc sel:@selector(setAmpInput:) arg:ampPp]; [theTemplate to:osc sel:@selector(setIncInput:) arg:freqPp]; [theTemplate to:osc sel:@selector(setOutput:) arg:outPp]; /* Return the PatchTemplate. */ return theTemplate; } - init { /* Sent once when the patch is created. */ [[self synthElementAt:osc] setTable:nil defaultToSineROM:YES]; 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 */ freqEnv = nil; freq0 = 0.0; freq1 = MK_DEFAULTFREQ; /* 440.0 */ freqAtt = MK_NODVAL; /* parameter not present */ freqRel = MK_NODVAL; /* parameter not present */ portamento = MK_DEFAULTPORTAMENTO; /* 0.1 */ bearing = MK_DEFAULTBEARING; /* 0.0 (centered between speakers) */ return self; } - preemptFor:aNote { [[self synthElementAt:ampAsymp] preemptEnvelope]; [self setDefaults]; return self; } #define valid(_x) (!MKIsNoDVal(_x)) - applyParameters:aNote /* This is a private method to the Envy class. It is used internally only. */ { /* Retrieve and store the parameters. */ Envelope * 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]; Envelope * myFreqEnv = [aNote parAsEnvelope:MK_freqEnv]; double myFreq0 = [aNote parAsDouble:MK_freq0]; double myFreq1 = [aNote freq]; double myFreqAtt = [aNote parAsDouble:MK_freqAtt]; double myFreqRel = [aNote parAsDouble:MK_freqRel]; 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 shouldApplyFreq = NO; BOOL shouldApplyBearing = NO; /* The same portamento is used in both frequency and amplitude. */ if (valid(myPortamento)) { portamento = myPortamento; shouldApplyAmp = YES; shouldApplyFreq = YES; } /* Check the amplitude parameters and set the instance variables. */ if (myAmpEnv != nil) { ampEnv = myAmpEnv; shouldApplyAmp = YES; } if (valid(myAmp0)) { amp0 = myAmp0; shouldApplyAmp = YES; } if (valid(myAmp1)) { amp1 = myAmp1; shouldApplyAmp = YES; } if (valid(myAmpAtt)) { ampAtt = myAmpAtt; shouldApplyAmp = YES; } if (valid(myAmpRel)) { ampRel = myAmpRel; shouldApplyAmp = YES; } /* Apply the amplitude parameters. */ if (shouldApplyAmp || isNoteOn) MKUpdateAsymp([self synthElementAt:ampAsymp], ampEnv, amp0, amp1, ampAtt, ampRel, portamento, phraseStatus); /* Check the freqeuncy parameters and set the instance variables. */ if (myFreqEnv != nil) { freqEnv = myFreqEnv; shouldApplyFreq = YES; } if (valid(myFreq0)) { freq0 = myFreq0; shouldApplyFreq = YES; } if (valid(myFreq1)) { freq1 = myFreq1; shouldApplyFreq = YES; } if (valid(myFreqAtt)) { freqAtt = myFreqAtt; shouldApplyFreq = YES; } if (valid(myFreqRel)) { freqRel = myFreqRel; shouldApplyFreq = YES; } /* Apply the frequency parameters. */ if (shouldApplyFreq || isNoteOn) MKUpdateAsymp([self synthElementAt:freqAsymp], freqEnv, [[self synthElementAt:osc] incAtFreq:freq0], [[self synthElementAt:osc] incAtFreq:freq1], freqAtt, freqRel, portamento, phraseStatus); /* Check and set the bearing. */ if (valid(myBearing)) { bearing = myBearing; shouldApplyBearing = YES; } if (shouldApplyBearing || isNewPhrase) [[self synthElementAt:stereoOut] setBearing:bearing]; return self; } - noteOnSelf:aNote { /* Apply the parameters to the patch. */ [self applyParameters:aNote]; /* Make the final connection to the output sample stream. */ [[self synthElementAt:stereoOut] setInput:[self synthElementAt:outPp]]; /* 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]; /* Signal the release portion of the frequency Envelope. */ [[self synthElementAt:freqAsymp] finish]; /* 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:freqAsymp] 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.