This is FakeUG.m in view mode; [Download] [Up]
/**************************************************
* SynthBuilder
* Copyright 1993 Nick Porcaro All Rights Reserved
**************************************************/
/* #define DEBUG_BACKWARD 1 */
/* #define DEBUG_ERASE 1 */
/*
* FakeUG.m
* Eric Jordan, independent work, Spring, 1992
*
* Nick Porcaro, independent work, Summer 1993
*
* - Added new inspector.
*
* --> Arguments are updated when the user enters return
* (left as an excersise for later to do correctly)
*
* --> The buttons next to each field either open a slider
* or an envelope editor
*/
#import <stdlib.h>
#import <stdio.h>
#import <sys/file.h>
#import <appkit/Application.h>
#import <appkit/Matrix.h>
#import <ctype.h>
#import <dpsclient/psops.h>
#import <dpsclient/wraps.h>
#import <appkit/publicWraps.h>
#import <strings.h>
#import <musickit/musickit.h>
#import <musickit/unitgenerators/AsympUG.h>
#import <appkit/TextField.h>
#import "FakeSynthPatch.h"
#import "FakePatchPoint.h"
#import "Controller.h"
#import "UGDef.h"
#import "UGArgDef.h"
#import "UGMethodDef.h"
#import "PatchParam.h"
#import "Clavier.h"
#import "UGArgSlider.h"
#import "EnvDelegate.h"
#import "EnvController.h"
#import "FakeUG.h"
#import "Utilities.h"
#import "ElementController.h"
#import "Controller.h"
static char ErrorMsg[1024];
extern char *getAppName();
#define NODESIZE 10
@implementation FakeUG
static char TempString[1024];
static int uniquename = 0;
+ initialize
/* Set the version. This can be used in a later version to distinguish older
* formats when unarchiving documents.
*/
{
[FakeUG setVersion:5];
return self;
}
- awakeFromNib
{
clavInit = NO;
clickCount = 0;
return self;
}
- init
{
int i;
[super init];
allocOrder = 1;
for (i=0;i<MAXCONNECTIONS;i++)
{
connections[i]=nil;
}
for (i=0;i<MAXNOTEPARAMETERS;i++)
{
arg[i] = NULL;
envDelegate[i] = nil;
argEnvelope[i] = nil;
argEnabled[i] = YES;
slider[i] = nil;
}
isAllocated = NO;
strcpy(theName, "");
clavier = nil;
midi = nil;
noteFilter = nil;
patchParam = nil;
clickCount = 0;
useInspectorRect = NO;
inspectorRectJustLoaded = NO;
return self;
}
- takeArgEnableFrom:sender
{
argEnabled[currArg] = ([sender intValue] ? YES : NO);
return self;
}
- (BOOL) isArgEnabled:(int) num
{
BOOL rval;
if ((num >=0) && (num < MAXNOTEPARAMETERS))
{
rval = argEnabled[num];
}
else
{
/* Request was out of bounds */
rval = NO;
}
return rval;
}
- takeAllocOrderFrom:sender
{
int button, order, ival, maxOrder;
maxOrder = [[theSP getFakeUGs] count];
order = [self getAllocOrder];
if ([sender isKindOfClassNamed: "TextField"])
{
ival = [sender intValue];
if ((ival <= maxOrder) && (ival >=1))
{
[self setAllocOrder:order];
[theSP sortFakeUGsByAllocOrder];
[self updateAllocOrder];
}
else
{
NXRunAlertPanel(getAppName(), "Invalid order: %d Must be between 1 and %d",
NULL, NULL, NULL, ival, maxOrder);
[sender setIntValue:order];
return self;
}
}
else
{
/* Get order from switcher */
/* button = -1 for top, 1 for bottom */
button = [[sender selectedCell] tag];
order += button;
/* Only set a new order if it's within range */
if ((order <= maxOrder) && (order >= 1))
{
[self setAllocOrder:order];
[theSP sortFakeUGsByAllocOrder];
[self updateAllocOrder];
}
}
return self;
}
- setAllocOrder:(int) order
{
allocOrder = order;
return self;
}
- (int) getAllocOrder
{
return allocOrder;
}
- updateAllocOrder
{
if (argCount > 0)
{
[allocOrderField setIntValue:allocOrder];
}
else
{
[allocOrderField2 setIntValue:allocOrder];
}
return self;
}
- setSP:aSP
{
theSP = aSP;
return self;
}
- getSP
{
return theSP;
}
- initWithDef: aUGDef WithPatch:aSP
{
[self setSP: aSP];
[self initUGDef: aUGDef];
[self initSubviews];
[self setDefaultValues];
[self validate];
return self;
}
- initUGDef: aUGDef
{
theUGDef = aUGDef;
theMethods = [theUGDef methods];
methodCount = [theMethods count];
theArgs = [theUGDef arguments];
argCount = [theArgs count];
sprintf(theName, "%c%s%i", tolower([self getTypeString][0]),
[self getTypeString]+1, uniquename++);
theImage = [NXImage findImageNamed:[theUGDef getIconFile]];
if (!theImage)
{
sprintf(TempString, "Cannot find image for: %s", [theUGDef getName]);
NXRunAlertPanel(getAppName(), TempString, NULL, NULL, NULL);
return nil;
}
return self;
}
- setDefaultValues
/* This assumes you called initUGDef first */
{
int i;
int len;
char *aStr;
UGArgDef *anArg;
if (! [theSP useDefaultArgValues])
{
return self;
}
/* Set the default parameter values
* and the right stuff in the inspector
*/
for (i=0; i<argCount; i++)
{
anArg = [theArgs objectAt:i];
aStr = [anArg defaultValue];
if (aStr)
{
len = strlen(aStr);
len += 1;
if (arg[i])
{
NXZoneFree([self zone], arg[i]);
}
/*ME* Observed malloc error here on load: old save new, load old */
if (NXMallocCheck())
{
printf("malloc error!!!!\n");
}
arg[i] = (char *) NXZoneCalloc([self zone], len, sizeof(char));
strcpy(arg[i], aStr);
}
}
return self;
}
- initSubviews
/* This assumes you called initUGDef first */
{
int i;
UGMethodDef *aMethod;
for (i=0; i<methodCount; i++)
{
NXRect *newrect = (NXRect *) NXZoneMalloc([self zone], sizeof (*newrect));
id newnode = [[NodeView alloc] init];
[newnode setPatch:[self thePatch]];
aMethod = [theMethods objectAt:i];
[newnode setTag:i];
[self addSubview:newnode];
NXSetRect(newrect,
[aMethod xCoord] - NODESIZE/2,
[aMethod yCoord] - NODESIZE/2,
NODESIZE,NODESIZE);
#ifdef DEBUG_PARAM
DEBUG_PRINT("fakeUG %s: Created node with tag %d at x: %d y: %d\n",
[self getTypeString], [newnode getTag],
[aMethod xCoord], [aMethod yCoord]);
#endif DEBUG_PARAM
[newnode setFrame:newrect];
[newnode display];
}
return self;
}
- checkSubviews
/* This ensures the subview indices are equal to the NodeView tags
* This was a problem with old files
*/
{
int i;
int nodeViewCount;
id nodeView;
nodeViewCount = [subviews count];
if (nodeViewCount != methodCount)
{
sprintf(TempString, "Internal error file: %s line: %d", __FILE__, __LINE__);
NXRunAlertPanel(getAppName(), TempString, NULL, NULL, NULL);
return self;
}
for (i=0; i<nodeViewCount; i++)
{
nodeView = [subviews objectAt:i];
if ( ![nodeView isKindOfClassNamed: "NodeView"])
{
sprintf(TempString, "Internal error file: %s line: %d", __FILE__, __LINE__);
NXRunAlertPanel(getAppName(), TempString, NULL, NULL, NULL);
return self;
}
[nodeView setTag:i];
}
return self;
}
- displayArg:(int) i
{
[argName setStringValue:[[[theUGDef arguments] objectAt:i] getName]];
if ([self getArgType:i] == PARTIALS)
{
/* Can't inspect partials yet */
[argButton setEnabled:NO];
}
else
{
[argButton setEnabled:YES];
}
if ([self getArgType:i] == ENV)
{
/* Don't let the user futs with the envelope field */
[argVal setEditable:NO];
[argVal setSelectable:YES];
}
else
{
[argVal setEnabled:YES];
[argVal setEditable:YES];
}
if (! arg[i])
{
[argVal setStringValue: ""];
}
else
{
[argVal setStringValue: arg[i]];
}
if (argCount > 0)
{
[argIndexField setIntValue:i+1];
}
if (slider[i])
{
[slider[i] takeSliderValueFrom:argVal];
}
if (argEnabled[i])
{
[argEnabledSwitch setIntValue:1];
}
else
{
[argEnabledSwitch setIntValue:0];
}
return self;
}
- checkConnections
{
int i, j, k;
id temp_connections[MAXCONNECTIONS];
id theToNodes;
/* Older versions allowed connections[0]
* to be non-nil, and the newer versions
* don't. Deal with this by re-organizing
* the connections array so it has no empty slots
* before non-empty slots
*/
for (i=0; i<MAXCONNECTIONS; i++)
{
temp_connections[i] = nil;
}
j = 0;
for (i=0; i<MAXCONNECTIONS; i++)
{
if (connections[i])
{
temp_connections[j++] = connections[i];
}
}
if (j > 0)
{
#ifdef DEBUG_BACKWARD
printf("** Reprocessing %d connections for: %s\n\n", j, [self getName]);
#endif DEBUG_BACKWARD
for (i=0; i<j; i++)
{
connections[i] = temp_connections[i];
theToNodes = [connections[i] getToNodes];
#ifdef DEBUG_BACKWARD
printf("$$ Set connection[%d] = temp_connection[%d]: %s ToNode ct: %d\n",
i, i, [connections[i] getName],
(int) [theToNodes count]);
#endif DEBUG_BACKWARD
for (k=0; k<[theToNodes count]; k++)
{
#ifdef DEBUG_BACKWARD
printf(">> Node: %d tag: %d FakeUG: %s\n",
k,
[[theToNodes objectAt:k] getTag],
[[[theToNodes objectAt:k] superview] getName]);
#endif DEBUG_BACKWARD
}
}
for (i=j; i<MAXCONNECTIONS; i++)
{
connections[i] = nil;
#ifdef DEBUG_BACKWARD
printf("nilling connection: %d\n", i);
#endif DEBUG_BACKWARD
}
}
[self checkSubviews];
#ifdef DEBUG_BACKWARD
[self printConnections];
#endif DEBUG_BACKWARD
return self;
}
- printConnections
{
int i, j;
id theToNodes, toFakeUG;
for (i=0; i<MAXCONNECTIONS; i++)
{
if (connections[i])
{
printf("%s: Connection: %d from: %s (tag %d) to:",
[self getName],
i,
[[connections[i] getFromFakeUG] getName],
[[connections[i] getFromNode] getTag]);
theToNodes = [connections[i] getToNodes];
for (j=0; j<[theToNodes count]; j++)
{
toFakeUG = [[theToNodes objectAt:j] superview];
printf(" %s tag: %d",
[toFakeUG getName],
[ [theToNodes objectAt:j] getTag]);
}
printf("\n");
}
}
return self;
}
- validate
/* Make sure we are together
* This is useful to do if we have
* just loaded an existing file that may
* be out of date, and in the case where the fakeUG
* is a Clavier or PatchParameter
*/
{
int aType;
isSoundMaker = NO;
if (!theUGDef || ![theUGDef isKindOfClassNamed: "UGDef"])
{
sprintf(TempString, "Internal error file: %s line: %d", __FILE__, __LINE__);
NXRunAlertPanel(getAppName(), TempString, NULL, NULL, NULL);
return self;
}
aType = [theUGDef getMetaType];
/* Check for consistency
*/
if ( (aType != PP_UG) && (aType != CLAV_UG) && (aType != MIDI_UG))
{
/* A little paranoia from a previous bug */
if (!theUGDef || ![theUGDef isKindOfClassNamed: "UGDef"])
{
sprintf(TempString, "Internal error file: %s line: %d", __FILE__, __LINE__);
NXRunAlertPanel(getAppName(), "Internal error file: %s line: %d", NULL, NULL, NULL);
return self;
}
}
theMethods = [theUGDef methods];
methodCount = [theMethods count];
theArgs = [theUGDef arguments];
argCount = [theArgs count];
switch (aType)
{
case (MK_UG):
{
isSoundMaker = YES;
if (argCount > 0)
{
currArg = 0;
}
break; /* Just a regular audio UG */
}
case (CLM_UG):
{
NXRunAlertPanel(getAppName(),
"Sorry I cannot deal with CLM UGs yet",
NULL, NULL, NULL);
break;
}
case (PP_UG):
{
/* Allocate a PatchParameter if necessary
* When the user double clicks on the icon
* the editor scene will "just happen" because
* we allocate all the cool stuff here.
*/
if (! patchParam)
{
/* New PP */
patchParam = [[PatchParam alloc] init];
[patchParam setPatch:[self thePatch]];
[patchParam setViewFakeUG:self];
[patchParam setPatchParamName:theName];
}
else
{
/* PP just read from file */
[patchParam setPatch:[self thePatch]];
[patchParam setViewFakeUG:self];
}
break;
}
case (CLAV_UG):
{
if (! clavier)
{
clavier = [[Clavier alloc] init];
[clavier initConnectionWithPatch:[self thePatch] WithFakeUG: self];
[clavier setClavierName:theName];
}
break;
}
case (MIDI_UG):
{
midi = [theSP midi];
inspector = nil;
noArgInspector = nil;
break;
}
default:
{
break;
}
}
return self;
}
- getImage
{
return theImage;
}
- (BOOL)getErasing
{
return erasing;
}
- (char *)getName
{
return theName;
}
- changeName:(char *)aName
{
int len;
if (! [[theSP utilities] checkName:aName])
{
[fakeUGName setStringValue:theName];
return nil;
}
len = strlen(aName) + 1;
strcpy(theName, aName);
[self setInspectorName:theName];
return self;
}
- takeNameFrom:sender
{
[self changeName: (char *)[sender stringValue]];
return self;
}
- (char *)getTypeString
/* This returns a string that indentifies
* the unit generator class used to make sound for this FakeUG
* The name of the class is based on the root class name
* plus "x" if its connections (other than data connections)
* are from x memory, and "y" if they are in y-memory.
*/
{
int i;
static char s[1024];
/* There is a special case for Biquads. They're output
* must be y memory, and they only have leaf classes
* with a single x or y. Hence, the only issue
* is what memory location the input of the Biquad uses.
* If it uses x memory, return BiquadUGx, else return BiquadUGy.
*/
strcpy(s, [theUGDef getType]);
if (strcmp(s, "BiquadUG") == 0)
{
if (! connections[0] && ! connections[1])
{
/* This means the biquad is unconnected */
return "BiquadUG";
}
else if ([connections[0] getXMemory] || [connections[1] getXMemory])
{
return "BiquadUGx";
}
else
{
return "BiquadUGy";
}
}
for (i=0; i<[theMethods count]; i++)
{
if ((connections[i] != nil) && ![self isData])
{
if ([connections[i] getXMemory])
{
sprintf(s,"%sx",s);
}
else
{
sprintf(s,"%sy",s);
}
}
}
if ([theUGDef isADSwitch] && connections[1] && connections[2])
{
s[strlen(s)-1]='\0';
}
return s;
}
- (char *)getGenericTypeString
{
return [theUGDef getType];
}
- (BOOL)isAFakeUG
{
/* We have to tell the recepient of a message that uses
* a FakeUG object that the object is in fact a FakeUG (late binding in action!)
*/
return YES;
}
- (BOOL)isAFakePatchPoint
{
return NO;
}
- (char *)getConnectionName:(int)connectionNumber
{
UGMethodDef *aMethod;
aMethod = [theMethods objectAt:connectionNumber];
return [aMethod getName];
}
- setConnection:(int)connectionNumber toFakePatchPoint:fakePatchPoint
{
connections[connectionNumber] = fakePatchPoint;
return self;
}
- getConnection:(int)connectionNumber
{
return connections[connectionNumber];
}
- getUG
{
return ug;
}
- (int)getArgType:(int)i
{
return [[theArgs objectAt:i] argType];
}
- allocateUGMK
{
if (isAllocated)
{
#ifdef DEBUG_PARAM
DEBUG_PRINT("ug: %s already allocated\n", [self getName]);
#endif DEBUG_PARAM
return self;
}
if (![self isPatchParameter] &&
![self isMidi] &&
![self isClavier] &&
![self isData])
{
ug = [[superview getOrch]
allocUnitGenerator:objc_getClass([self getTypeString])];
if (! ug)
{
sprintf(ErrorMsg,
"Is DSP being used by another app? Could not allocate %s",
[self getName]);
NXRunAlertPanel(getAppName(), ErrorMsg, NULL, NULL, NULL);
return nil;
}
#ifdef DEBUG_PARAM
DEBUG_PRINT("*** ug: %s allocated\n", [self getName]);
#endif DEBUG_PARAM
isAllocated = YES;
}
return self;
}
- runMK
{
if (isSoundMaker)
{
[ug run];
}
return self;
}
- deallocUGMK
{
if (isSoundMaker)
{
[ug finish];
[ug dealloc];
ug = nil;
isAllocated = NO;
}
return self;
}
- (BOOL)isEnvelopeHandler
{
return [theUGDef isEnvelopeHandler];
}
- (BOOL)isDSwitch
{
return [theUGDef isADSwitch];
}
- (BOOL)isData
{
return [theUGDef isData];
}
- (BOOL)isStorage
{
return [theUGDef isStorage];
}
- (BOOL)isOscg
{
return [theUGDef isOscg];
}
- (BOOL)isSineROM
{
return [theUGDef isSineROM];
}
- (int)getLength
{
return ([theUGDef hasLength] ?
((arg[0]==NULL) ? 0 : atoi(arg[0])) :
16);
}
- (BOOL)hasLength
{
return [theUGDef hasLength];
}
- (BOOL)hasConstant
{
if (! [theUGDef hasConstant])
return NO;
if (![self getConstant])
return NO;
return YES;
}
- (char *)getConstant
{
if ([theUGDef hasLength])
return arg[1];
else
return arg[0];
}
- setConstantPP:(double) value
{
int i;
id aPP;
/* Set the constant for each connection to this
* constant PP to value
*/
for (i=0; i<MAXCONNECTIONS; i++)
{
if (connections[i])
{
aPP = [connections[i] getpp];
if (aPP)
{
[aPP setToConstant: DSPDoubleToFix24(value)];
}
}
}
return self;
}
- (BOOL)isComplete
/* Returns YES if the fakeUG has all its connections made */
{
int i;
BOOL rval = YES;
if (isSoundMaker)
{
for (i=0; i<methodCount; i++)
{
if (!connections[i])
{
rval = NO;
}
}
}
else
{
rval = NO;
}
return rval;
}
- (BOOL)acceptsFirstMouse
{
return YES;
}
- (BOOL)acceptsFirstResponder
{
return NO;
}
- drawSelf:(BOOL)instance
{
NXPoint *thePoint = (NXPoint *)NXZoneMalloc([self zone], sizeof(*thePoint));
int i;
thePoint->x = thePoint->y = 0.0;
if ([superview getSelected]==self)
[theImage composite:NX_COPY toPoint:thePoint];
else
[theImage composite:NX_SOVER toPoint:thePoint];
[self unlockFocus];
for (i=0; i<MAXCONNECTIONS; i++)
if (connections[i]!=nil)
{
[connections[i] lockFocus];
if (instance)
PSsetinstance(YES);
[connections[i] drawSelf:NULL :0];
if (instance)
PSsetinstance(NO);
[connections[i] unlockFocus];
}
[self lockFocus];
return self;
}
- eraseSelf
{
int i;
NXRect *rect = (NXRect *)NXZoneMalloc ([self zone], sizeof (*rect));
rect->origin.x = frame.origin.x;
rect->origin.y = frame.origin.y;
rect->size.width = frame.size.width;
rect->size.height = frame.size.height;
[self convertRectFromSuperview:rect];
PSsetgray(NX_LTGRAY);
NXRectFill(rect);
for (i=0; i<MAXCONNECTIONS; i++)
if (connections[i]!=nil)
{
[self unlockFocus];
[connections[i] lockFocus];
[connections[i] eraseSelf];
#ifdef DEBUG_ERASE
printf("(FakeUG %s - eraseSelf) Erased connection %d pp: %s\n",
[self getName], i, [connections[i] getName]);
#endif DEBUG_ERASE
[connections[i] unlockFocus];
[self lockFocus];
}
erasing = YES;
[self unlockFocus];
[superview display];
[self lockFocus];
erasing = NO;
return self;
}
- closeInspector
{
int i;
for (i=0; i<MAXNOTEPARAMETERS; i++)
{
if (slider[i])
{
[slider[i] closeInspector];
}
if (envDelegate[i])
{
[envDelegate[i] closeInspector];
}
}
if ( (argCount > 0) && inspector)
{
[inspector performClose:self];
}
else if (noArgInspector)
{
[noArgInspector performClose:self];
}
if ([self isPatchParameter])
{
[patchParam closeInspector];
}
if ([self isClavier])
{
[clavier closeInspector];
}
inspectorDisplayed = NO;
return self;
}
- removeSelf
{
int i;
[self lockFocus];
[self closeInspector];
[self eraseSelf];
[self unlockFocus];
for (i=0; i<MAXCONNECTIONS; i++)
if (connections[i]!=nil)
{
id temp = connections[i];
[temp removeSelf];
[temp free];
}
/* Now fix the envelopes
* The next time an envelope inspector comes
* up it will use the new envelope we
* just read in with a new envDelegate
*/
for (i=0; i<MAXNOTEPARAMETERS; i++)
{
if (envDelegate[i])
{
[envDelegate[i] free];
envDelegate[i] = nil;
}
if (argEnvelope[i])
{
[argEnvelope[i] free];
argEnvelope[i] = nil;
}
}
if (patchParam)
{
[patchParam free];
}
if ([theUGDef isMidi])
{
[theSP setHaveMidi:NO];
}
[superview remFakeUGFromList:self];
return self;
}
- remConnection:(int)i
{
connections[i]=nil;
#ifdef DEBUG_ERASE
printf("(FakeUG %s - remConnection) Nilled connection %d\n",
[self getName], i);
#endif DEBUG_ERASE
return self;
}
- nilConnectionsWithId:aFakePatchPoint
{
int i;
for (i=0; i<MAXCONNECTIONS; i++)
{
if (connections[i] && (connections[i] == aFakePatchPoint))
{
connections[i] = nil;
}
}
return self;
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
if (!erasing)
{
[self drawSelf:NO];
NXPing();
}
return self;
}
- mouseDown:(NXEvent *)theEvent
{
mouseUpRespond = YES;
[window addToEventMask:NX_LMOUSEDRAGGEDMASK];
noMovement = YES;
whereGrabbed = theEvent->location;
[self convertPoint:&whereGrabbed fromView:nil];
return self;
}
- mouseDragged:(NXEvent *)theEvent
{
NXPoint *location = (NXPoint *) NXZoneMalloc([self zone], sizeof (*location));
NXRect *rect = (NXRect *)NXZoneMalloc ([self zone], sizeof (*rect));
NXRect limits;
/* When the user drags on a FakeUG this method gets called twice
* the first time it's called noMovement = YES, the second time it gets
* set to NO
*/
if (noMovement)
{
/* This code just draws the fake UG in the same place it was before
* the drag
*/
noMovement = NO;
[self lockFocus];
[self eraseSelf];
PSnewinstance();
PSsetinstance(YES);
[self drawSelf:YES];
PSsetinstance(NO);
[self unlockFocus];
}
location->x = theEvent->location.x;
location->y = theEvent->location.y;
[superview convertPoint:location fromView:nil];
[superview getBounds:&limits];
if ((location->x >= limits.origin.x) &&
(location->y >= limits.origin.y) &&
(location->x <= limits.size.width+limits.origin.x) &&
(location->y <= limits.size.height+limits.origin.y))
{
[self convertPoint:location fromView:superview];
location->x = location->x-whereGrabbed.x;
location->y = location->y-whereGrabbed.y;
[superview convertPoint:location fromView:self];
[self moveTo:location->x :location->y];
[self lockFocus];
PSnewinstance();
PSsetinstance(YES);
/* After this line gets done the terd get's left over */
[self drawSelf:YES];
PSsetinstance(NO);
[self unlockFocus];
NXPing();
[window flushWindow];
}
return self;
}
- mouseUp:(NXEvent *)theEvent
{
NXPoint *location = (NXPoint *) NXZoneMalloc ([self zone], sizeof (*location));
NXRect *rect = (NXRect *)NXZoneMalloc ([self zone], sizeof (*rect));
NXRect limits;
if (mouseUpRespond)
{
mouseUpRespond = NO;
if (noMovement)
[superview setSelected:self];
else
{
NXPing();
location->x = theEvent->location.x;
location->y = theEvent->location.y;
[superview convertPoint:location fromView:nil];
[superview getBounds:&limits];
if ((location->x>=limits.origin.x) &&
(location->y>=limits.origin.y) &&
(location->x<=limits.size.width+limits.origin.x) &&
(location->y<=limits.size.height+limits.origin.y))
{
[self convertPoint:location fromView:superview];
location->x = location->x-whereGrabbed.x;
location->y = location->y-whereGrabbed.y;
[superview convertPoint:location fromView:self];
[self moveTo:location->x :location->y];
}
[self lockFocus];
[self drawSelf:NO];
PSnewinstance();
[self unlockFocus];
NXPing();
}
[window removeFromEventMask:NX_LMOUSEDRAGGEDMASK];
[window flushWindow];
[superview display];
}
return self;
}
- getInspectorRect:anInspector
{
if (anInspector)
{
useInspectorRect = YES;
[anInspector getFrame:&inspectorRect];
}
else
{
useInspectorRect = NO;
inspectorRect.origin.x = -1;
inspectorRect.origin.y = -1;
inspectorRect.size.width = -1;
inspectorRect.size.height = -1;
}
return self;
}
- write:(NXTypedStream *) stream
{
char *aName;
int i;
[super write:stream];
NXWriteTypes(stream, "i", &allocOrder);
NXWriteTypes(stream, "@", &theUGDef);
NXWriteArray(stream, "@", MAXCONNECTIONS, &connections);
NXWriteArray(stream, "*", MAXNOTEPARAMETERS, &arg);
NXWriteArray(stream, "c", MAXNOTEPARAMETERS, &argEnabled);
NXWriteTypes(stream, "@", &theImage);
aName = theName;
NXWriteTypes(stream, "*", &aName);
NXWriteTypes(stream, "@", &patchParam);
NXWriteTypes(stream, "@", &clavier);
/* Make sure we have the latest envelope happening */
for (i=0; i<MAXNOTEPARAMETERS; i++)
{
if ([self getArgType:i] == ENV)
{
[self syncEnvelope:i];
argEnvelope[i] = [envDelegate[i] envelope];
}
}
NXWriteArray(stream, "@", MAXNOTEPARAMETERS, &argEnvelope);
NXWriteArray(stream, "@", MAXNOTEPARAMETERS, &slider);
if (argCount > 0)
{
[self getInspectorRect:inspector];
}
else
{
[self getInspectorRect:noArgInspector];
}
NXWriteTypes(stream, "d", &inspectorRect.origin.x);
NXWriteTypes(stream, "d", &inspectorRect.origin.y);
NXWriteTypes(stream, "d", &inspectorRect.size.width);
NXWriteTypes(stream, "d", &inspectorRect.size.height);
NXWriteTypes(stream, "c", &useInspectorRect);
NXWriteTypes(stream, "c", &inspectorDisplayed);
return self;
}
- read:(NXTypedStream *) stream
{
int version, old_ug_type, i, len;
char *old_arg[9], *old_name;
id elementController;
[super read:stream];
isAllocated = NO;
clavier = nil;
midi = nil;
allocOrder = 1;
if (! theSP)
{
theSP = [[Controller theController] theSP];
}
version = NXTypedStreamClassVersion(stream, "FakeUG");
useInspectorRect = NO;
inspectorRectJustLoaded = NO;
switch (version)
{
case(5):
{
NXReadTypes(stream, "i", &allocOrder);
NXReadTypes(stream, "@", &theUGDef);
NXReadArray(stream, "@", MAXCONNECTIONS, &connections);
NXReadArray(stream, "*", MAXNOTEPARAMETERS, &arg);
NXReadArray(stream, "c", MAXNOTEPARAMETERS, &argEnabled);
NXReadTypes(stream, "@", &theImage);
NXReadTypes(stream, "*", &old_name);
NXReadTypes(stream, "@", &patchParam);
NXReadTypes(stream, "@", &clavier);
NXReadArray(stream, "@", MAXNOTEPARAMETERS, &argEnvelope);
NXReadArray(stream, "@", MAXNOTEPARAMETERS, &slider);
NXReadTypes(stream, "d", &inspectorRect.origin.x);
NXReadTypes(stream, "d", &inspectorRect.origin.y);
NXReadTypes(stream, "d", &inspectorRect.size.width);
NXReadTypes(stream, "d", &inspectorRect.size.height);
NXReadTypes(stream, "c", &useInspectorRect);
NXReadTypes(stream, "c", &inspectorDisplayed);
inspectorRectJustLoaded = YES;
if (old_name)
{
strcpy(theName, old_name);
}
else
{
strcpy(theName, "");
}
// [self validate];
break;
}
case(4):
{
NXReadTypes(stream, "i", &allocOrder);
NXReadTypes(stream, "@", &theUGDef);
NXReadArray(stream, "@", MAXCONNECTIONS, &connections);
NXReadArray(stream, "*", MAXNOTEPARAMETERS, &arg);
NXReadArray(stream, "c", MAXNOTEPARAMETERS, &argEnabled);
NXReadTypes(stream, "@", &theImage);
NXReadTypes(stream, "*", &old_name);
NXReadTypes(stream, "@", &patchParam);
NXReadTypes(stream, "@", &clavier);
NXReadArray(stream, "@", MAXNOTEPARAMETERS, &argEnvelope);
NXReadTypes(stream, "d", &inspectorRect.origin.x);
NXReadTypes(stream, "d", &inspectorRect.origin.y);
NXReadTypes(stream, "d", &inspectorRect.size.width);
NXReadTypes(stream, "d", &inspectorRect.size.height);
NXReadTypes(stream, "c", &useInspectorRect);
NXReadTypes(stream, "c", &inspectorDisplayed);
inspectorRectJustLoaded = YES;
if (old_name)
{
strcpy(theName, old_name);
}
else
{
strcpy(theName, "");
}
// [self validate];
break;
}
case(3):
{
NXReadTypes(stream, "i", &allocOrder);
NXReadTypes(stream, "@", &theUGDef);
NXReadArray(stream, "@", MAXCONNECTIONS, &connections);
NXReadArray(stream, "*", MAXNOTEPARAMETERS, &arg);
NXReadArray(stream, "c", MAXNOTEPARAMETERS, &argEnabled);
NXReadTypes(stream, "@", &theImage);
NXReadTypes(stream, "*", &old_name);
NXReadTypes(stream, "@", &patchParam);
NXReadTypes(stream, "@", &clavier);
NXReadArray(stream, "@", MAXNOTEPARAMETERS, &argEnvelope);
if (old_name)
{
strcpy(theName, old_name);
}
else
{
strcpy(theName, "");
}
// [self validate];
break;
}
case(2):
{
NXReadTypes(stream, "i", &allocOrder);
NXReadTypes(stream, "@", &theUGDef);
NXReadArray(stream, "@", MAXCONNECTIONS, &connections);
NXReadArray(stream, "*", MAXNOTEPARAMETERS, &arg);
NXReadTypes(stream, "@", &theImage);
NXReadTypes(stream, "*", &old_name);
NXReadTypes(stream, "@", &patchParam);
NXReadTypes(stream, "@", &clavier);
NXReadArray(stream, "@", MAXNOTEPARAMETERS, &argEnvelope);
if (old_name)
{
strcpy(theName, old_name);
}
else
{
strcpy(theName, "");
}
for (i=0; i<MAXNOTEPARAMETERS; i++)
{
argEnabled[i] = YES;
}
// [self validate];
break;
}
default:
{
/* Old versions didn't have versioning */
NXReadArray(stream, "@", 5, &connections);
for (i=0; i<9; i++)
{
old_arg[i] = NULL;
}
NXReadArray(stream, "*", 9, &old_arg);
NXReadTypes(stream, "@i*ccc",
&theImage, &old_ug_type, &old_name, &noMovement, &erasing,
&mouseUpRespond);
if (old_name)
{
strcpy(theName, old_name);
}
else
{
strcpy(theName, "");
}
/* Convert typeOfFakeUG to a UGDef
* This will set all the default values in theUGDef
*/
elementController = [[theSP theController] elementController];
[self initUGDef: [elementController oldUGTypeToUGDef: old_ug_type]];
[self setDefaultValues];
for (i=0; i<MAXNOTEPARAMETERS; i++)
{
argEnabled[i] = YES;
}
// [self validate];
/* Now set the old argument values into the new arg */
for (i=0; i<9; i++)
{
if (old_arg[i])
{
len = strlen(old_arg[i]);
if (len > 0)
{
len += 10; /* for good measure */
if (arg[i])
{
NXZoneFree([self zone], arg[i]);
}
arg[i] = (char *) NXZoneCalloc([self zone], len, sizeof(char));
strcpy(arg[i], old_arg[i]);
}
else
{ /* Pathological */
len = 2;
if (arg[i])
{
NXZoneFree([self zone], arg[i]);
}
arg[i] = (char *) NXZoneCalloc([self zone], len, sizeof(char));
strcpy(arg[i], "");
}
}
}
}
}
/* Make sure all the envelopes are synced */
for (i=0; i<MAXNOTEPARAMETERS; i++)
{
if (envDelegate[i])
{
[envDelegate[i] free];
envDelegate[i] = nil;
}
[self syncEnvelope:i];
}
return self;
}
- (STR)getArgCast:(int)type;
{
char *cast;
switch (type)
{
case(INT):
{
cast = "(int)";
break;
}
case(DOUBLE):
{
cast = "(double)";
break;
}
case(BOOLEAN):
{
cast = "(BOOL)";
break;
}
default:
{
cast = NULL;
}
}
return(cast);
}
- (STR)getArgTypeStr:(int)type;
{
char *cast;
switch (type)
{
case(INT):
{
cast = "int";
break;
}
case(DOUBLE):
{
cast = "double";
break;
}
case(BOOLEAN):
{
cast = "BOOL";
break;
}
case(ENV):
{
cast = "ENV";
break;
}
case(DSPDATUM):
{
cast = "DSPDATUM";
break;
}
case(PARTIALS):
{
cast = "PARTIALS";
break;
}
default:
{
cast = NULL;
}
}
return(cast);
}
- (int)getUGTarget
{
return [theUGDef getMetaType];
}
- (BOOL)isPatchParameter
{
return [theUGDef isPatchParameter];
}
- (BOOL)isClavier
{
return [theUGDef isClavier];
}
- (BOOL)isMidi
{
return [theUGDef isMidi];
}
- (BOOL)isNoteFilter
{
return [theUGDef isNoteFilter];
}
- thePatch
{
return theSP;
}
- clavier
/* Called by FakeSynthPatch when a clavier icon is clicked on */
{
if ([self isClavier])
{
if (clavier)
{
/* From an archived object */
if (! clavInit)
{
[clavier initConnectionWithPatch:[self thePatch] WithFakeUG: self];
clavInit = YES;
}
}
else
{
/* A new one */
clavier = [[Clavier alloc] init];
[clavier initConnectionWithPatch:[self thePatch] WithFakeUG: self];
[clavier setClavierName:theName];
}
return clavier;
}
else
{
return nil;
}
}
- midi
{
return midi;
}
- noteFilter
{
return noteFilter;
}
- patchParam
{
return patchParam;
}
- (BOOL) isSoundMaker
{
return isSoundMaker;
}
- setInspectorName:(char *) aName
{
int i;
if (argCount > 0)
{
[inspector setTitle: aName];
}
else
{
[noArgInspector setTitle: aName];
}
for (i=0;i<MAXNOTEPARAMETERS;i++)
{
[slider[i] updateInspectorTitle];
}
return self;
}
- switchArg:sender
/* Change the argument being displayed on the inspector */
{
int button;
/* button = -1 for top, 1 for bottom */
button = [[sender selectedCell] tag];
currArg += button;
if (currArg < 0)
{
currArg = argCount - 1;
}
else if (currArg == argCount)
{
currArg = 0;
}
[self displayArg:currArg];
return self;
}
- displayInspector
{
char *nibFile;
if ([self isPatchParameter])
{
[[self patchParam] displayInspector];
}
else if ([self isClavier])
{
[clavier displayInspector];
}
else
{
if (! inspector)
{
nibFile = [theUGDef getNibFile];
if (! nibFile)
{
if (! [self isMidi])
{
NXRunAlertPanel(getAppName(), "No nib file defined for: %s",
NULL, NULL, NULL, [theUGDef getName]);
}
return nil;
}
[NXApp loadNibSection:nibFile owner:self withNames:NO];
[self displayArg:currArg];
[argIndexField setIntValue:argCount];
}
if (argCount > 0)
{
[self updateAllocOrder];
[fakeUGName setStringValue: theName];
[fakeUGType setStringValue:[self getTypeString]];
[argCountField setIntValue:[self getArgCount]];
[argIndexField setIntValue:currArg+1];
[self setInspectorName:theName];
[self bringUpInspector:inspector];
}
else
{
[self updateAllocOrder];
[fakeUGNameNoArg setStringValue: theName];
[fakeUGTypeNoArg setStringValue:[self getTypeString]];
[self setInspectorName:theName];
[self bringUpInspector:noArgInspector];
}
}
inspectorDisplayed = YES;
return self;
}
- displayInspectorIfWasActive
{
if ([self isPatchParameter])
{
[[self patchParam] displayInspectorIfWasActive];
}
else if ([self isClavier])
{
[clavier displayInspectorIfWasActive];
}
else
{
if (inspectorDisplayed)
{
[self displayInspector];
}
}
return self;
}
- inspectorClosed
/* Called by the inspector's delegate */
{
inspectorDisplayed = NO;
return self;
}
- bringUpInspector:anInspector
{
int i;
if (inspectorRectJustLoaded)
{
if (useInspectorRect)
{
[anInspector placeWindowAndDisplay:&inspectorRect];
useInspectorRect = NO;
}
inspectorRectJustLoaded = NO;
for (i=0; i<MAXNOTEPARAMETERS; i++)
{
if (slider[i])
{
[slider [i]
initFromFakeUG: self
ArgNum: i
ArgField: argVal
ArgType: [[theArgs objectAt:i] argType]
];
[slider[i] displayInspector];
}
}
}
/* doHighlight toggle prevents the instance
* from being highlighted twice
*/
doHighlight = NO;
[anInspector makeKeyAndOrderFront:self];
doHighlight = YES;
return self;
}
- takeArgFromInspector:sender
/* This is called when a return is hit in a cell in argVal */
{
[self setArgWithIndex: currArg To: (char *) [sender stringValue]];
if (slider[currArg])
{
[slider[currArg] takeSliderValueFrom:argVal];
}
return self;
}
- inspectArg:sender
{
if ([[theArgs objectAt:currArg] argType] == ENV)
{
[self displayEnvelope:currArg];
[self displayArg:currArg];
}
else
{
if (! slider[currArg])
{
slider[currArg] = [[UGArgSlider alloc] init];
[slider [currArg]
initFromFakeUG: self
ArgNum: currArg
ArgField: argVal
ArgType: [[theArgs objectAt:currArg] argType]
];
}
[slider[currArg] displayInspector];
}
return self;
}
- syncEnvelope:(int) i
{
if ([self getArgType:i] != ENV)
{
return nil;
}
if (! envDelegate[i])
{
envDelegate[i] = [[EnvDelegate alloc] init];
}
[envDelegate[i] setFakeUG:self ArgNum: i];
[envDelegate[i] setPatchParameter:nil];
if (! argEnvelope[i] && arg[i])
{
/* The argument was set but the Envelope object was
* never initialized
*/
argEnvelope[i] = [envDelegate[i] textToEnvelope:arg[i]];
}
return self;
}
- createDefaultEnvelope:(int) i
{
static double x[3];
static double y[3];
static double s[3];
int pointCount = 3;
int stickPoint = 1;
double orSamplingPeriod = 1.0;
double orDefaultSmoothing = 1.0;
Envelope *anEnv;
/* Create the default Envelope */
x[0] = 0; y[0] = 0;
x[1] = .5; y[1] = 1.0;
x[2] = 1; y[2] = 0;
s[0] = 1.0; s[1] = 1.0; s[2] = 1.0;
anEnv = [[Envelope alloc] init];
[anEnv setPointCount: pointCount
xArray: x
orSamplingPeriod: orSamplingPeriod
yArray: y
smoothingArray: s
orDefaultSmoothing: orDefaultSmoothing];
[anEnv setStickPoint:stickPoint];
argEnvelope[i] = anEnv;
return self;
}
- displayEnvelope:(int) i
{
id envController;
char *ptr;
int val;
[self syncEnvelope:i];
if (argEnvelope[i])
{
envController = [envDelegate[i] envController];
[envController setNewEnvelope:argEnvelope[i]];
[envController reScaleLimits:self];
[envController makeGraphType:1];
[envController reScaleLimits:self];
}
else
{
val = NXRunAlertPanel(getAppName(),
"No envelope defined. Create default envelope?",
"YES", /* default */
"NO", /* alt */
"Cancel"); /* other */
switch (val)
{
case(NX_ALERTDEFAULT):
{
[self createDefaultEnvelope:i];
envController = [envDelegate[i] envController];
[envController setNewEnvelope:argEnvelope[i]];
[envController reScaleLimits:self];
[envController makeGraphType:1];
[envController reScaleLimits:self];
break;
}
case(NX_ALERTALTERNATE):
{
break;
}
default:
{
return self;
}
}
}
sprintf(ErrorMsg, "%s %s", theName, [self getArgName:i]);
[envDelegate[i] displayWindow:ErrorMsg];
if (arg[i])
{
NXZoneFree([self zone], arg[i]);
arg[i] = NULL;
}
if (argEnvelope[i])
{
ptr = [[theSP utilities] envelopeToText:argEnvelope[i]];
if (ptr)
{
arg[i] = (char *) NXZoneCalloc ([self zone], 1+strlen(ptr), sizeof(char));
strcpy(arg[i], ptr);
}
}
[self displayArg:i];
return self;
}
- inspector
{
return inspector;
}
- setArg: (int) argnum To:(char *) value
/* This gets called when the inspector field is touched
* directly
*/
{
currArg = argnum;
[self setArgWithIndex: currArg To:value];
/* Update the inspector */
[self displayArg:argnum];
return self;
}
- setArgWithIndex:(int) argnum To:(char*) value
{
#ifdef DEBUG_PARAM
DEBUG_PRINT("FakeUG:setArgWithIndex:%d To:%s\n", argnum, value);
#endif DEBUG_PARAM
if (! value)
{
if (arg[argnum])
{
NXZoneFree([self zone], arg[argnum]);
}
arg[argnum] = NULL;
}
else
{
const char *temp = value;
if (arg[argnum])
{
NXZoneFree([self zone], arg[argnum]);
}
arg[argnum] = (char *) NXZoneCalloc ([self zone], 1+strlen(temp), sizeof(char));
strcpy(arg[argnum], temp);
}
[self syncEnvelope:argnum];
#ifdef DEBUG_PARAM
DEBUG_PRINT("setArgWithIndex:To: Sending %s to arg %d and updating inspector\n",
arg[argnum], argnum);
#endif DEBUG_PARAM
[self sendArg:argnum];
return self;
}
- setArg:(int)i WithEnvelope:anEnv
{
char *ptr;
if ([self getArgType:i] == ENV)
{
argEnvelope[i] = anEnv;
}
if (arg[i])
{
NXZoneFree([self zone], arg[i]);
arg[i] = NULL;
}
ptr = [[theSP utilities] envelopeToText:argEnvelope[i]];
if (ptr)
{
arg[i] = (char *) NXZoneCalloc ([self zone], 1+strlen(ptr), sizeof(char));
strcpy(arg[i], ptr);
}
[self displayArg:i];
[self sendArg:i];
return self;
}
- sendArg:(int) num
{
if (isSoundMaker)
{
if (argEnabled[num])
{
[theSP setUGParameterFromFakeUG:self argNum:num];
}
else
{
if ([self getArgType:num] == ENV)
{
/* Dis-associate the current envelope from the asymp */
if (ug)
{
[ug abortEnvelope];
}
}
}
}
return self;
}
- (STR)getArg:(int)i
{
return arg[i];
}
- getArgEnvelope:(int)i
{
id envCopy;
if ([self getArgType:i] == ENV)
{
/* Return a copy of the latest envelope */
if (argEnvelope[i])
{
envCopy = [argEnvelope[i] copy];
}
else
{
envCopy = nil;
}
return envCopy;
}
return nil;
}
- clearArgEnvelope:(int)i
{
argEnvelope[i] = nil;
if (arg[i])
{
NXZoneFree([self zone], arg[i]);
arg[i] = NULL;
}
[self displayArg:i];
return self;
}
- willAddEnvelope:(int)i
{
if ( !([self getArgType:i] == ENV))
{
return self;
}
if (ug)
{
[ug abortEnvelope];
[theSP enableNoteOff:NO];
}
return self;
}
- willRemoveEnvelope:(int)i
{
if ( !([self getArgType:i] == ENV))
{
return self;
}
if (ug)
{
[ug abortEnvelope];
[theSP enableNoteOff:NO];
}
return self;
}
- (int) methodCount
{
return methodCount;
}
- (int) getArgCount
{
return argCount;
}
- (char *)getMethod:(int)i
{
return [[theMethods objectAt:i] getName];
}
- (char *)getArgName:(int)i
{
return [[theArgs objectAt:i] getName];
}
- (BOOL) isMethodAnOutput:(int)i
{
return [[theMethods objectAt:i] isOutput];
}
- printSelf
{
int i;
int connectionCount = 0;
for (i=0; i<MAXCONNECTIONS; i++)
{
if (connections[i]!=nil)
{
connectionCount++;
}
}
printf("+++++++++++++++++++++++++++++++++++++++++++++\n\n");
printf("- (FakeUG %s) connections: %d\n", [self getName], connectionCount);
for (i=0; i<methodCount; i++)
{
printf("method %d: %s\n", i, [self getMethod:i]);
}
for (i=0; i<argCount; i++)
{
printf("arg %d %s: %s\n", i, [self getArgName:i], arg[i]);
}
for (i=0; i<connectionCount; i++)
{
[connections[i] printSelf];
}
return self;
}
- displayIfDoubleClick
{
if ([self isPatchParameter])
{
[[self patchParam] displayIfDoubleClick];
}
else if ([self isClavier])
{
[[self clavier] displayIfDoubleClick];
}
else
{
clickCount++;
if (clickCount >= 2)
{
clickCount = 0;
[self displayInspector];
}
}
return self;
}
- highlightSelf
{
if ( (![theSP windowMiniaturized]) && doHighlight)
{
[theSP setSelected:self];
[window removeFromEventMask:NX_LMOUSEDRAGGEDMASK];
[window flushWindow];
[theSP display];
}
return self;
}
- setDoHighlight:(BOOL) flag
{
doHighlight = flag;
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.