home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / Apps / AudioApps / GISO / Controller.m < prev    next >
Encoding:
Text File  |  1992-12-21  |  16.1 KB  |  617 lines

  1. /*    
  2. **    Copyright (C) 1992  Ronin Consulting, Inc.
  3. **
  4. **    This program is free software; you can redistribute it and/or modify
  5. **    it under the terms of the GNU General Public License as published by
  6. **    the Free Software Foundation; version 1.
  7. **
  8. **    This program is distributed in the hope that it will be useful,
  9. **    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. **    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. **    GNU General Public License for more details.
  12. **
  13. **    You should have received a copy of the GNU General Public License
  14. **    along with this program; if not, write to the Free Software
  15. **    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #import <stdio.h>
  18. #import "Controller.h"
  19. #import "Defaults.h"
  20. #import "StringStorage.h"
  21. #import "TokenString.h"
  22. #import "EnhancedText.h"
  23. #import "EnhancedMatrix.h"
  24. #import "Subprocess.h"
  25. #import "version.h"
  26. #import <appkit/appkit.h>
  27. #import <libc.h>
  28. #import <objc/NXStringTable.h>
  29. #import <soundkit/soundkit.h>
  30. #import "EnhancedApp.h"
  31.  
  32. @implementation Controller
  33.  
  34. - init
  35. {
  36.    [super init];
  37.  
  38.    [NXApp appDirectory];
  39.    openPanel = [OpenPanel new];
  40.    [openPanel allowMultipleFiles: NO];
  41.    inFile = [[StringStorage alloc] init];
  42.    savePanel = [SavePanel new];
  43.    outFile = [[StringStorage alloc] init];
  44.  
  45.    strings = [[NXStringTable alloc] init];
  46.    dataFormSwitches = [[NXStringTable alloc] init];
  47.    dataSizeSwitches = [[NXStringTable alloc] init];
  48.    inHotListStr = [[NXStringTable alloc] init];
  49.    inHotListConfig = [[NXStringTable alloc] init];
  50.    outHotListStr = [[NXStringTable alloc] init];
  51.    outHotListConfig = [[NXStringTable alloc] init];
  52.  
  53.    theSound = [Sound new];
  54.    [theSound setDelegate: self];
  55.  
  56.    return self;
  57. }
  58.  
  59. - appDidInit: sender
  60. {
  61.    id buffer = [[StringStorage alloc] init];
  62.    id dir = [[StringStorage alloc] init];
  63.  
  64.    defaults = [Defaults new];             /* get access to applications defaults */
  65.  
  66.                          /* load the effects popup */
  67.    if(![strings readFromFile: "English.lproj/effects.strings"])
  68.        NXLogError("File effects is missiong from .app");
  69.  
  70.    [self loadPopUpList: effect with: strings from: 1];
  71.    [strings empty];
  72.  
  73.                          /* load the filetype popups */
  74.    if(![strings readFromFile: "English.lproj/filetype.strings"])
  75.        NXLogError("File filetype is missiong from .app");
  76.  
  77.    [self loadPopUpList: inType with: strings from: 1];
  78.    [self loadPopUpList: outType with: strings from: 2];
  79.    [strings empty];
  80.  
  81.                          /* load the rates popups */
  82.    if(![strings readFromFile: "English.lproj/rate.strings"])
  83.        NXLogError("File rate missing\n");
  84.  
  85.    [self loadPopUpList: inRate with: strings from: 1];
  86.    [[inRate target] setTarget: self];
  87.    [[inRate target] setAction: @selector(copyValue:)];
  88.  
  89.    [self loadPopUpList: outRate with: strings from: 2];
  90.    [[outRate target] setTarget: self];
  91.    [[outRate target] setAction: @selector(copyValue:)];
  92.    [outRateText setDoubleValue: atof([outRate title])];
  93.    
  94.    [strings empty];
  95.                          /* load the format popups */
  96.    if(![strings readFromFile: "English.lproj/dataFormat.strings"])
  97.        NXLogError("File dataFormat missing\n");
  98.  
  99.    [self loadPopUpList: inDataForm with: strings from: 1];
  100.    [self loadPopUpList: outDataForm with: strings from: 2];
  101.    [strings empty];
  102.  
  103.                          /* laod the format swithes */
  104.    if(![dataFormSwitches readFromFile: "English.lproj/dataFormatSwitches.strings"])
  105.        NXLogError("File dataFormatSwitches missing\n");
  106.  
  107.                          /* load data size popups */
  108.    if(![strings readFromFile: "English.lproj/dataSize.strings"])
  109.        NXLogError("File dataSize missing\n");
  110.  
  111.    [self loadPopUpList: inDataSize with: strings from: 1];
  112.    [self loadPopUpList: outDataSize with: strings from: 2];
  113.    [strings empty];
  114.  
  115.                          /* laod the size swithes */
  116.    if(![dataSizeSwitches readFromFile: "English.lproj/dataSizeSwitches.strings"])
  117.        NXLogError("File dataSizeSwitches missing\n");
  118.  
  119.                          /* load data size popups */
  120.    if(![strings readFromFile: "English.lproj/channel.strings"])
  121.        NXLogError("File channel missing\n");
  122.  
  123.    [self loadPopUpList: inChannels with: strings from: 1];
  124.    [self loadPopUpList: outChannels with: strings from: 2];
  125.    [strings empty];
  126.  
  127.    [dir setStringValue: [defaults get: "StoreDirectory"]];
  128.  
  129.    if(!*[dir stringValue])
  130.        [dir setStringValue: "English.lproj/"];
  131.    else
  132.        [dir appendStringValue: "/"];
  133.  
  134.    [buffer setStringValue: [dir stringValue]];
  135.    [buffer appendStringValue: "inHotList.strings"];
  136.                          /* load in hot list */
  137.    if(![inHotListStr readFromFile: [buffer stringValue]])
  138.        NXLogError("File inHotList missing.\n");
  139.  
  140.    [self loadPopUpList: inHotList with: inHotListStr from: 1];
  141.    [[inHotList target] setTarget: self];
  142.    [[inHotList target] setAction: @selector(loadFromHotList:)];
  143.  
  144.    [buffer setStringValue: [dir stringValue]];
  145.    [buffer appendStringValue: "inHotListConfig.strings"];
  146.                          /* load in hot list configs */
  147.    if(![inHotListConfig readFromFile: [buffer stringValue]])
  148.        NXLogError("File inHotListConfig missing.\n");
  149.  
  150.  
  151.    [buffer setStringValue: [dir stringValue]];
  152.    [buffer appendStringValue: "outHotList.strings"];
  153.                          /* load out hot list */
  154.    if(![outHotListStr readFromFile: [buffer stringValue]])
  155.        NXLogError("File outHotList missing.\n");
  156.  
  157.    [self loadPopUpList: outHotList with: outHotListStr from: 1];
  158.    [[outHotList target] setTarget: self];
  159.    [[outHotList target] setAction: @selector(loadFromHotList:)];
  160.  
  161.    [buffer setStringValue: [dir stringValue]];
  162.    [buffer appendStringValue: "outHotListConfig.strings"];
  163.                          /* load out hot list configs */
  164.    if(![outHotListConfig readFromFile: [buffer stringValue]])
  165.        NXLogError("File outHotListConfig missing.\n");
  166.  
  167.    [self loadFromHotList: [[inHotList target] itemList]];
  168.    [self loadFromHotList: [[outHotList target] itemList]];
  169.  
  170.    [panel makeKeyAndOrderFront: self];
  171.    [dialog appendString: "Ready...\n"];
  172.  
  173.    return self;
  174. }
  175.  
  176. - convert:sender
  177. {
  178.    char cmd[1024];
  179.  
  180.    [convert setTitle: "STOP"];
  181.    NXPing();
  182.  
  183.    if(![convert state])                 /* already doing a conversion - stop it */
  184.    {
  185.       [subprocess terminate: self];
  186.       [convert setTitle: "Do Conversion"];
  187.       return self;
  188.    }
  189.    
  190.    if (![[sender window] makeFirstResponder: [sender window]])
  191.    {
  192.       [dialog appendString: "Invalid entry.\n"];
  193.       [convert setState: 0];
  194.       [convert setTitle: "Do Conversion"];
  195.       return self;
  196.    }
  197.    
  198.    [[sender window] endEditingFor:nil];
  199.  
  200.    if(!*[inFile stringValue])
  201.    {
  202.       [dialog appendString: "No input File is set.\n"];
  203.       [convert setState: 0];
  204.       [convert setTitle: "Do Conversion"];
  205.       return self;
  206.    }
  207.  
  208.  
  209.    if(!*[outFile stringValue])
  210.    {
  211.       char filename[strlen([defaults get: "TmpDirectory"]) + 15];
  212.  
  213.       sprintf(filename,"%s/GISOXXXXXX", [defaults get: "TmpDirectory"]);
  214.       [outFile setStringValue: mktemp(filename)];
  215.       [outFile appendStringValue: ".snd"];
  216.    }
  217.  
  218.    /* 
  219.     * Build up the command line.
  220.     */
  221.    strcpy(cmd, "sox -V ");
  222.  
  223.    if([volume doubleValue] != 1.0)
  224.        sprintf(cmd + strlen(cmd), "-v %6.2f ", [volume doubleValue]);
  225.  
  226.    if([[inType target] indexOfItem: [inType title]])
  227.        sprintf(cmd + strlen(cmd), "-t %s ", [inType title]);
  228.  
  229.    if([inRateText doubleValue])
  230.        sprintf(cmd + strlen(cmd), "-r %10.3f ", [inRateText doubleValue]);
  231.  
  232.    if([[inDataForm target] indexOfItem: [inDataForm title]])
  233.        sprintf(cmd + strlen(cmd), "%s ", 
  234.            [dataFormSwitches valueForStringKey: [inDataForm title]]);
  235.  
  236.    if([[inDataSize target] indexOfItem: [inDataSize title]])
  237.        sprintf(cmd + strlen(cmd), "%s ",
  238.            [dataSizeSwitches valueForStringKey: [inDataSize title]]);
  239.  
  240.    if([[inChannels target] indexOfItem: [inChannels title]])
  241.        sprintf(cmd + strlen(cmd), "-c %s ", [inChannels title]);
  242.  
  243.    if([swapBytes state])
  244.        strcat(cmd, "-x ");
  245.  
  246.    sprintf(cmd + strlen(cmd), "%s -t %s -r %10.3f %s %s -c %s %s ",
  247.        [inFile stringValue],
  248.        [outType title],
  249.        [outRateText doubleValue],
  250.        [dataFormSwitches valueForStringKey: [outDataForm title]],
  251.        [dataSizeSwitches valueForStringKey: [outDataSize title]],
  252.        [outChannels title],
  253.        [outFile stringValue]);
  254.  
  255.    if([[effect target] indexOfItem: [effect title]])
  256.        sprintf(cmd + strlen(cmd), "%s %s ", 
  257.            [effect title], [effectArgText stringValue]);
  258.  
  259.    [dialog appendString: cmd];
  260.    [dialog appendString: "\n"];
  261.  
  262.    subprocess = [[Subprocess alloc] init: cmd withDelegate: self];
  263.    return self;
  264. }
  265.  
  266. - openFile:sender
  267. {
  268.    static int first = 1;
  269.  
  270.    if (first)
  271.    {
  272.       [openPanel runModalForDirectory: "~/" file: ""];
  273.       first = 0;
  274.    }
  275.    else
  276.        [openPanel runModalForDirectory: "" file: ""];
  277.  
  278.    [inFile setStringValue: [openPanel filename]];
  279.    if(*[inFile stringValue])
  280.    {
  281.       [dialog appendString: [inFile stringValue]];
  282.       [dialog appendString: " used as input\n"];
  283.       [outFile setStringValue: ""];
  284.    }
  285.    
  286.    return self;
  287. }
  288.  
  289. - saveFile:sender
  290. {
  291.    static int first = 1;
  292.    id tempFile = [[StringStorage alloc] init];
  293.  
  294.    if(!*[outFile stringValue])
  295.    {
  296.       [dialog appendString: "No sound created.\n"];
  297.       [tempFile free];
  298.       return self;
  299.    }
  300.    
  301.    if(first)
  302.    {
  303.       [savePanel runModalForDirectory: "~/" file: ""];
  304.       first = 0;
  305.    }
  306.    else
  307.       [savePanel runModalForDirectory: "" file: ""];
  308.  
  309.    [tempFile setStringValue: [savePanel filename]];
  310.    if(*[tempFile stringValue])
  311.    {
  312.       char cmd[128];
  313.  
  314.       [dialog appendString: [savePanel filename]];
  315.       [dialog appendString: " used as output\n"];
  316.       sprintf(cmd, "cp \"%s\" \"%s\" ", [outFile stringValue], [tempFile stringValue]);
  317.       system(cmd);
  318.       [outFile setStringValue: [tempFile stringValue]];
  319.    }
  320.  
  321.    [tempFile free];
  322.    return self;
  323. }
  324.  
  325. - saveToHotList: sender
  326. {
  327.    id buffer = [[StringStorage alloc] init];
  328.    id file = [[StringStorage alloc] init];
  329.    id dir = [[StringStorage alloc] init];
  330.    char num[10],  *name;
  331.    BOOL inHot;
  332.  
  333.    name = (char *)[entryName stringValue];
  334.  
  335.    if(!name || !*name)
  336.    {
  337.       NXRunAlertPanel([NXApp appName], "Entry must have a name.", 
  338.                NULL, NULL, NULL);
  339.       [dir free];
  340.       [buffer free];
  341.       [file free];
  342.       return self;
  343.    }
  344.    
  345.  
  346.    [dir setStringValue: [defaults get: "StoreDirectory"]];
  347.  
  348.    
  349.    if(!*[dir stringValue])
  350.        NXRunAlertPanel([NXApp appName], "No directory to store the hot lists - see preferences.", 
  351.                NULL, NULL, NULL);
  352.    else
  353.    {
  354.       inHot = [whichRadio state];
  355.       
  356.       [buffer setStringValue: [(inHot?inType:outType) title]];
  357.       [buffer appendStringValue: "|"];
  358.       [buffer appendStringValue: [(inHot?inRateText:outRateText) stringValue]];
  359.       [buffer appendStringValue: "|"];
  360.       [buffer appendStringValue: [(inHot?inDataForm:outDataForm) title]];
  361.       [buffer appendStringValue: "|"];
  362.       [buffer appendStringValue: [(inHot?inDataSize:outDataSize) title]];
  363.       [buffer appendStringValue: "|"];
  364.       [buffer appendStringValue: [(inHot?inChannels:outChannels) title]];
  365.       
  366.       sprintf(num,"%ud", [(inHot?inHotListStr: outHotListStr) count] + 1);
  367.       
  368.       [(inHot?inHotListStr:outHotListStr) insertKey: num value: name];
  369.       [(inHot?inHotListConfig:outHotListConfig) insertKey: name value: (char *)[buffer stringValue]];
  370.       
  371.       if(inHot)
  372.       {
  373.      [file setStringValue: [dir stringValue]];
  374.      [file appendStringValue: "/inHotList.strings"];
  375.      [inHotListStr writeToFile: [file stringValue]];
  376.      [file setStringValue: [dir stringValue]];
  377.      [file appendStringValue: "/inHotListConfig.strings"];
  378.      [inHotListConfig writeToFile: [file stringValue]];
  379.      [[inHotList target] addItem: [entryName stringValue]];
  380.       }
  381.       else
  382.       {
  383.      [file setStringValue: [dir stringValue]];
  384.      [file appendStringValue: "/outHotList.strings"];
  385.      [outHotListStr writeToFile: [file stringValue]];
  386.      [file setStringValue: [dir stringValue]];
  387.      [file appendStringValue: "/outHotListConfig.strings"];
  388.      [outHotListConfig writeToFile: [file stringValue]];
  389.      [[outHotList target] addItem: [entryName stringValue]];
  390.       }
  391.    }
  392.    
  393.    [dir free];
  394.    [buffer free];
  395.    [file free];
  396.    [[sender window] performClose: self];
  397.    return self;
  398. }
  399.  
  400. - stopPlay: sender
  401. {
  402.    [theSound stop];
  403.    return self;
  404. }
  405.  
  406. - playIt: sender
  407. {
  408.  
  409.    if(*[outFile stringValue])
  410.    {
  411.       [theSound readSoundfile: (char *)[outFile stringValue]];
  412.       [theSound play];
  413.    }
  414.    else
  415.    {
  416.       [dialog appendString: "No sound has been created.\n"];
  417.       [playButton setState: 0];
  418.    }
  419.  
  420.    return self;
  421. }
  422.  
  423. - copyValue: sender
  424. {
  425.    if(sender == [[inRate target] itemList])
  426.        [inRateText setDoubleValue: atof([[sender selectedCell] title])];
  427.    else
  428.        [outRateText setDoubleValue: atof([[sender selectedCell] title])];
  429.  
  430.    return self;
  431. }
  432.  
  433.  
  434. - willPlay: sender
  435. {
  436.    [soundMeter run: self];
  437.    return self;
  438. }
  439.  
  440. - didPlay: sender
  441. {
  442.    [playButton setState: 0];
  443.    [soundMeter stop: self];
  444.    return self;
  445. }
  446.  
  447. - hadError: sender
  448. {
  449.    [dialog appendString: "Error playing sound...\n"];
  450.    return self;
  451. }
  452.  
  453. - setDialog: anObject
  454. {
  455.    dialog = [anObject docView];
  456.    return self;
  457. }
  458.  
  459. - setSoundMeter: anObject
  460. {
  461.    soundMeter = anObject;
  462.    [soundMeter setSound: theSound];
  463.    
  464.    return self;
  465. }
  466.  
  467. - loadFromHotList: sender
  468. {
  469.    const char *title;
  470.    id tokens = [[TokenString alloc] init];
  471.    BOOL inHot;
  472.  
  473.    [tokens setSeparator: '|'];
  474.  
  475.    inHot = ((sender == [[inHotList target] itemList])? YES : NO);
  476.  
  477.    [tokens setStringValue: [(inHot?inHotListConfig:outHotListConfig) 
  478.             valueForStringKey: [[sender selectedCell] title]]];
  479.  
  480.    if(!(title = [tokens popToken]))
  481.    {
  482.       [dialog appendString: "Malformed hot list entry\n"];
  483.       return self;
  484.    }
  485.  
  486.    [(inHot?inType:outType) setTitle: title];
  487.  
  488.    if(!(title = [tokens popToken]))
  489.    {
  490.       [dialog appendString: "Malformed hot list entry\n"];
  491.       return self;
  492.    }
  493.    
  494.    [(inHot?inRateText:outRateText) setStringValue: title];
  495.  
  496.    if(!(title = [tokens popToken]))
  497.    {
  498.       [dialog appendString: "Malformed hot list entry\n"];
  499.       return self;
  500.    }
  501.    
  502.    [(inHot?inDataForm:outDataForm) setTitle: title];
  503.  
  504.    if(!(title = [tokens popToken]))
  505.    {
  506.       [dialog appendString: "Malformed hot list entry\n"];
  507.       return self;
  508.    }
  509.    
  510.    [(inHot?inDataSize:outDataSize) setTitle: title];
  511.  
  512.    if(!(title = [tokens popToken]))
  513.    {
  514.       [dialog appendString: "Malformed hot list entry\n"];
  515.       return self;
  516.    }
  517.    
  518.    [(inHot?inChannels:outChannels) setTitle: title];
  519.  
  520.    [tokens free];
  521.  
  522.    return self;
  523. }
  524.  
  525. - setVersionNo: anObject             /* set the version number on the info panel */
  526. {
  527.    [anObject setStringValue: versionNumber];
  528.    return self;
  529. }
  530.  
  531. - (int) loadPopUpList: button with: stringTable from: (int) x
  532. {
  533.    char key[15];
  534.    const char *value;
  535.    id list = [button target];             /* get the popUpList */
  536.  
  537.    while(1)
  538.    {
  539.       sprintf(key, "%d", x++);
  540.       value = [stringTable valueForStringKey: key];
  541.  
  542.       if(!value)
  543.       break;
  544.  
  545.       [list addItem: value];
  546.    }
  547.  
  548.    [list removeItem: [button title]];         /* clear out the .nibs item */
  549.    [button setTitle: [[[list itemList] cellAt: 0:0] title]];
  550.    [[list itemList] selectCellAt: 0 : 0];
  551.    return --x;
  552. }
  553.  
  554. - cleanKill: sender                 /* clean temporary files before we go */
  555. {
  556.    char cmd[strlen([defaults get: "TmpDirectory"]) + 50];
  557.  
  558.    sprintf(cmd, "rm -f %s/GISO[0-9][0-9][0-9][0-9][0-9][0-9].snd", [defaults get: "TmpDirectory"]);
  559.    system(cmd);
  560.    return [NXApp terminate: self];
  561. }
  562.  
  563. - (BOOL)appAcceptsAnotherFile:sender
  564. {
  565.    return YES;
  566. }
  567.  
  568. - (int)app:sender openFile:(const char *)filename type:(const char *)aType
  569. {
  570.    [inFile setStringValue: filename];
  571.    if(*[inFile stringValue])
  572.    {
  573.       [dialog appendString: [inFile stringValue]];
  574.       [dialog appendString: " used as input\n"];
  575.       [outFile setStringValue: ""];
  576.       return YES;
  577.    }
  578.  
  579.    return NO;
  580. }
  581.  
  582. - subprocess:sender done:(int)exitStatus
  583. {
  584.    if(exitStatus)
  585.        [dialog appendString: "ABORTED\n"];
  586.    else
  587.        [dialog appendString: "Done.\n"];
  588.  
  589.    [subprocess free];
  590.    [convert setState: 0];
  591.    [convert setTitle: "Do Conversion"];
  592.    return self;
  593. }
  594.  
  595. - subprocess:sender output:(char *)buffer
  596. {
  597.    [dialog appendString: buffer];
  598.    [dialog appendString: "\n"];
  599.    return self;
  600. }
  601.  
  602. - subprocess:sender stderrOutput:(char *)buffer
  603. {
  604.    [dialog appendString: buffer];
  605.    [dialog appendString: "\n"];
  606.    return self;
  607. }
  608.  
  609. - subprocess:sender error:(const char *)errorString
  610. {
  611.    [dialog appendString: errorString];
  612.    [dialog appendString: "\n"];
  613.    return self;
  614. }
  615.  
  616. @end
  617.