ftp.nice.ch/pub/next/audio/converter/GISO.3.3.s.tar.gz#/GISO/Controller.m

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.