This is Controller.m in view mode; [Download] [Up]
/************************************************** * SynthBuilder * Copyright 1993 Nick Porcaro All Rights Reserved **************************************************/ /* * Controller.m * Eric Jordan, independent work, Spring, 1992 * Re-written by Nick Porcaro Summer 1993 */ #import <stdlib.h> #import <strings.h> #import <appkit/Matrix.h> #import <appkit/View.h> #import <appkit/Application.h> #import <appkit/Panel.h> #import <appkit/Button.h> #import <appkit/OpenPanel.h> #import <appkit/SavePanel.h> #import <musickit/Midi.h> #import "Controller.h" #import "FakeSynthPatch.h" #import "DragView.h" #import "FakePatchPoint.h" #import "MKCodeGen.h" #import "ClmCodeGen.h" #import "ElementController.h" #import "Utilities.h" #import "MainWindowDelegate.h" extern char *getAppName(); static id openPanel = nil; static char TempString[1024]; char *getOpenPath(char *banner) { static const char dir[1024]; if (!openPanel) { openPanel = [OpenPanel new]; } [openPanel setTitle:banner]; [openPanel allowMultipleFiles:NO]; if ([openPanel runModalForDirectory:dir file:NULL types:NULL]) { return ((char *) [openPanel filename]); } else { return NULL; } } static id savePanel = nil; char *getSavePath(char *banner) /* Set up and run the Save panel for the given type. */ { static const char dir[1024]; static const char file[1024]; if (!savePanel) { savePanel = [SavePanel new]; } [savePanel setTitle:banner]; if ([savePanel runModalForDirectory:dir file:file]) { return ((char *) [savePanel filename]); } else { return NULL; } } @implementation Controller static id theController = nil; + theController { return theController; } - awakeFromNib { // malloc_debug(0xFFFF); [dragView setPatch:theSP]; return self; } - init { theController = self; return self; } - displayMainWindow /* Called after the ViewController gets its act together */ { [theWindow makeKeyAndOrderFront:self]; return self; } - setHidingScene:sender { if ([sender intValue]) stopSoundOnHide = YES; else stopSoundOnHide = NO; return self; } - newSP:sender /* This just erases what we already have. The user * is asked to save the current SP */ { int val; val = NXRunAlertPanel(getAppName(), "Do you want to save the current patch first?", "YES", /* default */ "NO", /* alt */ "Cancel"); /* other */ switch (val) { case(NX_ALERTDEFAULT): { [self save:self]; break; } case(NX_ALERTALTERNATE): { break; } default: { return self; } } [theSP removeSelf]; [theSP display]; [dragView setPatch:theSP]; [self setFileName:""]; [[theSP window] makeKeyAndOrderFront:self]; return self; } static BOOL didFirstOpen = NO; - open:sender { char *file_name; int val; if (didFirstOpen) { val = NXRunAlertPanel(getAppName(), "Do you want to save the current patch first?", "YES", /* default */ "NO", /* alt */ "Cancel"); /* other */ switch (val) { case(NX_ALERTDEFAULT): { [self save:self]; break; } case(NX_ALERTALTERNATE): { break; } default: { return self; } } } else { didFirstOpen = YES; } sprintf(TempString, "%s Open Patch", getAppName()); file_name = getOpenPath(TempString); if (! file_name) { return nil; } [self openFile:file_name]; return self; } - openFile:(char *) fileName { NXTypedStream *ts; id theSuperview = [theSP superview]; id theOldSP = theSP; id aSP; ts = NXOpenTypedStreamForFile(fileName, NX_READONLY); if (ts) { [theWindow setTitle: "Loading ..."]; aSP = NXReadObject(ts); NXCloseTypedStream(ts); } else { NXRunAlertPanel("Open", "Cannot open file: %s", NULL, NULL, NULL, fileName); return nil; } /* Make sure all the interface controls that * theSP are responsible for are wired up properly */ [mainWindowDelegate setOwner:aSP]; [theSP deallocatePatch:self]; [aSP setController: self]; [aSP setWindowDelegate: [theSP windowDelegate]]; [aSP setMemory: [theSP memory]]; [aSP setUtilities: [theSP utilities]]; [aSP setMidiPortSwitch: [theSP midiPortSwitch]]; [aSP setSoundOutDeviceSwitch: [theSP soundOutDeviceSwitch]]; [aSP setSamplingRateSwitch: [theSP samplingRateSwitch]]; [aSP setDefaultArgValSwitch: [theSP defaultArgValSwitch]]; [aSP setAllocOnOpenSwitch: [theSP allocOnOpenSwitch]]; [aSP setAlwaysUpdateSwitch: [theSP alwaysUpdateSwitch]]; [aSP setNoteOnButton: [theSP noteOnButton]]; [aSP setNoteOffButton: [theSP noteOffButton]]; [aSP setStopButton: [theSP stopButton]]; [aSP setResetControl: [theSP resetControl]]; [aSP setCloseAllControl: [theSP closeAllControl]]; [aSP setDisplayAllControl: [theSP displayAllControl]]; [aSP setPrintSelfControl: [theSP printSelfControl]]; [aSP setOrch: [theSP getOrch]]; [theOldSP removeSelf]; theSP = aSP; [theSuperview addSubview:theSP]; [dragView setPatch:theSP]; [theSP updateElements]; if ([theSP allocOnOpen]) { [theSP allocatePatch]; } [theSP display]; [theSP makeSelected:nil]; if ([renamePPSwitch intValue]) { [self fixPatchPointNames]; } [theSP sortFakePatchPointsByAllocOrder]; [theSP sortFakeUGsByAllocOrder]; [[theSP window] orderFront:self]; [self setFileName:fileName]; [theOldSP free]; return self; } - fixPatchPointNames { int i, len; id fakePatchPoints, thePatchPoint; char pp_name[256], *format_str; static char patch_name[256]; /* Make sure all the patch points have the * correct (based on feeder pin) name * * Here's the sense to this naming: * * In the feedback example, constantpp should be a patchpoint, not a synthData. * That is, you should say: * constantpp13Out = [template addPatchpoint:MK_xPatch]; * rather than: * constantpp13Out = [template addSynthData:MK_xData length:16]; * * What you did is ok, but not as clear. * * Also, I wouldn't use the name "Out" when something is a constantpp. * Instead just use the name, i.e. "constantpp13". * I also wouldn't use the name "Out" when something is a synthdata. * The only time you should use that is when you have * something that's an "implicit" patchpoint, i.e. something that was * created by this program, not the user, in order to connect two unit generators. */ fakePatchPoints = [theSP getFakePatchPoints]; for (i=0; i<[fakePatchPoints count]; i++) { thePatchPoint = [[[fakePatchPoints objectAt:i] getFromNode] superview]; if (([thePatchPoint hasConstant]) || ([thePatchPoint isData])) { format_str = "%s"; } else { format_str = "%sOut"; } sprintf(pp_name, format_str, [[[[fakePatchPoints objectAt:i] getFromNode] superview] getName]); len = strlen(pp_name); strcpy(patch_name, pp_name); [ (FakePatchPoint *) [fakePatchPoints objectAt:i] setName:patch_name]; } return self; } - save:sender { if (currentFileName) { [self doSave:currentFileName]; } else { [self saveAs:self]; } return self; } - saveAs:sender { char *fileName; sprintf(TempString, "%s Save Patch", getAppName()); if (! (fileName = getSavePath(TempString))) { return self; } [self doSave:fileName]; /* fileName should have the full path */ return self; } - doSave:(char *)fileName { char *str; int len; NXTypedStream *ts; ts = NXOpenTypedStreamForFile(fileName, NX_WRITEONLY); if (ts) { [theWindow setTitle: "Saving ..."]; NXWriteRootObject(ts, theSP); NXCloseTypedStream(ts); /* Sorry this is needed because setFileName * and the caller of this function can * interfere with each other */ len = strlen(fileName) + 1; str = (char *) NXZoneCalloc([self zone], len, sizeof(char)); strcpy(str, fileName); [self setFileName:str]; NXZoneFree([self zone], str); } else { NXRunAlertPanel(getAppName(), "Can't create file: %s", NULL, NULL, NULL, fileName); } return self; } - setFileName:(char *) file { int len; if (currentFileName) { NXZoneFree([self zone], currentFileName); } currentFileName = NULL; len = strlen(file); if ( (! file) || (len <= 0) || (strcmp(file, "") == 0) ) { [theWindow setTitle: "Untitled"]; return self; } len++; currentFileName = (char *) NXZoneCalloc([self zone], len, sizeof(char)); if (! currentFileName) { NXRunAlertPanel(getAppName(), "Out of Memory", NULL, NULL, NULL); return self; } strcpy(currentFileName, file); [theWindow setTitle: [utilities getPathLeaf:currentFileName]]; return self; } - removeSelected:sender { [theSP removeSelected:sender]; return self; } - setNameOfSelectedObject:sender { [theSP setNameOfSelectedObject:sender]; return self; } - getHelp:sender { [NXApp showHelpPanel:self]; /************* if (!helpWindow) { [NXApp loadNibSection:"Help.nib" owner:self]; } [helpWindow makeKeyAndOrderFront:self]; ****************/ return self; } - getInfo:sender { if (!infoPanel) { [NXApp loadNibSection:"Info.nib" owner:self]; } [infoPanel makeKeyAndOrderFront:self]; return self; } - theSP { return theSP; } - elementController { return theElementController; } - displayAdminPanel:sender { int val; val = NXRunAlertPanel(getAppName(), "DANGER: Only for administrators. Are you sure?", "NO", /* default */ "YES", /* alt */ "Cancel"); /* other */ switch (val) { case(NX_ALERTDEFAULT): { break; } case(NX_ALERTALTERNATE): { [adminPanel makeKeyAndOrderFront:self]; break; } default: { break; } } return self; } - changeMidiPort:sender /* this is a temporary hack to get around a problem where * when you load a file with a midi object, SynthBuilder will * crash when you attempt to change the midi port. */ { [theSP restartMidi:sender]; return self; } - showLegal:sender { if (!legalPanel) { [NXApp loadNibSection:"Legal.nib" owner:self]; } [legalPanel makeKeyAndOrderFront:self]; return self; } @end @implementation Controller(ApplicationDelegate) /* * We have set up the Controller to be * the delegate of the Application object * This is done in the Interface Builder * by connnecting the File's Owner delegate * outlet to the ControllerInstance. * Since Controller is a delegate of Application, * forwards the appDid* and appWill* methods * to Controller. This is a good thing to do, as * opposed to making a subclass of Application * and overriding it's appDid* appWill methods */ /* * Set some defaults when the app starts */ - appDidInit:sender { if ([soundHidingPref intValue]) stopSoundOnHide = YES; else stopSoundOnHide = NO; return self; } /* If hidden, kill the orchestra if the user * has set this as a preference */ - appDidResignActive:sender { if (stopSoundOnHide) { [theSP releaseDSP:self]; } return self; } - appWillTerminate:sender /* This is what gets called when the terminate message * is sent to the app. We can clean up the midi mess here * If this method were to return nil, the app would not terminate. * For example you could add code in here to check for unsaved documents */ { int val; val = NXRunAlertPanel(getAppName(), "Do you want to save the current patch first?", "YES", /* default */ "NO", /* alt */ NULL); /* other */ switch (val) { case(NX_ALERTDEFAULT): { [self save:self]; break; } } return self; } #ifdef HELP_PANEL_TRICK > - app:sender willShowHelpPanel:panel > /* This method does nothing non-standard. > * I was trying to figure out how to > * get the help panel to resize. I ran out of time. (Nick) > */ > { > char path[MAXPATHLEN + 1]; > > sprintf (path, "%s/%s", [panel helpDirectory], > "TableOfContents.rtf"); > > [panel showFile:path atMarker:NULL]; > return self; > } > #endif HELP_PANEL_TRICK @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.