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.