home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Audio / FrontEnd / Source / FrontEnd.m < prev    next >
Encoding:
Text File  |  1990-05-26  |  13.7 KB  |  480 lines

  1. /* -----------------------------------------------------------------------------------    */
  2. /* FrontEnd.m -- Copyright (c) 1990 Ed Hill                        */
  3. /*                                            */
  4. /*   This program is free software; you can redistribute it and/or modify it under the     */        
  5. /*   terms of the GNU General Public License as published by the Free Software        */        
  6. /*   Foundation; either version 1, or (at your option) any later option.        */        
  7. /*                                            */                                        
  8. /*   This program is distributed in the hope that it will be useful, but WITHOUT ANY    */
  9. /*   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A    */        
  10. /*   PARTICULAR PURPOSE.  See the GNU General Public License for more details.        */            
  11. /*                                            */
  12. /*   You should have received a copy of the GNU General Public License along with this     */    
  13. /*   this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave,     */
  14. /*   Cambridge, MA 02139, USA, or send electronic mail to the author.            */    
  15. /* ------------------------------------------------------------------------------------    */
  16. /*                                               */
  17. /* ------------------------------------------------------------------------------------    */
  18. /* I am aware that this program does nothing that hasn't been done before.  I simply    */
  19. /* wanted to see how easy it was to add a simple user interface to an existing non-user    */
  20. /* friendly program.  I would like to add functionality to this program in the future    */
  21. /* If you have suggestions or ideas that would be useful in future releases plese feel    */
  22. /* to write me at edhill@shumun.weeg.uiowa.edu (NeXT).  I also welcome any programming    */
  23. /* advice (I would have done this different, etc...).                    */
  24. /* ------------------------------------------------------------------------------------    */
  25.  
  26. #import "GNULicense.h"        
  27. #import "FrontEnd.h"        
  28. #import <appkit/appkit.h>
  29. #import <appkit/publicWraps.h>    
  30. #import <appkit/nextstd.h>    
  31. #import <soundkit/soundkit.h>
  32. #import <sound/sound.h>
  33. #import <string.h>        
  34. #import <stdio.h>
  35.  
  36. @implementation FrontEnd
  37.  
  38. /* ------------------------------------------------------------------------------------    */
  39. /* The following methods set up the necessary outlets.                     */
  40. /* Which are connected via the Interface Builder.                    */
  41. /* ------------------------------------------------------------------------------------    */
  42. -setFrontEndWindow:anObject
  43. {
  44.     FrontEndWindow = anObject;
  45.     return self;
  46. }
  47.  
  48. -setNameView:anObject
  49. {
  50.     NameView = anObject;
  51.     return self;
  52. }
  53.  
  54. -setNameView2:anObject
  55. {
  56.     NameView2 = anObject;
  57.     return self;
  58. }
  59.  
  60. -setIconBox:anObject
  61. {
  62.     IconBox = anObject;
  63.     return self;
  64. }
  65.  
  66. -setIconBox2:anObject
  67. {
  68.     IconBox2 = anObject;
  69.     return self;
  70. }
  71.  
  72. -setSampleButton:anObject
  73. {
  74.     SampleButton = anObject;
  75.     popup = [PopUpList new];      
  76.     [popup addItem:"Sample Rate = 22 KHz"];
  77.     [popup addItem:"Sample Rate = 11 KHz"];
  78.     [[popup setTarget:self] setAction:@selector(changeSampleRate:)];
  79.     NXAttachPopUpList (SampleButton, popup);    
  80.     return self;
  81. }
  82.  
  83. -setConvertButton:anObject
  84. {
  85.     ConvertButton = anObject;
  86.     return self;
  87. }
  88.  
  89. -setErrorText:anObject
  90. {
  91.     ErrorText = anObject;
  92.     [ErrorText setStringValue:""];
  93.     return self;
  94. }
  95.  
  96. /* ------------------------------------------------------------------------------------    */
  97. /* The following four methods are delegate methods that add functionality to the     */
  98. /* existing methods are already defined by the Application class.  I believe that I      */
  99. /* am doing something wrong because I have been told that I shouldn't have to redefine    */
  100. /* the -unhide method.  If you can tell what I am doing wrong I would greatly         */
  101. /* appreciate it.                                    */
  102. /* ------------------------------------------------------------------------------------    */
  103. - appDidInit:sender
  104. {
  105.     id             theListener;
  106.     id             theSpeaker;
  107.     unsigned int    windowNum;
  108.     
  109.     theSpeaker = [NXApp appSpeaker];
  110.     NXConvertWinNumToGlobal([FrontEndWindow windowNum], &windowNum);
  111.     theListener = [NXApp appListener];
  112.     [theListener setDelegate:self];
  113.     [theListener privatePort];
  114.     [theListener addPort];
  115.     [theSpeaker setSendPort: NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
  116.     [theSpeaker registerWindow: windowNum toPort:[theListener listenPort]];
  117.     isPaused = FALSE;
  118.     sampleRate = 1;
  119.     NX_FREE( nextSoundName );
  120.     NX_MALLOC( nextSoundName, char, strlen( "" ) + 1 );
  121.     strcpy( nextSoundName, "" );
  122.     NX_FREE( macSoundName );
  123.     NX_MALLOC( macSoundName, char, strlen( "" ) + 1 );
  124.     strcpy( macSoundName, "" );
  125.     NX_FREE( iconPath );
  126.     NX_MALLOC( iconPath, char, strlen( "" ) + 1 );
  127.     strcpy( iconPath, "" );
  128.     NothingHere = TRUE;
  129.     [ConvertButton setEnabled:NO];
  130.     
  131.     return self;
  132. }
  133.  
  134.  
  135. - (int)iconEntered:(int)windowNum 
  136.     at:(double)x 
  137.     :(double)y 
  138.     iconWindow:(int)iconWindowNum 
  139.     iconX:(double)iconX 
  140.     iconY:(double)iconY 
  141.     iconWidth:(double)iconWidth 
  142.     iconHeight:(double)iconHeight 
  143.     pathList:(const char *)pathList
  144. {
  145.     NX_FREE( iconPath );
  146.     NX_MALLOC( iconPath, char, strlen( pathList ) + 1 );
  147.     strcpy( iconPath, pathList );
  148.     return 0;
  149. }
  150.  
  151. - unhide:sender
  152. {
  153.     [NXApp unhide:self];
  154.     return self;
  155. }
  156.  
  157. - (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
  158. {
  159.     NXPoint    iconViewOrigin;
  160.     id        currentIcon;
  161.     BOOL    OKflag;
  162.     char     *fileName;
  163.     
  164.     iconViewOrigin.x = iconViewOrigin.y = 0.0;
  165.     NX_FREE( nextSoundName );
  166.     NX_MALLOC( nextSoundName, char, strlen( "" ) + 1 );
  167.     strcpy( nextSoundName, "" );        
  168.     OKflag = [self setUpDraggedInFiles:self];
  169.  
  170.     if( OKflag )
  171.     {
  172.         NothingHere = FALSE;
  173.     [NXApp activateSelf:YES]; 
  174.     [FrontEndWindow makeKeyAndOrderFront:self];   
  175.     *flag = 1;
  176.     [ErrorText setStringValue:""];
  177.     [ConvertButton setEnabled:YES];
  178.  
  179.     [IconBox lockFocus];
  180.     currentIcon = [Bitmap findBitmapFor:"Macsnd"];
  181.     [currentIcon composite:NX_COPY toPoint:&iconViewOrigin];
  182.     [IconBox unlockFocus];
  183.     fileName = strrchr(macSoundName, '/');
  184.     fileName++;
  185.     [NameView setStringValue:fileName];
  186.     
  187.     /* This is probably a stupid way to do this but its quick */
  188.     [IconBox2 lockFocus];
  189.     currentIcon = [Bitmap findBitmapFor:"Blank"];
  190.     [currentIcon composite:NX_COPY toPoint:&iconViewOrigin];
  191.     [IconBox2 unlockFocus];
  192.     [NameView2 setStringValue:""];
  193.     }
  194.     else
  195.     {
  196.     /* This is probably a stupid way to do this but its quick */
  197.         NothingHere = TRUE;
  198.     [IconBox lockFocus];
  199.     currentIcon = [Bitmap findBitmapFor:"Blank"];
  200.     [currentIcon composite:NX_COPY toPoint:&iconViewOrigin];
  201.     [IconBox unlockFocus];
  202.     [NameView setStringValue:""];
  203.     [IconBox2 lockFocus];
  204.     currentIcon = [Bitmap findBitmapFor:"Blank"];
  205.     [currentIcon composite:NX_COPY toPoint:&iconViewOrigin];
  206.     [IconBox2 unlockFocus];    
  207.     [NameView2 setStringValue:""];
  208.     [ConvertButton setEnabled:NO];
  209.     
  210.     NX_FREE( macSoundName );
  211.     NX_MALLOC( macSoundName, char, strlen( "" ) + 1 );
  212.     strcpy( macSoundName, "" );        
  213.     *flag = 0;
  214.     }
  215.     return 0;
  216. }
  217.  
  218. /* ------------------------------------------------------------------------------------    */
  219. /* This method checks to make sure that the file that has been dragged from the     */
  220. /* workspace is the proper type (ending with a ".macsnd" suffix).            */
  221. /* ------------------------------------------------------------------------------------    */
  222. -setUpDraggedInFiles:sender
  223. {
  224.     char    *tab;
  225.     char    *extension;
  226.     BOOL    hadInvalid;
  227.     
  228.     hadInvalid = FALSE;
  229.     if( iconPath )
  230.     {
  231.     tab = strchr(iconPath,'\t');
  232.     if (tab) 
  233.         *tab = '\0';
  234.     extension = strrchr(iconPath,'.');
  235.     if (extension)
  236.     {
  237.            if (!strcmp(extension,".macsnd"))
  238.         {
  239.         NX_FREE( macSoundName );
  240.         NX_MALLOC( macSoundName, char, strlen( iconPath ) + 1 );
  241.         strcpy( macSoundName, iconPath );
  242.         }
  243.         else
  244.         {
  245.             hadInvalid = TRUE;
  246.         [ErrorText setStringValue:"NOT '.macsnd' Extension"];
  247.         }
  248.     } 
  249.     else 
  250.     {
  251.         hadInvalid = TRUE;
  252.         [ErrorText setStringValue:"NOT '.macsnd' Extension"];
  253.       }
  254.     }
  255.     else
  256.         [ErrorText setStringValue:"Workspace Error"];
  257.     
  258.     if( hadInvalid )
  259.         return FALSE;
  260.     else
  261.         return TRUE;
  262. }
  263.  
  264. /* ------------------------------------------------------------------------------------    */
  265. /* The following three methods perform functions on the converted sound.  I added this    */
  266. /* functionality so that the user can instantly tell if the conversion was completed    */
  267. /* succesfully.                                        */
  268. /* ------------------------------------------------------------------------------------    */
  269. -playsound:sender
  270. {
  271.     if( strcmp( nextSoundName, "" ) )
  272.     {
  273.         if( currentSound )
  274.             [currentSound play];
  275.     else
  276.         [ErrorText setStringValue:"Sound Not Initialized"];
  277.     }
  278.     else
  279.         [ErrorText setStringValue:"No NeXT Sound to Play"];
  280.     
  281.     return self;        
  282. }
  283.  
  284. -stopsound:sender
  285. {
  286.     if( strcmp( nextSoundName, "" ) )
  287.     {
  288.         if( currentSound )
  289.             [currentSound stop];
  290.     else
  291.         [ErrorText setStringValue:"Sound Not Initialized"];
  292.     }
  293.     else
  294.         [ErrorText setStringValue:"No NeXT Sound to Stop"];
  295.     
  296.     return self;        
  297. }
  298.  
  299. -pausesound:sender
  300. {
  301.     if( strcmp( nextSoundName, "" ) )
  302.     {
  303.     if( currentSound )
  304.     {
  305.         if( isPaused )
  306.         {
  307.         isPaused = FALSE;
  308.         [currentSound resume:self];
  309.         }
  310.         else
  311.         {
  312.         isPaused = TRUE;
  313.         [currentSound pause:self];
  314.         } 
  315.     }
  316.     else
  317.         [ErrorText setStringValue:"Sound Not Initialized"]; 
  318.     }
  319.     else
  320.         [ErrorText setStringValue:"No NeXT Sound to Pause"];
  321.     
  322.     return self;            
  323. }
  324.  
  325. /* ------------------------------------------------------------------------------------    */
  326. /* This method is activated when the user activates the PopUpList.  It simply sets     */
  327. /* the sampleing rate for the user.                            */
  328. /* ------------------------------------------------------------------------------------    */
  329. -changeSampleRate:sender;
  330. {
  331.     if( NothingHere )
  332.         [ConvertButton setEnabled:NO];
  333.     else
  334.         [ConvertButton setEnabled:YES];
  335.     
  336.     if( strcmp( [[sender selectedCell] title], "Sample Rate = 22 KHz" ) )
  337.         sampleRate = 0;
  338.     else
  339.         sampleRate = 1;
  340.     return self;
  341. }
  342.  
  343. /* ------------------------------------------------------------------------------------    */
  344. /* This function takes care of most of the error checking and visual effects that take    */
  345. /* take place before the sound is converted.  It changes the name of the original file    */
  346. /* and places the NeXT Sound icon in its respective dock.                */
  347. /* ------------------------------------------------------------------------------------    */
  348. -convertMactoNeXT:sender
  349. {
  350.     NXPoint    iconViewOrigin;
  351.     id        currentIcon;
  352.     char    *fileName;
  353.     char     *tempName;
  354.     
  355.     iconViewOrigin.x = iconViewOrigin.y = 0.0;
  356.  
  357.     if( strcmp( macSoundName, "" ) )
  358.     {    
  359.     [IconBox2 lockFocus];
  360.     currentIcon = [Bitmap findBitmapFor:"Sound"];
  361.     [currentIcon composite:NX_COPY toPoint:&iconViewOrigin];
  362.     [IconBox2 unlockFocus];
  363.     
  364.     NX_FREE( nextSoundName );
  365.     NX_MALLOC( nextSoundName, char, strlen( macSoundName ) + 1 );
  366.     strcpy( nextSoundName, macSoundName );    
  367.     fileName = strrchr(nextSoundName, '/');
  368.     fileName++;
  369.     tempName = fileName;
  370.     while( *tempName++ != '.' );
  371.     strcpy( tempName, "snd\0" );
  372.     [NameView2 setStringValue:fileName];
  373.     [self _actualMactoNeXTcode:sampleRate];
  374.     currentSound = [Sound newFromSoundfile:nextSoundName];
  375.     [ErrorText setStringValue:""];
  376.     [ConvertButton setEnabled:NO];
  377.     return self;
  378.     }
  379.     else
  380.        [ErrorText setStringValue:"No Sound to Convert"];
  381. }
  382.  
  383. /* ------------------------------------------------------------------------------------    */
  384. /* This is the actual code that converts the Macintosh sound to a NeXT sound.  I did     */
  385. /* not write this code it was written by Robert Hood.  I honestly haven't even looked     */
  386. /* at this code.  I hope to rewrite this function in a future release so that I can fix    */
  387. /* a known bug in it.                                    */
  388. /* ------------------------------------------------------------------------------------    */
  389. -_actualMactoNeXTcode:(int)theSampleRate
  390. {
  391.     FILE *input, *output;
  392.     char filename [256], outname [256];
  393.     int temp,last;
  394.     int fast;
  395.     char temp2;
  396.     unsigned char ch;
  397.     
  398.     strcpy (filename, macSoundName);
  399.     fast = theSampleRate;
  400.     
  401.     
  402.     if ((input = fopen (filename, "rb")) == 0)
  403.         {
  404.         perror (filename);
  405.         exit (-1);
  406.         }
  407.     strcpy (outname, nextSoundName);
  408.     if ((output = fopen (outname, "wb")) == 0)
  409.         {
  410.         perror (outname);
  411.         exit (-1);
  412.         }
  413.     temp = 0x2E736E64;  /* magic */
  414.     fwrite (&temp, 4, 1, output);
  415.     temp = 0x0000001C;  /* start of sound */
  416.     fwrite (&temp, 4, 1, output);
  417.     temp = 0x98 + 1;   /* end of sound...doesn't seem to matter */
  418.     fwrite (&temp, 4, 1, output);
  419.     temp = 0x00000003; /* ?? */
  420.     fwrite (&temp, 4, 1, output);
  421.     temp = 0x00005622;  /* sample frequency */
  422.     fwrite (&temp, 4, 1, output);
  423.     temp = 0x00000001; /* ?? */
  424.     fwrite (&temp, 4, 1, output);
  425.     temp = 0x00000000;  /* space filler? */
  426.     fwrite (&temp, 4, 1, output);
  427.     temp = 0x00000000;  /* space filler? */
  428.     fwrite (&temp, 4, 1, output);
  429.  
  430.     last = 0;
  431.     while (!feof (input))
  432.         {
  433.         ch = getc (input);
  434.  
  435.         temp = ch;
  436.         temp = (128 - temp) * (int)64;
  437.  
  438.         if (!fast)   /* 11 kHz is simulated by averaging the input */
  439.             {
  440.             last = (last + temp) / 2;
  441.             putc ((last >> 8) & 0xFF, output);
  442.             putc ((last) & 0xFF, output);
  443.             last = temp;
  444.             }
  445.         putc ((temp >> 8) & 0xFF, output);
  446.         putc ((temp) & 0xFF, output);
  447.         }
  448.     fclose (input);
  449.     fclose (output);
  450. }
  451.  
  452.  
  453. /* ------------------------------------------------------------------------------------    */
  454. /* This brings up the GNU Panel which shows the Public GNU License.            */
  455. /* ------------------------------------------------------------------------------------    */
  456. -showGNULicense:sender
  457. {
  458.    if (myGNULicense == nil)
  459.       myGNULicense = [GNULicense new];
  460.  
  461.    /* Not really necessary, but kinda cutesy. */
  462.    if ([sender isKindOf:[Control class]] == YES) {
  463.       [sender setTarget:myGNULicense];
  464.       [sender setAction:@selector (showLicense:)];
  465.    }
  466.  
  467.    [myGNULicense showLicense:self];
  468.    return self;
  469. }
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479. @end
  480.