This is Controller.m in view mode; [Download] [Up]
/* ** Copyright (C) 1992 Ronin Consulting, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; version 1. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #import <stdio.h> #import "Controller.h" #import "Defaults.h" #import "StringStorage.h" #import "TokenString.h" #import "EnhancedText.h" #import "EnhancedMatrix.h" #import "Subprocess.h" #import <appkit/appkit.h> #import <libc.h> #import <objc/NXStringTable.h> #import <soundkit/soundkit.h> #import "EnhancedApp.h" #import "FileName.h" @implementation Controller - init { [super init]; [NXApp appDirectory]; openPanel = [OpenPanel new]; [openPanel allowMultipleFiles: NO]; inFile = [[StringStorage alloc] init]; savePanel = [SavePanel new]; outFile = [[StringStorage alloc] init]; strings = [[NXStringTable alloc] init]; dataFormSwitches = [[NXStringTable alloc] init]; dataSizeSwitches = [[NXStringTable alloc] init]; inHotListStr = [[NXStringTable alloc] init]; inHotListConfig = [[NXStringTable alloc] init]; outHotListStr = [[NXStringTable alloc] init]; outHotListConfig = [[NXStringTable alloc] init]; defaults = [Defaults new]; /* get access to applications defaults */ theSound = [[Sound alloc] init]; [theSound setDelegate: self]; _waiting = NO; return self; } - appDidInit: sender { id buffer = [[StringStorage alloc] init]; id dir = [[StringStorage alloc] init]; /* load the effects popup */ if(![strings readFromFile: "English.lproj/effects.strings"]) NXLogError("File effects is missiong from .app"); [self loadPopUpList: effect with: strings from: 1]; [strings empty]; /* load the filetype popups */ if(![strings readFromFile: "English.lproj/filetype.strings"]) NXLogError("File filetype is missiong from .app"); else { /* get a list of file types */ int count = 0; const void *key, *value; char *aType; NXHashState state = [strings initState]; NX_MALLOC(fileTypes, char *, [strings count] + 1); while ([strings nextState: &state key: &key value: &value]) { NX_MALLOC(aType,char,strlen((char *)value) + 1); strcpy(aType, (char *)value); fileTypes[count] = aType; count++; } fileTypes[count] = (char *)0; } [self loadPopUpList: inType with: strings from: 1]; [self loadPopUpList: outType with: strings from: 3]; [strings empty]; /* load the rates popups */ if(![strings readFromFile: "English.lproj/rate.strings"]) NXLogError("File rate missing\n"); [self loadPopUpList: inRate with: strings from: 1]; [[inRate target] setTarget: self]; [[inRate target] setAction: @selector(copyValue:)]; [self loadPopUpList: outRate with: strings from: 1]; [[outRate target] setTarget: self]; [[outRate target] setAction: @selector(copyValue:)]; [outRateText setDoubleValue: atof([outRate title])]; [strings empty]; /* load the format popups */ if(![strings readFromFile: "English.lproj/dataFormat.strings"]) NXLogError("File dataFormat missing\n"); [self loadPopUpList: inDataForm with: strings from: 1]; [self loadPopUpList: outDataForm with: strings from: 1]; [strings empty]; /* laod the format swithes */ if(![dataFormSwitches readFromFile: "English.lproj/dataFormatSwitches.strings"]) NXLogError("File dataFormatSwitches missing\n"); /* load data size popups */ if(![strings readFromFile: "English.lproj/dataSize.strings"]) NXLogError("File dataSize missing\n"); [self loadPopUpList: inDataSize with: strings from: 1]; [self loadPopUpList: outDataSize with: strings from: 1]; [strings empty]; /* laod the size swithes */ if(![dataSizeSwitches readFromFile: "English.lproj/dataSizeSwitches.strings"]) NXLogError("File dataSizeSwitches missing\n"); /* load data size popups */ if(![strings readFromFile: "English.lproj/channel.strings"]) NXLogError("File channel missing\n"); [self loadPopUpList: inChannels with: strings from: 1]; [self loadPopUpList: outChannels with: strings from: 1]; [strings empty]; [dir setStringValue: [defaults get: "StoreDirectory"]]; if(!*[dir stringValue]) [dir setStringValue: "English.lproj/"]; else [dir appendStringValue: "/"]; [buffer setStringValue: [dir stringValue]]; [buffer appendStringValue: "inHotList.strings"]; /* load in hot list */ if(![inHotListStr readFromFile: [buffer stringValue]]) NXLogError("File inHotList missing.\n"); [self loadPopUpList: inHotList with: inHotListStr from: 1]; [[inHotList target] setTarget: self]; [[inHotList target] setAction: @selector(loadFromHotList:)]; [buffer setStringValue: [dir stringValue]]; [buffer appendStringValue: "inHotListConfig.strings"]; /* load in hot list configs */ if(![inHotListConfig readFromFile: [buffer stringValue]]) NXLogError("File inHotListConfig missing.\n"); [buffer setStringValue: [dir stringValue]]; [buffer appendStringValue: "outHotList.strings"]; /* load out hot list */ if(![outHotListStr readFromFile: [buffer stringValue]]) NXLogError("File outHotList missing.\n"); [self loadPopUpList: outHotList with: outHotListStr from: 1]; [[outHotList target] setTarget: self]; [[outHotList target] setAction: @selector(loadFromHotList:)]; [buffer setStringValue: [dir stringValue]]; [buffer appendStringValue: "outHotListConfig.strings"]; /* load out hot list configs */ if(![outHotListConfig readFromFile: [buffer stringValue]]) NXLogError("File outHotListConfig missing.\n"); [self loadFromHotList: [[inHotList target] itemList]]; [self loadFromHotList: [[outHotList target] itemList]]; [panel makeKeyAndOrderFront: self]; [dialog appendString: "Ready...\n"]; [[NXApp appListener] setServicesDelegate: self]; return self; } - convert:sender { char cmd[1024]; [convert setTitle: "STOP"]; NXPing(); if(![convert state]) /* already doing a conversion - stop it */ { [dialog appendString: "Stopping conversion\n"]; [subprocess terminate: self]; [convert setTitle: "CONVERT"]; _waiting = NO; return nil; } if (![panel makeFirstResponder: panel]) { [dialog appendString: "Invalid entry.\n"]; [convert setState: 0]; [convert setTitle: "CONVERT"]; _waiting = NO; return nil; } [panel endEditingFor:nil]; if(!*[inFile stringValue]) { [dialog appendString: "No input File is set.\n"]; [convert setState: 0]; [convert setTitle: "CONVERT"]; _waiting = NO; return nil; } if(!*[outFile stringValue]) { [outFile setStringValue: [defaults get: "TmpDirectory"]]; [outFile appendStringValue: "/GISO"]; [outFile mktemp]; [outFile appendStringValue: ".snd"]; } /* * Build up the command line. */ strcpy(cmd, "sox -V "); if([volume doubleValue] != 1.0) sprintf(cmd + strlen(cmd), "-v %6.2f ", [volume doubleValue]); if([[inType target] indexOfItem: [inType title]]) sprintf(cmd + strlen(cmd), "-t %s ", [inType title]); if([inRateText doubleValue]) sprintf(cmd + strlen(cmd), "-r %10.3f ", [inRateText doubleValue]); if([[inDataForm target] indexOfItem: [inDataForm title]]) sprintf(cmd + strlen(cmd), "%s ", [dataFormSwitches valueForStringKey: [inDataForm title]]); if([[inDataSize target] indexOfItem: [inDataSize title]]) sprintf(cmd + strlen(cmd), "%s ", [dataSizeSwitches valueForStringKey: [inDataSize title]]); if([[inChannels target] indexOfItem: [inChannels title]]) sprintf(cmd + strlen(cmd), "-c %s ", [inChannels title]); if([swapBytes state]) strcat(cmd, "-x "); sprintf(cmd + strlen(cmd), "%s -t %s ", [inFile stringValue], [outType title]); /* -r %10.3f %s %s -c %s %s " */ if([outRateText doubleValue]) sprintf(cmd + strlen(cmd),"-r %10.3f ", [outRateText doubleValue]); if([[outDataForm target] indexOfItem: [outDataForm title]]) sprintf(cmd + strlen(cmd), "%s ", [dataFormSwitches valueForStringKey: [outDataForm title]]); if([[outDataSize target] indexOfItem: [outDataSize title]]) sprintf(cmd + strlen(cmd), "%s ", [dataSizeSwitches valueForStringKey: [outDataSize title]]); if([[outChannels target] indexOfItem: [outChannels title]]) sprintf(cmd + strlen(cmd), "-c %s ", [outChannels title]); sprintf(cmd + strlen(cmd), "%s ", [outFile stringValue]); if([[effect target] indexOfItem: [effect title]]) sprintf(cmd + strlen(cmd), "%s %s ", [effect title], [effectArgText stringValue]); [dialog appendString: cmd]; [dialog appendString: "\n"]; subprocess = [[Subprocess alloc] init: cmd withDelegate: self]; if(*[defaults get: "AutoPlay"] == 'Y') _waiting = YES; return self; } - openFile:sender { static int first = 1; if (first) { [openPanel runModalForDirectory: [defaults get: "OpenDir"] file: "" types: fileTypes]; first = 0; } else { [openPanel runModalForDirectory: "" file: "" types: fileTypes]; [defaults writeDB: "OpenDir" as: [openPanel directory]]; } [inFile setStringValue: [openPanel filename]]; if(*[inFile stringValue]) { [dialog appendString: [inFile stringValue]]; [dialog appendString: " used as input\n"]; if(*[defaults get: "AutoConvert"] == 'Y') { [convert setState: 1]; [self perform: @selector(convert:) with: self afterDelay: 1 cancelPrevious: YES]; } [outFile setStringValue: ""]; } return self; } - saveFile:sender { static int first = 1; id tempFile = [[StringStorage alloc] init]; if(!*[outFile stringValue]) { [dialog appendString: "No sound created.\n"]; [tempFile free]; return self; } [savePanel setRequiredFileType: [outType title]]; if(first) { [savePanel runModalForDirectory: [defaults get:"SaveDir"] file: ""]; first = 0; } else { [savePanel runModalForDirectory: "" file: ""]; [defaults writeDB: "SaveDir" as: [savePanel directory]]; } [tempFile setStringValue: [savePanel filename]]; if(*[tempFile stringValue]) { char cmd[128]; [dialog appendString: [savePanel filename]]; [dialog appendString: " used as output\n"]; sprintf(cmd, "cp \"%s\" \"%s\" ", [outFile stringValue], [tempFile stringValue]); system(cmd); [outFile setStringValue: [tempFile stringValue]]; } [tempFile free]; return self; } - saveToHotList: sender { id buffer = [[StringStorage alloc] init]; id file = [[StringStorage alloc] init]; id dir = [[StringStorage alloc] init]; char num[10], *name; BOOL inHot; name = (char *)[entryName stringValue]; if(!name || !*name) { NXRunAlertPanel([NXApp appName], "Entry must have a name.", NULL, NULL, NULL); [dir free]; [buffer free]; [file free]; return self; } [dir setStringValue: [defaults get: "StoreDirectory"]]; if(!*[dir stringValue]) NXRunAlertPanel([NXApp appName], "No directory to store the hot lists - see preferences.", NULL, NULL, NULL); else { inHot = [whichRadio state]; [buffer setStringValue: [(inHot?inType:outType) title]]; [buffer appendStringValue: "|"]; [buffer appendStringValue: [(inHot?inRateText:outRateText) stringValue]]; [buffer appendStringValue: "|"]; [buffer appendStringValue: [(inHot?inDataForm:outDataForm) title]]; [buffer appendStringValue: "|"]; [buffer appendStringValue: [(inHot?inDataSize:outDataSize) title]]; [buffer appendStringValue: "|"]; [buffer appendStringValue: [(inHot?inChannels:outChannels) title]]; sprintf(num,"%d", [(inHot?inHotListStr: outHotListStr) count] + 1); [(inHot?inHotListStr:outHotListStr) insertKey: num value: name]; [(inHot?inHotListConfig:outHotListConfig) insertKey: name value: (char *)[buffer stringValue]]; if(inHot) { [file setStringValue: [dir stringValue]]; [file appendStringValue: "/inHotList.strings"]; [inHotListStr writeToFile: [file stringValue]]; [file setStringValue: [dir stringValue]]; [file appendStringValue: "/inHotListConfig.strings"]; [inHotListConfig writeToFile: [file stringValue]]; [[inHotList target] addItem: [entryName stringValue]]; } else { [file setStringValue: [dir stringValue]]; [file appendStringValue: "/outHotList.strings"]; [outHotListStr writeToFile: [file stringValue]]; [file setStringValue: [dir stringValue]]; [file appendStringValue: "/outHotListConfig.strings"]; [outHotListConfig writeToFile: [file stringValue]]; [[outHotList target] addItem: [entryName stringValue]]; } } [dir free]; [buffer free]; [file free]; [[sender window] performClose: self]; return self; } - stopPlay: sender { [theSound stop]; return self; } - playIt: sender { BOOL error = NO; if(!*[outFile stringValue]) { [dialog appendString: "No sound has been created.\n"]; error = YES; } else if([theSound readSoundfile: (char *)[outFile stringValue]]) { [dialog appendString: "Could not load resultant sound.\n"]; error = YES; } else if(![theSound isPlayable]) { [dialog appendString: "Sound isn't playable.\n"]; error = YES; } else [theSound play: sender]; if(error) { NXBeep(); [playButton setState: 0]; } return self; } - copyValue: sender { if(sender == [[inRate target] itemList]) [inRateText setDoubleValue: atof([[sender selectedCell] title])]; else [outRateText setDoubleValue: atof([[sender selectedCell] title])]; return self; } - willPlay: sender { [soundMeter run: self]; return self; } - didPlay: sender { [playButton setState: 0]; [soundMeter stop: self]; return self; } - hadError: sender { [dialog appendString: "Error playing sound...\n"]; [playButton setState: 0]; return self; } - setDialog: anObject { dialog = [anObject docView]; return self; } - setSoundMeter: anObject { soundMeter = anObject; [soundMeter setSound: theSound]; return self; } - loadFromHotList: sender { BOOL inHot; inHot = ((sender == [[inHotList target] itemList])? YES : NO); return [self loadType: inHot fromString: [(inHot?inHotListConfig:outHotListConfig) valueForStringKey: [[sender selectedCell] title]]]; } - loadType: (BOOL) input fromString: (const char *)str { id tokens = [[TokenString alloc] init: str]; const char *title; [tokens setSeparator: '|']; if(!(title = [tokens popStringValue])) { [dialog appendString: "Malformed hot list entry\n"]; return self; } [(input?inType:outType) setTitle: title]; if(!(title = [tokens popStringValue])) { [dialog appendString: "Malformed hot list entry\n"]; return self; } [(input?inRateText:outRateText) setStringValue: title]; if(!(title = [tokens popStringValue])) { [dialog appendString: "Malformed hot list entry\n"]; return self; } [(input?inDataForm:outDataForm) setTitle: title]; if(!(title = [tokens popStringValue])) { [dialog appendString: "Malformed hot list entry\n"]; return self; } [(input?inDataSize:outDataSize) setTitle: title]; if(!(title = [tokens popStringValue])) { [dialog appendString: "Malformed hot list entry\n"]; return self; } [(input?inChannels:outChannels) setTitle: title]; [tokens free]; return self; } - (int) loadPopUpList: button with: stringTable from: (int) x { char key[15]; const char *value; id list = [button target]; /* get the popUpList */ while(1) { sprintf(key, "%d", x++); value = [stringTable valueForStringKey: key]; if(!value) break; [list addItem: value]; } [list removeItem: [button title]]; /* clear out the .nibs item */ [button setTitle: [[[list itemList] cellAt: 0:0] title]]; [[list itemList] selectCellAt: 0 : 0]; return --x; } - cleanKill: sender /* clean temporary files before we go */ { char cmd[strlen([defaults get: "TmpDirectory"]) + 50]; NXLogError("Cleaning tmp.."); sprintf(cmd, "rm -f %s/GISO*.snd", [defaults get: "TmpDirectory"]); NXLogError(cmd); system(cmd); return [NXApp terminate: self]; } - (BOOL)appAcceptsAnotherFile:sender { return YES; } - (int)app:sender openFile:(const char *)filename type:(const char *)aType { [inFile setStringValue: filename]; if(*[inFile stringValue]) { [dialog appendString: [inFile stringValue]]; [dialog appendString: " used as input\n"]; [outFile setStringValue: ""]; if(*[defaults get: "AutoConvert"] == 'Y') { [convert setState: 1]; [self perform: @selector(convert:) with: self afterDelay: 1 cancelPrevious: YES]; } return YES; } return NO; } #ifdef FOOBAR - playAsSound: (id)pasteboard userData:(const char *)userData error:(char **)msg { char *filenames; const char *tok, *ftype; id tokens, filename; int length,x; BOOL known; [pasteboard types]; /* pretend to check the pasteboard types */ /* read the ASCII data from the pasteboard */ if ([pasteboard readType:NXFilenamePboardType data:&filenames length:&length]) { NXLogError("play %s",filenames); tokens = [[TokenString alloc] init: filenames]; filename = [[StringStorage alloc] init]; while(tok = [tokens popStringValue]) { [filename setStringValue: tok]; ftype = [filename fileType]; for(x = 0, known = NO; fileTypes[x] && !known; x++) if(!strcmp(ftype, fileTypes[x])) known = YES; if(known) { [self loadType: YES fromString: "Use Filename|0|Use Header|Use Header|Use Header"]; [self loadType: NO fromString: "snd|0|Use Header|Use Header|Use Header"]; [self app: self openFile: [filename stringValue] type: ""]; if(*[defaults get: "AutoConvert"] != 'Y') { [convert setState: 1]; [self convert: self]; } _waiting = YES; } else (*msg) = "Unknown sound file extension."; } [tokens free]; [filename free]; } return self; } #endif - convertSound: (id)pasteboard userData:(const char *)userData error:(char **)msg { char *filename; char *sep; int length; [pasteboard types]; /* pretend to check the pasteboard types */ /* read the ASCII data from the pasteboard */ if ([pasteboard readType:NXFilenamePboardType data:&filename length:&length]) { if(sep = index(filename,'\t')) *sep = (char)0; /* only handle a single sound */ [self loadType: YES fromString: "auto|0|Use Header|Use Header|Use Header"]; [self loadType: NO fromString: "snd|0|Use Header|Use Header|Use Header"]; [self app: self openFile: filename type: ""]; if(*[defaults get: "AutoConvert"] != 'Y') { [convert setState: 1]; [self convert: self]; } } return self; } - subprocess:sender done:(int)exitStatus { if(exitStatus) [dialog appendString: "ABORTED\n"]; else { if(_waiting) [self perform: @selector(playIt:) with: self afterDelay: 1 cancelPrevious: YES]; [dialog appendString: "Done.\n"]; } _waiting = NO; [subprocess free]; [convert setState: 0]; [convert setTitle: "CONVERT"]; return self; } - subprocess:sender output:(char *)buffer { [dialog appendString: buffer]; [dialog appendString: "\n"]; return self; } - subprocess:sender stderrOutput:(char *)buffer { [dialog appendString: buffer]; [dialog appendString: "\n"]; return self; } - subprocess:sender error:(const char *)errorString { [dialog appendString: errorString]; [dialog appendString: "\n"]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.